1 /* COMM3705.C (c) Copyright Max H. Parke, 2007-2012 */
2 /* Hercules 3705 communications controller */
3 /* running NCP */
4
5
6 /***********************************************************************/
7 /* */
8 /* comm3705.c - (C) Copyright 2007 by MHP <ikj1234i at yahoo dot com> */
9 /* */
10 /* Loosely based on commadpt.c by Ivan Warren */
11 /* */
12 /* This module appears to the "host" as a 3705 communications */
13 /* controller running NCP. It does not attempt to provide an emulated */
14 /* execution environment for native 3705 code. */
15 /* */
16 /* Experimental release 0.02 Oct. 15, 2007 */
17 /* */
18 /* A very minimalistic SNA engine is implemented. All received SNA */
19 /* requests are responded to with a positive response. Also, there's */
20 /* enough code to enable a single SNA session to logon in LU1 (TTY) */
21 /* mode. */
22 /* */
23 /* FID1 is the only SNA header type supported. */
24 /* */
25 /* A large amount of required SNA functionality is not present in this */
26 /* release. There are no "state machines", "layers", "services", */
27 /* chaining*, pacing, brackets, etc.etc.etc. There are */
28 /* probably more bugs than working functions... Enjoy ;-) */
29 /* */
30 /* A better implementation might be to separate the SNA functions out */
31 /* into an independent process, with communications over a full-duplex */
32 /* TCP/IP socket... We might also get rid of all the magic constants...*/
33 /* */
34 /* New in release 0.02 - */
35 /* - VTAM switched (dial) support */
36 /* - New remote NCP capability */
37 /* - SNA 3270 (LU2) support (*with RU chaining) */
38 /* - fixes for some bugs in 0.01 */
39 /* New in release 0.03 - */
40 /* - don't process TTY lines until CR received */
41 /* New in release 0.04 - */
42 /* - make debug messages optional */
43 /* */
44 /* 73 DE KA1RBI */
45 /***********************************************************************/
46
47 #include "hstdinc.h"
48 #include "hercules.h"
49 #include "devtype.h"
50 #include "opcode.h"
51 #include "parser.h"
52 #include "comm3705.h"
53
54 #if defined(WIN32) && defined(OPTION_DYNAMIC_LOAD) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
55 SYSBLK *psysblk;
56 #define sysblk (*psysblk)
57 #endif
58
59 #if !defined(min)
60 #define min(a,b) (((a) <= (b)) ? (a) : (b))
61 #endif
62
63 static void make_sna_requests2(COMMADPT*);
64 static void make_sna_requests3(COMMADPT*);
65 static void make_sna_requests4(COMMADPT*, int, BYTE);
66 static void make_sna_requests5(COMMADPT*);
67
68 static unsigned char R010201[3] = {0x01, 0x02, 0x01};
69 static unsigned char R010202[3] = {0x01, 0x02, 0x02};
70 static unsigned char R010203[3] = {0x01, 0x02, 0x03};
71 static unsigned char R010204[3] = {0x01, 0x02, 0x04};
72 static unsigned char R010205[3] = {0x01, 0x02, 0x05};
73 static unsigned char R01020A[3] = {0x01, 0x02, 0x0A};
74 static unsigned char R01020B[3] = {0x01, 0x02, 0x0B};
75 static unsigned char R01020F[3] = {0x01, 0x02, 0x0F};
76 static unsigned char R010211[3] = {0x01, 0x02, 0x11};
77 static unsigned char R010216[3] = {0x01, 0x02, 0x16};
78 static unsigned char R010217[3] = {0x01, 0x02, 0x17};
79 static unsigned char R010219[3] = {0x01, 0x02, 0x19};
80 static unsigned char R01021A[3] = {0x01, 0x02, 0x1A};
81 static unsigned char R01021B[3] = {0x01, 0x02, 0x1B};
82 static unsigned char R010280[3] = {0x01, 0x02, 0x80};
83 static unsigned char R010281[3] = {0x01, 0x02, 0x81};
84 static unsigned char R010284[3] = {0x01, 0x02, 0x84};
85
86 #define BUFPD 0x1C
87
88 static BYTE commadpt_immed_command[256]=
89 { 0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,
90 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
91 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
92 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
93 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
94 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
95 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
96 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
97 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
98 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
99 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
100 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
101 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
102 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
103 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
104 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
105
106 /*---------------------------------------------------------------*/
107 /* PARSER TABLES */
108 /*---------------------------------------------------------------*/
109 static PARSER ptab[]={
110 {"lport","%s"},
111 {"lhost","%s"},
112 {"rport","%s"},
113 {"rhost","%s"},
114 {"dial","%s"},
115 {"rto","%s"},
116 {"pto","%s"},
117 {"eto","%s"},
118 {"switched","%s"},
119 {"lnctl","%s"},
120 {"debug","%s"},
121 {"emu3791","%s"},
122 {"locsuba","%s"},
123 {"rmtsuba","%s"},
124 {"locncpnm","%s"},
125 {"rmtncpnm","%s"},
126 {"idblk","%s"},
127 {"idnum","%s"},
128 {"unitsz","%s"},
129 {"ackspeed","%s"},
130 {NULL,NULL}
131 };
132
133 enum {
134 COMMADPT_KW_LPORT=1,
135 COMMADPT_KW_LHOST,
136 COMMADPT_KW_RPORT,
137 COMMADPT_KW_RHOST,
138 COMMADPT_KW_DIAL,
139 COMMADPT_KW_READTO,
140 COMMADPT_KW_POLLTO,
141 COMMADPT_KW_ENABLETO,
142 COMMADPT_KW_SWITCHED,
143 COMMADPT_KW_LNCTL,
144 COMMADPT_KW_DEBUG,
145 COMMADPT_KW_EMU3791,
146 COMMADPT_KW_LOCSUBA,
147 COMMADPT_KW_RMTSUBA,
148 COMMADPT_KW_LOCNCPNM,
149 COMMADPT_KW_RMTNCPNM,
150 COMMADPT_KW_IDBLK,
151 COMMADPT_KW_IDNUM,
152 COMMADPT_KW_UNITSZ,
153 COMMADPT_KW_ACKSPEED
154 } comm3705_kw;
155
156 //////////////////////////////////////////////////////////////////////
157 // some code copied from console.c
158 static HOST_INFO cons_hostinfo; /* Host info for this system */
159 /*-------------------------------------------------------------------*/
160 /* Telnet command definitions */
161 /*-------------------------------------------------------------------*/
162 #define BINARY 0 /* Binary Transmission */
163 #define IS 0 /* Used by terminal-type negotiation */
164 #define SEND 1 /* Used by terminal-type negotiation */
165 #define ECHO_OPTION 1 /* Echo option */
166 #define SUPPRESS_GA 3 /* Suppress go-ahead option */
167 #define TIMING_MARK 6 /* Timing mark option */
168 #define TERMINAL_TYPE 24 /* Terminal type option */
169 #define NAWS 31 /* Negotiate About Window Size */
170 #define EOR 25 /* End of record option */
171 #define EOR_MARK 239 /* End of record marker */
172 #define SE 240 /* End of subnegotiation parameters */
173 #define NOP 241 /* No operation */
174 #define DATA_MARK 242 /* The data stream portion of a Synch.
175 This should always be accompanied
176 by a TCP Urgent notification */
177 #define BRK 243 /* Break character */
178 #define IP 244 /* Interrupt Process */
179 #define AO 245 /* Abort Output */
180 #define AYT 246 /* Are You There */
181 #define EC 247 /* Erase character */
182 #define EL 248 /* Erase Line */
183 #define GA 249 /* Go ahead */
184 #define SB 250 /* Subnegotiation of indicated option */
185 #define WILL 251 /* Indicates the desire to begin
186 performing, or confirmation that
187 you are now performing, the
188 indicated option */
189 #define WONT 252 /* Indicates the refusal to perform,
190 or continue performing, the
191 indicated option */
192 #define DO 253 /* Indicates the request that the
193 other party perform, or
194 confirmation that you are expecting
195 the other party to perform, the
196 indicated option */
197 #define DONT 254 /* Indicates the demand that the
198 other party stop performing,
199 or confirmation that you are no
200 longer expecting the other party
201 to perform, the indicated option */
202 #define IAC 255 /* Interpret as Command */
203
204 /*-------------------------------------------------------------------*/
205 /* 3270 definitions */
206 /*-------------------------------------------------------------------*/
207
208 /* 3270 remote commands */
209 #define R3270_EAU 0x6F /* Erase All Unprotected */
210 #define R3270_EW 0xF5 /* Erase/Write */
211 #define R3270_EWA 0x7E /* Erase/Write Alternate */
212 #define R3270_RB 0xF2 /* Read Buffer */
213 #define R3270_RM 0xF6 /* Read Modified */
214 #define R3270_RMA 0x6E /* Read Modified All */
215 #define R3270_WRT 0xF1 /* Write */
216 #define R3270_WSF 0xF3 /* Write Structured Field */
217
218 /* 3270 orders */
219 #define O3270_SBA 0x11 /* Set Buffer Address */
220 #define O3270_SF 0x1D /* Start Field */
221 #define O3270_SFE 0x29 /* Start Field Extended */
222 #define O3270_SA 0x28 /* Set Attribute */
223 #define O3270_IC 0x13 /* Insert Cursor */
224 #define O3270_MF 0x2C /* Modify Field */
225 #define O3270_PT 0x05 /* Program Tab */
226 #define O3270_RA 0x3C /* Repeat to Address */
227 #define O3270_EUA 0x12 /* Erase Unprotected to Addr */
228 #define O3270_GE 0x08 /* Graphic Escape */
229
230 /* Inbound structured fields */
231 #define SF3270_AID 0x88 /* Aid value of inbound SF */
232 #define SF3270_3270DS 0x80 /* SFID of 3270 datastream SF*/
233
234 /*-------------------------------------------------------------------*/
235 /* Internal macro definitions */
236 /*-------------------------------------------------------------------*/
237
238 /* DEBUG_LVL: 0 = none
239 1 = status
240 2 = headers
241 3 = buffers
242 */
243 #define DEBUG_LVL 0
244
245 #if DEBUG_LVL == 0
246 #define TNSDEBUG1 1 ? ((void)0) : logmsg
247 #define TNSDEBUG2 1 ? ((void)0) : logmsg
248 #define TNSDEBUG3 1 ? ((void)0) : logmsg
249 #endif
250 #if DEBUG_LVL == 1
251 #define TNSDEBUG1 logmsg
252 #define TNSDEBUG2 1 ? ((void)0) : logmsg
253 #define TNSDEBUG3 1 ? ((void)0) : logmsg
254 #endif
255 #if DEBUG_LVL == 2
256 #define TNSDEBUG1 logmsg
257 #define TNSDEBUG2 logmsg
258 #define TNSDEBUG3 1 ? ((void)0) : logmsg
259 #endif
260 #if DEBUG_LVL == 3
261 #define TNSDEBUG1 logmsg
262 #define TNSDEBUG2 logmsg
263 #define TNSDEBUG3 logmsg
264 #endif
265
266 #define TNSERROR logmsg
267
268 #define BUFLEN_3270 65536 /* 3270 Send/Receive buffer */
269 #define BUFLEN_1052 150 /* 1052 Send/Receive buffer */
270
271
272 #undef FIX_QWS_BUG_FOR_MCS_CONSOLES
273
274 /*-------------------------------------------------------------------*/
275 /* SUBROUTINE TO TRACE THE CONTENTS OF AN ASCII MESSAGE PACKET */
276 /*-------------------------------------------------------------------*/
277 #if DEBUG_LVL == 3
278 static void
packet_trace(BYTE * addr,int len)279 packet_trace(BYTE *addr, int len)
280 {
281 int i, offset;
282 BYTE c;
283 BYTE print_chars[17];
284
285 for (offset=0; offset < len; )
286 {
287 memset(print_chars,0,sizeof(print_chars));
288 logmsg("+%4.4X ", offset);
289 for (i=0; i < 16; i++)
290 {
291 c = *addr++;
292 if (offset < len) {
293 logmsg("%2.2X", c);
294 print_chars[i] = '.';
295 if (isprint(c)) print_chars[i] = c;
296 c = guest_to_host(c);
297 if (isprint(c)) print_chars[i] = c;
298 }
299 else {
300 logmsg(" ");
301 }
302 offset++;
303 if ((offset & 3) == 0) {
304 logmsg(" ");
305 }
306 } /* end for(i) */
307 logmsg(" %s\n", print_chars);
308 } /* end for(offset) */
309
310 } /* end function packet_trace */
311 #else
312 #define packet_trace( _addr, _len)
313 #endif
314
315
316 #if 1
get_inet_socket(char * host_serv)317 struct sockaddr_in * get_inet_socket(char *host_serv)
318 {
319 char *host = NULL;
320 char *serv;
321 struct sockaddr_in *sin;
322
323 if((serv = strchr(host_serv,':')))
324 {
325 *serv++ = '\0';
326 if(*host_serv)
327 host = host_serv;
328 }
329 else
330 serv = host_serv;
331
332 if(!(sin = malloc(sizeof(struct sockaddr_in))))
333 return sin;
334
335 sin->sin_family = AF_INET;
336
337 if(host)
338 {
339 struct hostent *hostent;
340
341 hostent = gethostbyname(host);
342
343 if(!hostent)
344 {
345 logmsg(_("HHCGI001I Unable to determine IP address from %s\n"),
346 host);
347 free(sin);
348 return NULL;
349 }
350
351 memcpy(&sin->sin_addr,*hostent->h_addr_list,sizeof(sin->sin_addr));
352 }
353 else
354 sin->sin_addr.s_addr = INADDR_ANY;
355
356 if(serv)
357 {
358 if(!isdigit(*serv))
359 {
360 struct servent *servent;
361
362 servent = getservbyname(serv, "tcp");
363
364 if(!servent)
365 {
366 logmsg(_("HHCGI002I Unable to determine port number from %s\n"),
367 host);
368 free(sin);
369 return NULL;
370 }
371
372 sin->sin_port = servent->s_port;
373 }
374 else
375 sin->sin_port = htons(atoi(serv));
376
377 }
378 else
379 {
380 logmsg(_("HHCGI003E Invalid parameter: %s\n"),
381 host_serv);
382 free(sin);
383 return NULL;
384 }
385
386 return sin;
387
388 }
389
390 #endif
391 /*-------------------------------------------------------------------*/
392 /* SUBROUTINE TO DOUBLE UP ANY IAC BYTES IN THE DATA STREAM */
393 /* Returns the new length after inserting extra IAC bytes */
394 /*-------------------------------------------------------------------*/
395 static int
double_up_iac(BYTE * buf,int len)396 double_up_iac (BYTE *buf, int len)
397 {
398 int m, n, x, newlen;
399
400 /* Count the number of IAC bytes in the data */
401 for (x=0, n=0; n < len; n++)
402 if (buf[n] == IAC) x++;
403
404 /* Exit if nothing to do */
405 if (x == 0) return len;
406
407 /* Insert extra IAC bytes backwards from the end of the buffer */
408 newlen = len + x;
409 TNSDEBUG3("console: DBG002: %d IAC bytes added, newlen=%d\n",
410 x, newlen);
411 for (n=newlen, m=len; n > m; ) {
412 buf[--n] = buf[--m];
413 if (buf[n] == IAC) buf[--n] = IAC;
414 }
415 packet_trace (buf, newlen);
416 return newlen;
417
418 } /* end function double_up_iac */
419
420
421 /*-------------------------------------------------------------------*/
422 /* SUBROUTINE TO TRANSLATE A NULL-TERMINATED STRING TO EBCDIC */
423 /*-------------------------------------------------------------------*/
424 static BYTE *
translate_to_ebcdic(char * str)425 translate_to_ebcdic (char *str)
426 {
427 int i; /* Array subscript */
428 BYTE c; /* Character work area */
429
430 for (i = 0; str[i] != '\0'; i++)
431 {
432 c = str[i];
433 str[i] = (isprint(c) ? host_to_guest(c) : SPACE);
434 }
435
436 return (BYTE *)str;
437 } /* end function translate_to_ebcdic */
438
439
440 /*-------------------------------------------------------------------*/
441 /* SUBROUTINE TO SEND A DATA PACKET TO THE CLIENT */
442 /*-------------------------------------------------------------------*/
443 static int
send_packet(int csock,BYTE * buf,int len,char * caption)444 send_packet (int csock, BYTE *buf, int len, char *caption)
445 {
446 int rc; /* Return code */
447
448 if (caption != NULL) {
449 TNSDEBUG2("console: DBG003: Sending %s\n", caption);
450 packet_trace (buf, len);
451 }
452
453 rc = send (csock, buf, len, 0);
454
455 if (rc < 0) {
456 TNSERROR("console: DBG021: send: %s\n", strerror(HSO_errno));
457 return -1;
458 } /* end if(rc) */
459
460 return 0;
461
462 } /* end function send_packet */
463
464
465 /*-------------------------------------------------------------------*/
466 /* SUBROUTINE TO RECEIVE A DATA PACKET FROM THE CLIENT */
467 /* This subroutine receives bytes from the client. It stops when */
468 /* the receive buffer is full, or when the last two bytes received */
469 /* consist of the IAC character followed by a specified delimiter. */
470 /* If zero bytes are received, this means the client has closed the */
471 /* connection, and this is treated as an error. */
472 /* Input: */
473 /* csock is the socket number */
474 /* buf points to area to receive data */
475 /* reqlen is the number of bytes requested */
476 /* delim is the delimiter character (0=no delimiter) */
477 /* Output: */
478 /* buf is updated with data received */
479 /* The return value is the number of bytes received, or */
480 /* -1 if an error occurred. */
481 /*-------------------------------------------------------------------*/
482 static int
recv_packet(int csock,BYTE * buf,int reqlen,BYTE delim)483 recv_packet (int csock, BYTE *buf, int reqlen, BYTE delim)
484 {
485 int rc=0; /* Return code */
486 int rcvlen=0; /* Length of data received */
487
488 while (rcvlen < reqlen) {
489
490 rc = recv (csock, buf + rcvlen, reqlen - rcvlen, 0);
491
492 if (rc < 0) {
493 TNSERROR("console: DBG022: recv: %s\n", strerror(HSO_errno));
494 return -1;
495 }
496
497 if (rc == 0) {
498 TNSDEBUG1("console: DBG004: Connection closed by client\n");
499 return -1;
500 }
501
502 rcvlen += rc;
503
504 if (delim != '\0' && rcvlen >= 2
505 && buf[rcvlen-2] == IAC && buf[rcvlen-1] == delim)
506 break;
507 }
508
509 TNSDEBUG2("console: DBG005: Packet received length=%d\n", rcvlen);
510 packet_trace (buf, rcvlen);
511
512 return rcvlen;
513
514 } /* end function recv_packet */
515
516
517 /*-------------------------------------------------------------------*/
518 /* SUBROUTINE TO RECEIVE A PACKET AND COMPARE WITH EXPECTED VALUE */
519 /*-------------------------------------------------------------------*/
520 static int
expect(int csock,BYTE * expected,int len,char * caption)521 expect (int csock, BYTE *expected, int len, char *caption)
522 {
523 int rc; /* Return code */
524 BYTE buf[512]; /* Receive buffer */
525 #if 1
526 /* TCP/IP for MVS returns the server sequence rather then
527 the client sequence during bin negotiation 19/06/00 Jan Jaeger */
528 static BYTE do_bin[] = { IAC, DO, BINARY, IAC, WILL, BINARY };
529 static BYTE will_bin[] = { IAC, WILL, BINARY, IAC, DO, BINARY };
530 #endif
531
532 UNREFERENCED(caption);
533
534 rc = recv_packet (csock, buf, len, 0);
535 if (rc < 0) return -1;
536
537 #if 1
538 /* TCP/IP FOR MVS DOES NOT COMPLY TO RFC 1576 THIS IS A BYPASS */
539 if(memcmp(buf, expected, len) != 0
540 && !(len == sizeof(will_bin)
541 && memcmp(expected, will_bin, len) == 0
542 && memcmp(buf, do_bin, len) == 0) )
543 #else
544 if (memcmp(buf, expected, len) != 0)
545 #endif
546 {
547 TNSDEBUG2("console: DBG006: Expected %s\n", caption);
548 return -1;
549 }
550 TNSDEBUG2("console: DBG007: Received %s\n", caption);
551
552 return 0;
553
554 } /* end function expect */
555
556
557 /*-------------------------------------------------------------------*/
558 /* SUBROUTINE TO NEGOTIATE TELNET PARAMETERS */
559 /* This subroutine negotiates the terminal type with the client */
560 /* and uses the terminal type to determine whether the client */
561 /* is to be supported as a 3270 display console or as a 1052/3215 */
562 /* printer-keyboard console. */
563 /* */
564 /* Valid display terminal types are "IBM-NNNN", "IBM-NNNN-M", and */
565 /* "IBM-NNNN-M-E", where NNNN is 3270, 3277, 3278, 3279, 3178, 3179, */
566 /* or 3180, M indicates the screen size (2=25x80, 3=32x80, 4=43x80, */
567 /* 5=27x132, X=determined by Read Partition Query command), and */
568 /* -E is an optional suffix indicating that the terminal supports */
569 /* extended attributes. Displays are negotiated into tn3270 mode. */
570 /* An optional device number suffix (example: IBM-3270@01F) may */
571 /* be specified to request allocation to a specific device number. */
572 /* Valid 3270 printer type is "IBM-3287-1" */
573 /* */
574 /* Terminal types whose first four characters are not "IBM-" are */
575 /* handled as printer-keyboard consoles using telnet line mode. */
576 /* */
577 /* Input: */
578 /* csock Socket number for client connection */
579 /* Output: */
580 /* class D=3270 display console, K=printer-keyboard console */
581 /* P=3270 printer */
582 /* model 3270 model indicator (2,3,4,5,X) */
583 /* extatr 3270 extended attributes (Y,N) */
584 /* devn Requested device number, or FFFF=any device number */
585 /* Return value: */
586 /* 0=negotiation successful, -1=negotiation error */
587 /*-------------------------------------------------------------------*/
588 static int
negotiate(int csock,BYTE * class,BYTE * model,BYTE * extatr,U16 * devn,char * group)589 negotiate(int csock, BYTE *class, BYTE *model, BYTE *extatr, U16 *devn,char *group)
590 {
591 int rc; /* Return code */
592 char *termtype; /* Pointer to terminal type */
593 char *s; /* String pointer */
594 BYTE c; /* Trailing character */
595 U16 devnum; /* Requested device number */
596 BYTE buf[512]; /* Telnet negotiation buffer */
597 static BYTE do_term[] = { IAC, DO, TERMINAL_TYPE };
598 static BYTE will_term[] = { IAC, WILL, TERMINAL_TYPE };
599 static BYTE req_type[] = { IAC, SB, TERMINAL_TYPE, SEND, IAC, SE };
600 static BYTE type_is[] = { IAC, SB, TERMINAL_TYPE, IS };
601 static BYTE do_eor[] = { IAC, DO, EOR, IAC, WILL, EOR };
602 static BYTE will_eor[] = { IAC, WILL, EOR, IAC, DO, EOR };
603 static BYTE do_bin[] = { IAC, DO, BINARY, IAC, WILL, BINARY };
604 static BYTE will_bin[] = { IAC, WILL, BINARY, IAC, DO, BINARY };
605 #if 0
606 static BYTE do_tmark[] = { IAC, DO, TIMING_MARK };
607 static BYTE will_tmark[] = { IAC, WILL, TIMING_MARK };
608 static BYTE wont_sga[] = { IAC, WONT, SUPPRESS_GA };
609 static BYTE dont_sga[] = { IAC, DONT, SUPPRESS_GA };
610 #endif
611 static BYTE wont_echo[] = { IAC, WONT, ECHO_OPTION };
612 static BYTE dont_echo[] = { IAC, DONT, ECHO_OPTION };
613 static BYTE will_naws[] = { IAC, WILL, NAWS };
614
615 /* Perform terminal-type negotiation */
616 rc = send_packet (csock, do_term, sizeof(do_term),
617 "IAC DO TERMINAL_TYPE");
618 if (rc < 0) return -1;
619
620 rc = expect (csock, will_term, sizeof(will_term),
621 "IAC WILL TERMINAL_TYPE");
622 if (rc < 0) return -1;
623
624 /* Request terminal type */
625 rc = send_packet (csock, req_type, sizeof(req_type),
626 "IAC SB TERMINAL_TYPE SEND IAC SE");
627 if (rc < 0) return -1;
628
629 rc = recv_packet (csock, buf, sizeof(buf)-2, SE);
630 if (rc < 0) return -1;
631
632 /* Ignore Negotiate About Window Size */
633 if (rc >= (int)sizeof(will_naws) &&
634 memcmp (buf, will_naws, sizeof(will_naws)) == 0)
635 {
636 memmove(buf, &buf[sizeof(will_naws)], (rc - sizeof(will_naws)));
637 rc -= sizeof(will_naws);
638 }
639
640 if (rc < (int)(sizeof(type_is) + 2)
641 || memcmp(buf, type_is, sizeof(type_is)) != 0
642 || buf[rc-2] != IAC || buf[rc-1] != SE) {
643 TNSDEBUG2("console: DBG008: Expected IAC SB TERMINAL_TYPE IS\n");
644 return -1;
645 }
646 buf[rc-2] = '\0';
647 termtype = (char *)(buf + sizeof(type_is));
648 TNSDEBUG2("console: DBG009: Received IAC SB TERMINAL_TYPE IS %s IAC SE\n",
649 termtype);
650
651 /* Check terminal type string for device name suffix */
652 s = strchr (termtype, '@');
653 if(s!=NULL)
654 {
655 if(strlen(s)<16)
656 {
657 strlcpy(group,&s[1],16);
658 }
659 }
660 else
661 {
662 group[0]=0;
663 }
664
665 if (s != NULL && sscanf (s, "@%hx%c", &devnum,&c) == 1)
666 {
667 *devn = devnum;
668 group[0]=0;
669 }
670 else
671 {
672 *devn = 0xFFFF;
673 }
674
675 /* Test for non-display terminal type */
676 if (memcmp(termtype, "IBM-", 4) != 0)
677 {
678 #if 0
679 /* Perform line mode negotiation */
680 rc = send_packet (csock, do_tmark, sizeof(do_tmark),
681 "IAC DO TIMING_MARK");
682 if (rc < 0) return -1;
683
684 rc = expect (csock, will_tmark, sizeof(will_tmark),
685 "IAC WILL TIMING_MARK");
686 if (rc < 0) return 0;
687
688 rc = send_packet (csock, wont_sga, sizeof(wont_sga),
689 "IAC WONT SUPPRESS_GA");
690 if (rc < 0) return -1;
691
692 rc = expect (csock, dont_sga, sizeof(dont_sga),
693 "IAC DONT SUPPRESS_GA");
694 if (rc < 0) return -1;
695 #endif
696
697 if (memcmp(termtype, "ANSI", 4) == 0)
698 {
699 rc = send_packet (csock, wont_echo, sizeof(wont_echo),
700 "IAC WONT ECHO");
701 if (rc < 0) return -1;
702
703 rc = expect (csock, dont_echo, sizeof(dont_echo),
704 "IAC DONT ECHO");
705 if (rc < 0) return -1;
706 }
707
708 /* Return printer-keyboard terminal class */
709 *class = 'K';
710 *model = '-';
711 *extatr = '-';
712 return 0;
713 }
714
715 /* Determine display terminal model */
716 if (memcmp(termtype+4,"DYNAMIC",7) == 0) {
717 *model = 'X';
718 *extatr = 'Y';
719 } else {
720 if (!(memcmp(termtype+4, "3277", 4) == 0
721 || memcmp(termtype+4, "3270", 4) == 0
722 || memcmp(termtype+4, "3178", 4) == 0
723 || memcmp(termtype+4, "3278", 4) == 0
724 || memcmp(termtype+4, "3179", 4) == 0
725 || memcmp(termtype+4, "3180", 4) == 0
726 || memcmp(termtype+4, "3287", 4) == 0
727 || memcmp(termtype+4, "3279", 4) == 0))
728 return -1;
729
730 *model = '2';
731 *extatr = 'N';
732
733 if (termtype[8]=='-') {
734 if (termtype[9] < '1' || termtype[9] > '5')
735 return -1;
736 *model = termtype[9];
737 if (memcmp(termtype+4, "328",3) == 0) *model = '2';
738 if (memcmp(termtype+10, "-E", 2) == 0)
739 *extatr = 'Y';
740 }
741 }
742
743 /* Perform end-of-record negotiation */
744 rc = send_packet (csock, do_eor, sizeof(do_eor),
745 "IAC DO EOR IAC WILL EOR");
746 if (rc < 0) return -1;
747
748 rc = expect (csock, will_eor, sizeof(will_eor),
749 "IAC WILL EOR IAC DO EOR");
750 if (rc < 0) return -1;
751
752 /* Perform binary negotiation */
753 rc = send_packet (csock, do_bin, sizeof(do_bin),
754 "IAC DO BINARY IAC WILL BINARY");
755 if (rc < 0) return -1;
756
757 rc = expect (csock, will_bin, sizeof(will_bin),
758 "IAC WILL BINARY IAC DO BINARY");
759 if (rc < 0) return -1;
760
761 /* Return display terminal class */
762 if (memcmp(termtype+4,"3287",4)==0) *class='P';
763 else *class = 'D';
764 return 0;
765
766 } /* end function negotiate */
767
768 /*-------------------------------------------------------------------*/
769 /* NEW CLIENT CONNECTION */
770 /*-------------------------------------------------------------------*/
771 static int
connect_client(int * csockp)772 connect_client (int *csockp)
773 /* returns 1 if 3270, else 0 */
774 {
775 int rc; /* Return code */
776 size_t len; /* Data length */
777 int csock; /* Socket for conversation */
778 struct sockaddr_in client; /* Client address structure */
779 socklen_t namelen; /* Length of client structure*/
780 char *clientip; /* Addr of client ip address */
781 U16 devnum; /* Requested device number */
782 BYTE class; /* D=3270, P=3287, K=3215/1052 */
783 BYTE model; /* 3270 model (2,3,4,5,X) */
784 BYTE extended; /* Extended attributes (Y,N) */
785 char buf[256]; /* Message buffer */
786 char conmsg[256]; /* Connection message */
787 char devmsg[25]; /* Device message */
788 char hostmsg[256]; /* Host ID message */
789 char num_procs[16]; /* #of processors string */
790 char group[16]; /* Console group */
791
792 /* Load the socket address from the thread parameter */
793 csock = *csockp;
794
795 /* Obtain the client's IP address */
796 namelen = sizeof(client);
797 rc = getpeername (csock, (struct sockaddr *)&client, &namelen);
798
799 /* Log the client's IP address and hostname */
800 clientip = strdup(inet_ntoa(client.sin_addr));
801
802 #if 0
803 // The following isn't really needed and hangs under unusual
804 // network configuration settings and thus has been removed.
805 {
806 struct hostent* pHE; /* Addr of hostent structure */
807 char* clientname; /* Addr of client hostname */
808
809 pHE = gethostbyaddr ((unsigned char*)(&client.sin_addr),
810 sizeof(client.sin_addr), AF_INET);
811
812 if (pHE != NULL && pHE->h_name != NULL
813 && pHE->h_name[0] != '\0') {
814 clientname = (char*) pHE->h_name;
815 } else {
816 clientname = "host name unknown";
817 }
818
819 TNSDEBUG1("console: DBG018: Received connection from %s (%s)\n",
820 clientip, clientname);
821 }
822 #else
823 TNSDEBUG1("console: DBG018: Received connection from %s\n",
824 clientip );
825 #endif
826
827 /* Negotiate telnet parameters */
828 rc = negotiate (csock, &class, &model, &extended, &devnum, group);
829 if (rc != 0)
830 {
831 close_socket (csock);
832 if (clientip) free(clientip);
833 return 0;
834 }
835
836 /* Build connection message for client */
837
838 if ( cons_hostinfo.num_procs > 1 )
839 snprintf( num_procs, sizeof(num_procs), "MP=%d", cons_hostinfo.num_procs );
840 else
841 strlcpy( num_procs, "UP", sizeof(num_procs) );
842
843 snprintf
844 (
845 hostmsg, sizeof(hostmsg),
846
847 "running on %s (%s-%s.%s %s %s)"
848
849 ,cons_hostinfo.nodename
850 ,cons_hostinfo.sysname
851 ,cons_hostinfo.release
852 ,cons_hostinfo.version
853 ,cons_hostinfo.machine
854 ,num_procs
855 );
856 snprintf (conmsg, sizeof(conmsg),
857 "Hercules version %s built on %s %s",
858 VERSION, __DATE__, __TIME__);
859
860 {
861 snprintf (devmsg, sizeof(devmsg), "Connected to device %4.4X",
862 0);
863 }
864
865 logmsg (_("HHCTE009I Client %s connected to %4.4X device %4.4X\n"),
866 clientip, 0x3270, 0);
867
868 /* Send connection message to client */
869 if (class != 'K')
870 {
871 len = snprintf (buf, sizeof(buf),
872 "\xF5\x40\x11\x40\x40\x1D\x60%s"
873 "\x11\xC1\x50\x1D\x60%s"
874 "\x11\xC2\x60\x1D\x60%s",
875 translate_to_ebcdic(conmsg),
876 translate_to_ebcdic(hostmsg),
877 translate_to_ebcdic(devmsg));
878
879 if (len < sizeof(buf))
880 {
881 buf[len++] = IAC;
882 }
883 else
884 {
885 ASSERT(FALSE);
886 }
887
888 if (len < sizeof(buf))
889 {
890 buf[len++] = EOR_MARK;
891 }
892 else
893 {
894 ASSERT(FALSE);
895 }
896 }
897 else
898 {
899 len = snprintf (buf, sizeof(buf), "%s\r\n%s\r\n%s\r\n",
900 conmsg, hostmsg, devmsg);
901 }
902
903 if (class != 'P') /* do not write connection resp on 3287 */
904 {
905 rc = send_packet (csock, (BYTE *)buf, len, "CONNECTION RESPONSE");
906 }
907 return (class == 'D') ? 1 : 0; /* return 1 if 3270 */
908 } /* end function connect_client */
909
910
logdump(char * txt,DEVBLK * dev,BYTE * bfr,size_t sz)911 static void logdump(char *txt,DEVBLK *dev,BYTE *bfr,size_t sz)
912 {
913 size_t i;
914 if(!dev->ccwtrace)
915 {
916 return;
917 }
918 logmsg(_("HHCCA300D %4.4X:%s\n"),
919 dev->devnum,
920 txt);
921 logmsg(_("HHCCA300D %4.4X:%s : Dump of %d (%x) byte(s)\n"),dev->devnum,txt,sz,sz);
922 for(i=0;i<sz;i++)
923 {
924 if(i%16==0)
925 {
926 if(i!=0)
927 {
928 logmsg("\n");
929 }
930 logmsg(_("HHCCA300D %4.4X:%s : %4.4X:"),dev->devnum,txt,i);
931 }
932 if(i%4==0)
933 {
934 logmsg(" ");
935 }
936 logmsg("%2.2X",bfr[i]);
937 }
938 logmsg("\nHHCCA300D ");
939 for(i=0;i<sz;i++)
940 {
941 if(i%16==0)
942 {
943 if(i!=0)
944 {
945 logmsg("\nHHCCA300D ");
946 }
947 }
948 logmsg (_("%c"),(bfr[i] & 0x7f) < 0x20 ? '.' : (bfr[i] & 0x7f));
949 }
950 logmsg("\n");
951 }
952
put_bufpool(void ** anchor,BYTE * ele)953 static void put_bufpool(void ** anchor, BYTE * ele) {
954 void ** elep = anchor;
955 for (;;) {
956 if (!*elep) break;
957 elep = *elep;
958 }
959 *elep = ele;
960 *(void**)ele = 0;
961 }
962
get_bufpool(void ** anchor)963 static BYTE * get_bufpool(void ** anchor) {
964 void ** elep = *anchor;
965 if (elep) {
966 *anchor = *elep;
967 } else {
968 *anchor = 0;
969 }
970 return (BYTE*)elep;
971 }
972
init_bufpool(COMMADPT * ca)973 static void init_bufpool(COMMADPT *ca) {
974 BYTE * areap;
975 int i1;
976 int numbufs = 64;
977 int bufsize = ca->unitsz+16+4;
978 ca->poolarea = (BYTE*)calloc (numbufs, bufsize);
979 if (!ca->poolarea) {
980 return;
981 }
982 areap = ca->poolarea;
983 for (i1 = 0; i1 < numbufs; i1++) {
984 put_bufpool(&ca->freeq, areap);
985 areap += (bufsize);
986 }
987 }
988
free_bufpool(COMMADPT * ca)989 static void free_bufpool(COMMADPT *ca) {
990 ca->sendq = 0;
991 ca->freeq = 0;
992 if (ca->poolarea) {
993 free(ca->poolarea);
994 ca->poolarea = 0;
995 }
996 }
997
998 /*-------------------------------------------------------------------*/
999 /* Free all private structures and buffers */
1000 /*-------------------------------------------------------------------*/
commadpt_clean_device(DEVBLK * dev)1001 static void commadpt_clean_device(DEVBLK *dev)
1002 {
1003 if(dev->commadpt!=NULL)
1004 {
1005 free(dev->commadpt);
1006 dev->commadpt=NULL;
1007 if(dev->ccwtrace)
1008 {
1009 logmsg(_("HHCCA300D %4.4X:clean : Control block freed\n"),
1010 dev->devnum);
1011 }
1012 }
1013 else
1014 {
1015 if(dev->ccwtrace)
1016 {
1017 logmsg(_("HHCCA300D %4.4X:clean : Control block not freed : not allocated\n"),dev->devnum);
1018 }
1019 }
1020 return;
1021 }
1022
1023 /*-------------------------------------------------------------------*/
1024 /* Allocate initial private structures */
1025 /*-------------------------------------------------------------------*/
commadpt_alloc_device(DEVBLK * dev)1026 static int commadpt_alloc_device(DEVBLK *dev)
1027 {
1028 dev->commadpt=malloc(sizeof(COMMADPT));
1029 if(dev->commadpt==NULL)
1030 {
1031 logmsg(_("HHCCA020E %4.4X:Memory allocation failure for main control block\n"),
1032 dev->devnum);
1033 return -1;
1034 }
1035 memset(dev->commadpt,0,sizeof(COMMADPT));
1036 dev->commadpt->dev=dev;
1037 return 0;
1038 }
1039 /*-------------------------------------------------------------------*/
1040 /* Parsing utilities */
1041 /*-------------------------------------------------------------------*/
1042 /*-------------------------------------------------------------------*/
1043 /* commadpt_getport : returns a port number or -1 */
1044 /*-------------------------------------------------------------------*/
commadpt_getport(char * txt)1045 static int commadpt_getport(char *txt)
1046 {
1047 int pno;
1048 struct servent *se;
1049 pno=atoi(txt);
1050 if(pno==0)
1051 {
1052 se=getservbyname(txt,"tcp");
1053 if(se==NULL)
1054 {
1055 return -1;
1056 }
1057 pno=se->s_port;
1058 }
1059 return(pno);
1060 }
1061 /*-------------------------------------------------------------------*/
1062 /* commadpt_getaddr : set an in_addr_t if ok, else return -1 */
1063 /*-------------------------------------------------------------------*/
commadpt_getaddr(in_addr_t * ia,char * txt)1064 static int commadpt_getaddr(in_addr_t *ia,char *txt)
1065 {
1066 struct hostent *he;
1067 he=gethostbyname(txt);
1068 if(he==NULL)
1069 {
1070 return(-1);
1071 }
1072 memcpy(ia,he->h_addr_list[0],4);
1073 return(0);
1074 }
1075
connect_message(int sfd,int na,int flag)1076 static void connect_message(int sfd, int na, int flag) {
1077 int rc;
1078 struct sockaddr_in client;
1079 socklen_t namelen;
1080 char *ipaddr;
1081 char msgtext[256];
1082 if (!sfd)
1083 return;
1084 namelen = sizeof(client);
1085 rc = getpeername (sfd, (struct sockaddr *)&client, &namelen);
1086 ipaddr = inet_ntoa(client.sin_addr);
1087 if (flag == 0)
1088 sprintf(msgtext, "%s:%d VTAM CONNECTION ACCEPTED - NETWORK NODE= %4.4X", ipaddr, (int)ntohs(client.sin_port), na);
1089 else
1090 sprintf(msgtext, "%s:%d VTAM CONNECTION TERMINATED", ipaddr, (int)ntohs(client.sin_port));
1091 logmsg( _("%s\n"), msgtext);
1092 write(sfd, msgtext, strlen(msgtext));
1093 write(sfd, "\r\n", 2);
1094 }
1095
commadpt_read_tty(COMMADPT * ca,BYTE * bfr,int len)1096 static void commadpt_read_tty(COMMADPT *ca, BYTE * bfr, int len)
1097 // everything has been tortured to now do 3270 also
1098 {
1099 BYTE bfr3[3];
1100 BYTE c;
1101 int i1;
1102 int eor=0;
1103 logdump("RECV",ca->dev, bfr,len);
1104 /* If there is a complete data record already in the buffer
1105 then discard it before reading more data
1106 For TTY, allow data to accumulate until CR is received */
1107 if (ca->is_3270) {
1108 if (ca->inpbufl) {
1109 ca->rlen3270 = 0;
1110 ca->inpbufl = 0;
1111 }
1112 }
1113 for (i1 = 0; i1 < len; i1++) {
1114 c = (unsigned char) bfr[i1];
1115 if (ca->telnet_opt) {
1116 ca->telnet_opt = 0;
1117 if(ca->dev->ccwtrace)
1118 logmsg(_("HHCCA300D %4.4X: Received TELNET CMD 0x%02x 0x%02x\n"),
1119 ca->dev->devnum,
1120 ca->telnet_cmd, c);
1121 bfr3[0] = 0xff; /* IAC */
1122 /* set won't/don't for all received commands */
1123 bfr3[1] = (ca->telnet_cmd == 0xfd) ? 0xfc : 0xfe;
1124 bfr3[2] = c;
1125 if (ca->sfd > 0) {
1126 write_socket(ca->sfd,bfr3,3);
1127 }
1128 if(ca->dev->ccwtrace)
1129 logmsg(_("HHCCA300D %4.4X: Sending TELNET CMD 0x%02x 0x%02x\n"),
1130 ca->dev->devnum,
1131 bfr3[1], bfr3[2]);
1132 continue;
1133 }
1134 if (ca->telnet_iac) {
1135 ca->telnet_iac = 0;
1136 if(ca->dev->ccwtrace)
1137 logmsg(_("HHCCA300D %4.4X: Received TELNET IAC 0x%02x\n"),
1138 ca->dev->devnum,
1139 c);
1140 switch (c) {
1141 case 0xFB: /* TELNET WILL option cmd */
1142 case 0xFD: /* TELNET DO option cmd */
1143 ca->telnet_opt = 1;
1144 ca->telnet_cmd = c;
1145 break;
1146 case 0xF4: /* TELNET interrupt */
1147 if (!ca->telnet_int) {
1148 ca->telnet_int = 1;
1149 }
1150 break;
1151 case EOR_MARK:
1152 eor = 1;
1153 break;
1154 case 0xFF: /* IAC IAC */
1155 ca->inpbuf[ca->rlen3270++] = 0xFF;
1156 break;
1157 }
1158 continue;
1159 }
1160 if (c == 0xFF) { /* TELNET IAC */
1161 ca->telnet_iac = 1;
1162 continue;
1163 } else {
1164 ca->telnet_iac = 0;
1165 }
1166 if (!ca->is_3270) {
1167 if (c == 0x0D) // CR in TTY mode ?
1168 ca->eol_flag = 1;
1169 c = host_to_guest(c); // translate ASCII to EBCDIC for tty
1170 }
1171 ca->inpbuf[ca->rlen3270++] = c;
1172 }
1173 /* received data (rlen3270 > 0) is sufficient for 3270,
1174 but for TTY, eol_flag must also be set */
1175 if ((ca->eol_flag || ca->is_3270) && ca->rlen3270) {
1176 ca->eol_flag = 0;
1177 if (ca->is_3270) {
1178 if (eor) {
1179 ca->inpbufl = ca->rlen3270;
1180 ca->rlen3270 = 0; /* for next msg */
1181 }
1182 } else {
1183 ca->inpbufl = ca->rlen3270;
1184 ca->rlen3270 = 0; /* for next msg */
1185 }
1186 if(ca->dev->ccwtrace)
1187 logmsg(_("%4.4X: posted %d input bytes\n"),ca->dev->devnum,ca->inpbufl);
1188 }
1189 }
1190
telnet_thread(void * vca)1191 static void *telnet_thread(void *vca) {
1192 COMMADPT *ca;
1193 int devnum; /* device number copy for convenience*/
1194 int sockopt; /* Used for setsocketoption */
1195 int ca_shutdown=0; /* Thread shutdown internal flag */
1196 int rc; /* return code from various rtns */
1197 struct sockaddr_in sin; /* bind socket address structure */
1198 BYTE bfr[256];
1199
1200 ca=(COMMADPT*)vca;
1201 /* get a work copy of devnum (for messages) */
1202 ca->sfd = 0;
1203 devnum=ca->devnum;
1204
1205 ca->lfd=socket(AF_INET,SOCK_STREAM,0);
1206 if(!socket_is_socket(ca->lfd))
1207 {
1208 logmsg(_("HHCCA003E %4.4X:Cannot obtain socket for incoming calls : %s\n"),devnum,strerror(HSO_errno));
1209 ca->have_cthread=0;
1210 release_lock(&ca->lock);
1211 return NULL;
1212 }
1213
1214 /* Reuse the address regardless of any */
1215 /* spurious connection on that port */
1216 sockopt=1;
1217 setsockopt(ca->lfd,SOL_SOCKET,SO_REUSEADDR,(GETSET_SOCKOPT_T*)&sockopt,sizeof(sockopt));
1218
1219 /* Bind the socket */
1220 sin.sin_family=AF_INET;
1221 sin.sin_addr.s_addr=ca->lhost;
1222 sin.sin_port=htons(ca->lport);
1223 while(1)
1224 {
1225 rc=bind(ca->lfd,(struct sockaddr *)&sin,sizeof(sin));
1226 if(rc<0)
1227 {
1228 logmsg(_("HHCCA018E %4.4X:Bind failed : %s\n"),devnum,strerror(HSO_errno));
1229 ca_shutdown=1;
1230 break;
1231 }
1232 else
1233 {
1234 break;
1235 }
1236 }
1237 /* Start the listen */
1238 if(!ca_shutdown)
1239 {
1240 listen(ca->lfd,10);
1241 logmsg(_("HHCCA005I %4.4X:Listening on port %d for incoming TCP connections\n"),
1242 devnum,
1243 ca->lport);
1244 }
1245 for (;;) {
1246 ca->sfd = 0;
1247 ca->sfd=accept(ca->lfd,NULL,0);
1248 if (ca->sfd < 1) continue;
1249 if (connect_client(&ca->sfd)) {
1250 ca->is_3270 = 1;
1251 } else {
1252 ca->is_3270 = 0;
1253 }
1254 socket_set_blocking_mode(ca->sfd,0); // set to non-blocking mode
1255 if (ca->emu3791 == 0) {make_sna_requests4(ca, 0, (ca->is_3270) ? 0x02 : 0x01);} // send REQCONT
1256 ca->hangup = 0;
1257 for (;;) {
1258 usleep(50000);
1259 if (ca->hangup)
1260 break;
1261 /* read_socket has changed from 3.04 to 3.06 - we need old way */
1262 #ifdef _MSVC_
1263 rc=recv(ca->sfd,bfr,ca->unitsz-BUFPD,0);
1264 #else
1265 rc=read(ca->sfd,bfr,ca->unitsz-BUFPD);
1266 #endif
1267 if (rc < 0) {
1268 if(0
1269 #ifndef WIN32
1270 || EAGAIN == errno
1271 #endif
1272 || HSO_EWOULDBLOCK == HSO_errno
1273 ) {
1274 continue;
1275 }
1276 break;
1277 // make_sna_requests4(ca, 1); // send REQDISCONT
1278 if (ca->emu3791 == 0) {make_sna_requests5(ca);}
1279 }
1280 if (rc == 0) {
1281 // make_sna_requests4(ca, 1); // send REQDISCONT
1282 if (ca->emu3791 == 0) {make_sna_requests5(ca);}
1283 break;
1284 }
1285 commadpt_read_tty(ca,bfr,rc);
1286 }
1287 close_socket(ca->sfd);
1288 ca->sfd = 0;
1289 }
1290 }
1291
1292 /*-------------------------------------------------------------------*/
1293 /* Communication Thread main loop */
1294 /*-------------------------------------------------------------------*/
commadpt_thread(void * vca)1295 static void *commadpt_thread(void *vca)
1296 {
1297 COMMADPT *ca; /* Work CA Control Block Pointer */
1298 int devnum; /* device number copy for convenience*/
1299 int delay; /* unacknowledged attention delay */
1300 int rc; /* return code from various rtns */
1301 int ca_shutdown; /* Thread shutdown internal flag */
1302 int init_signaled; /* Thread initialisation signaled */
1303
1304 /*---------------------END OF DECLARES---------------------------*/
1305
1306 /* fetch the commadpt structure */
1307 ca=(COMMADPT *)vca;
1308
1309 /* Obtain the CA lock */
1310 obtain_lock(&ca->lock);
1311
1312 /* get a work copy of devnum (for messages) */
1313 devnum=ca->devnum;
1314
1315 /* reset shutdown flag */
1316 ca_shutdown=0;
1317
1318 init_signaled=0;
1319
1320 logmsg(_("HHCCA002I %4.4X:3705 Communication thread "TIDPAT" started\n"),devnum,thread_id());
1321
1322 for (;;) {
1323 release_lock(&ca->lock);
1324 if(ca->ackspeed == 0) delay = 50000 + (ca->unack_attn_count * 100000); /* Max's reliable algorithm */
1325 else delay = (ca->unack_attn_count * ca->unack_attn_count + 1) * ca->ackspeed; /* much faster but TCAM hates it */
1326 usleep(min(1000000,delay)); /* go to sleep, max. 1 second */
1327 obtain_lock(&ca->lock);
1328 make_sna_requests2(ca);
1329 make_sna_requests3(ca);
1330 if (ca->sendq
1331 // attempt to fix hot i/o bug
1332 && ca->unack_attn_count < 10
1333 ) {
1334 ca->unack_attn_count++;
1335 rc = device_attention(ca->dev, CSW_ATTN);
1336 if(ca->dev->ccwtrace)
1337 logmsg(_("%4.4X: Raised attention rc = %d\n"), ca->dev->devnum, rc);
1338 }
1339 }
1340
1341 logmsg(_("HHCCA009I %4.4X:3705 utility thread terminated\n"),ca->devnum);
1342 release_lock(&ca->lock);
1343 return NULL;
1344 }
1345 /*-------------------------------------------------------------------*/
1346 /* Halt currently executing I/O command */
1347 /*-------------------------------------------------------------------*/
commadpt_halt(DEVBLK * dev)1348 static void commadpt_halt(DEVBLK *dev)
1349 {
1350 if(!dev->busy)
1351 {
1352 return;
1353 }
1354 }
1355
1356 /* The following 3 MSG functions ensure only 1 (one) */
1357 /* hardcoded instance exist for the same numbered msg */
1358 /* that is issued on multiple situations */
msg013e(DEVBLK * dev,char * kw,char * kv)1359 static void msg013e(DEVBLK *dev,char *kw,char *kv)
1360 {
1361 logmsg(_("HHCCA013E %4.4X:Incorrect %s specification %s\n"),dev->devnum,kw,kv);
1362 }
1363 /*-------------------------------------------------------------------*/
1364 /* Device Initialisation */
1365 /*-------------------------------------------------------------------*/
commadpt_init_handler(DEVBLK * dev,int argc,char * argv[])1366 static int commadpt_init_handler (DEVBLK *dev, int argc, char *argv[])
1367 {
1368 char thread_name[32];
1369 char thread_name2[32];
1370 int i;
1371 int rc;
1372 int pc; /* Parse code */
1373 int errcnt;
1374 struct in_addr in_temp;
1375 union {
1376 int num;
1377 char text[80];
1378 } res;
1379 dev->devtype=0x3705;
1380 if(dev->ccwtrace)
1381 {
1382 logmsg(_("HHCCA300D %4.4X:Initialisation starting\n"),dev->devnum);
1383 }
1384
1385 if(dev->commadpt!=NULL)
1386 {
1387 commadpt_clean_device(dev);
1388 }
1389 rc=commadpt_alloc_device(dev);
1390 if(rc<0)
1391 {
1392 logmsg(_("HHCCA010I %4.4X:initialisation not performed\n"),
1393 dev->devnum);
1394 return(-1);
1395 }
1396 if(dev->ccwtrace)
1397 {
1398 logmsg(_("HHCCA300D %4.4X:Initialisation : Control block allocated\n"),dev->devnum);
1399 }
1400 errcnt=0;
1401 /*
1402 * Initialise ports & hosts
1403 */
1404 dev->commadpt->sfd=-1;
1405 dev->commadpt->lport=0;
1406 dev->commadpt->debug_sna=0;
1407 dev->commadpt->emu3791=0;
1408 dev->commadpt->locsuba = 0x3800; /* local subarea = 7 (maxsuba=31) */
1409 dev->commadpt->rmtsuba = 0x4000; /* remote subarea = 8 (maxsuba=31) */
1410 strcpy(dev->commadpt->locncpnm,"MHP3705 "); /* local NCP name */
1411 strcpy(dev->commadpt->rmtncpnm,"MHPRMT1 "); /* remote NCP name */
1412 translate_to_ebcdic(dev->commadpt->locncpnm); /* convert to EBCDIC */
1413 translate_to_ebcdic(dev->commadpt->rmtncpnm); /* convert to EBCDIC */
1414 dev->commadpt->idblk = 0x17; /* IDBLK of switched PU (default=0x017) */
1415 dev->commadpt->idnum = 0x17; /* IDNUM of switched PU (default=0x00017) */
1416 dev->commadpt->unitsz = 256; /* I/O blocksize (must equal RRT KEYLN) */
1417 /* unitsz=256 is invalid for TCAM and */
1418 /* instable for VTAM. Default retained */
1419 /* for compatibility with previous */
1420 /* versions only. */
1421 dev->commadpt->ackspeed = 0; /* choose Max's original attn algorithm */
1422 for(i=0;i<argc;i++)
1423 {
1424 pc=parser(ptab,argv[i],&res);
1425 if(pc<0)
1426 {
1427 logmsg(_("HHCCA011E %4.4X:Error parsing %s\n"),dev->devnum,argv[i]);
1428 errcnt++;
1429 continue;
1430 }
1431 if(pc==0)
1432 {
1433 logmsg(_("HHCCA012E %4.4X:Unrecognized parameter %s\n"),dev->devnum,argv[i]);
1434 errcnt++;
1435 continue;
1436 }
1437 switch(pc)
1438 {
1439 case COMMADPT_KW_DEBUG:
1440 if (res.text[0] == 'y' || res.text[0] == 'Y')
1441 dev->commadpt->debug_sna = 1;
1442 else
1443 dev->commadpt->debug_sna = 0;
1444 break;
1445 case COMMADPT_KW_LPORT:
1446 rc=commadpt_getport(res.text);
1447 if(rc<0)
1448 {
1449 errcnt++;
1450 msg013e(dev,"LPORT",res.text);
1451 break;
1452 }
1453 dev->commadpt->lport=rc;
1454 break;
1455 case COMMADPT_KW_LHOST:
1456 if(strcmp(res.text,"*")==0)
1457 {
1458 dev->commadpt->lhost=INADDR_ANY;
1459 break;
1460 }
1461 rc=commadpt_getaddr(&dev->commadpt->lhost,res.text);
1462 if(rc!=0)
1463 {
1464 msg013e(dev,"LHOST",res.text);
1465 errcnt++;
1466 }
1467 break;
1468 case COMMADPT_KW_EMU3791:
1469 if(strcasecmp(res.text,"yes")==0 || strcmp(res.text,"1"))
1470 dev->commadpt->emu3791=1;
1471 break;
1472 case COMMADPT_KW_LOCSUBA:
1473 dev->commadpt->locsuba = (atoi(res.text)<<11); /* (maxsuba=31) */
1474 break;
1475 case COMMADPT_KW_RMTSUBA:
1476 dev->commadpt->rmtsuba = (atoi(res.text)<<11); /* (maxsuba=31) */
1477 break;
1478 case COMMADPT_KW_LOCNCPNM:
1479 strcpy(dev->commadpt->locncpnm," ");
1480 strcpy(dev->commadpt->locncpnm,res.text);
1481 memcpy(&dev->commadpt->locncpnm[strlen(res.text)]," ",1);
1482 translate_to_ebcdic(dev->commadpt->locncpnm);
1483 break;
1484 case COMMADPT_KW_RMTNCPNM:
1485 strcpy(dev->commadpt->rmtncpnm," ");
1486 strcpy(dev->commadpt->rmtncpnm,res.text);
1487 memcpy(&dev->commadpt->rmtncpnm[strlen(res.text)]," ",1);
1488 translate_to_ebcdic(dev->commadpt->rmtncpnm);
1489 break;
1490 case COMMADPT_KW_IDBLK:
1491 sscanf(res.text,"%3x",&dev->commadpt->idblk);
1492 break;
1493 case COMMADPT_KW_IDNUM:
1494 sscanf(res.text,"%5x",&dev->commadpt->idnum);
1495 break;
1496 case COMMADPT_KW_UNITSZ:
1497 dev->commadpt->unitsz = atoi(res.text);
1498 break;
1499 case COMMADPT_KW_ACKSPEED:
1500 dev->commadpt->ackspeed = atoi(res.text);
1501 break;
1502 default:
1503 break;
1504 }
1505 }
1506 if(errcnt>0)
1507 {
1508 logmsg(_("HHCCA021I %4.4X:Initialisation failed due to previous errors\n"),dev->devnum);
1509 return -1;
1510 }
1511 in_temp.s_addr=dev->commadpt->lhost;
1512 dev->bufsize=dev->commadpt->unitsz;
1513 dev->numsense=2;
1514 memset(dev->sense,0,sizeof(dev->sense));
1515
1516 init_bufpool(dev->commadpt);
1517
1518 dev->commadpt->devnum=dev->devnum;
1519
1520 /* Initialize the CA lock */
1521 initialize_lock(&dev->commadpt->lock);
1522
1523 /* Initialise thread->I/O & halt initiation EVB */
1524 initialize_condition(&dev->commadpt->ipc);
1525 initialize_condition(&dev->commadpt->ipc_halt);
1526
1527 /* Allocate I/O -> Thread signaling pipe */
1528 create_pipe(dev->commadpt->pipe);
1529
1530 /* Point to the halt routine for HDV/HIO/HSCH handling */
1531 dev->halt_device=commadpt_halt;
1532
1533 /* Obtain the CA lock */
1534 obtain_lock(&dev->commadpt->lock);
1535
1536 /* Start the telnet worker thread */
1537
1538 /* Set thread-name for debugging purposes */
1539 snprintf(thread_name2,sizeof(thread_name2),
1540 "commadpt %4.4X thread2",dev->devnum);
1541 thread_name2[sizeof(thread_name2)-1]=0;
1542
1543 if(create_thread(&dev->commadpt->tthread,&sysblk.detattr,telnet_thread,dev->commadpt,thread_name2))
1544 {
1545 logmsg(D_("HHCCA022E create_thread: %s\n"),strerror(errno));
1546 release_lock(&dev->commadpt->lock);
1547 return -1;
1548 }
1549
1550 /* Start the async worker thread */
1551
1552 /* Set thread-name for debugging purposes */
1553 snprintf(thread_name,sizeof(thread_name),
1554 "commadpt %4.4X thread",dev->devnum);
1555 thread_name[sizeof(thread_name)-1]=0;
1556
1557 if(create_thread(&dev->commadpt->cthread,&sysblk.detattr,commadpt_thread,dev->commadpt,thread_name))
1558 {
1559 logmsg(D_("HHCCA022E create_thread: %s\n"),strerror(errno));
1560 release_lock(&dev->commadpt->lock);
1561 return -1;
1562 }
1563 dev->commadpt->have_cthread=1;
1564
1565 /* Release the CA lock */
1566 release_lock(&dev->commadpt->lock);
1567 /* Indicate succesfull completion */
1568 return 0;
1569 }
1570
1571 /*-------------------------------------------------------------------*/
1572 /* Query the device definition */
1573 /*-------------------------------------------------------------------*/
commadpt_query_device(DEVBLK * dev,char ** class,int buflen,char * buffer)1574 static void commadpt_query_device (DEVBLK *dev, char **class,
1575 int buflen, char *buffer)
1576 {
1577 BEGIN_DEVICE_CLASS_QUERY( "LINE", dev, class, buflen, buffer );
1578
1579 snprintf(buffer,buflen,"Read count=%d, Write count=%d", dev->commadpt->read_ccw_count, dev->commadpt->write_ccw_count);
1580 }
1581
1582 /*-------------------------------------------------------------------*/
1583 /* Close the device */
1584 /* Invoked by HERCULES shutdown & DEVINIT processing */
1585 /*-------------------------------------------------------------------*/
commadpt_close_device(DEVBLK * dev)1586 static int commadpt_close_device ( DEVBLK *dev )
1587 {
1588 if(dev->ccwtrace)
1589 {
1590 logmsg(_("HHCCA300D %4.4X:Closing down\n"),dev->devnum);
1591 }
1592
1593 /* Obtain the CA lock */
1594 obtain_lock(&dev->commadpt->lock);
1595
1596 /* Terminate current I/O thread if necessary */
1597 if(dev->busy)
1598 {
1599 commadpt_halt(dev);
1600 }
1601
1602 free_bufpool(dev->commadpt);
1603
1604 /* release the CA lock */
1605 release_lock(&dev->commadpt->lock);
1606
1607 /* Free all work storage */
1608 commadpt_clean_device(dev);
1609
1610 /* Indicate to hercules the device is no longer opened */
1611 dev->fd=-1;
1612
1613 if(dev->ccwtrace)
1614 {
1615 logmsg(_("HHCCA300D %4.4X:Closed down\n"),dev->devnum);
1616 }
1617 return 0;
1618 }
1619
make_seq(COMMADPT * ca,BYTE * reqptr)1620 void make_seq (COMMADPT * ca, BYTE * reqptr) {
1621 if (reqptr[4] == (ca->locsuba >> 8)) { /* local NCP */
1622 reqptr[6] = (unsigned char)(++ca->ncpa_sscp_seqn >> 8) & 0xff;
1623 reqptr[7] = (unsigned char)( ca->ncpa_sscp_seqn ) & 0xff;
1624 } else
1625 if (reqptr[4] == (ca->rmtsuba >> 8)){ /* remote NCP */
1626 reqptr[6] = (unsigned char)(++ca->ncpb_sscp_seqn >> 8) & 0xff;
1627 reqptr[7] = (unsigned char)( ca->ncpb_sscp_seqn ) & 0xff;
1628 }
1629 }
1630
format_sna(BYTE * requestp,char * tag,int devnum)1631 static void format_sna (BYTE * requestp, char * tag, int devnum) {
1632 char fmtbuf[32];
1633 char fmtbuf2[32];
1634 char fmtbuf3[32];
1635 char fmtbuf4[32];
1636 char fmtbuf5[256];
1637 char fmtbuf6[32];
1638 char *ru_type="";
1639 int len;
1640 sprintf(fmtbuf, "%02X%02X %02X%02X %02X%02X %02X%02X %02X%02X",
1641 requestp[0], requestp[1], requestp[2], requestp[3], requestp[4], requestp[5], requestp[6], requestp[7], requestp[8], requestp[9]);
1642 sprintf(fmtbuf2, "%02X%02X%02X",
1643 requestp[10], requestp[11], requestp[12]);
1644 len = (requestp[8] << 8) + requestp[9];
1645 len -= 3; /* for len of ru only */
1646 sprintf(fmtbuf3, "%02X", requestp[13]);
1647 sprintf(fmtbuf4, "%02X", requestp[14]);
1648 if (len > 1)
1649 strcat(fmtbuf3, fmtbuf4);
1650 sprintf(fmtbuf4, "%02X", requestp[15]);
1651 if (len > 2)
1652 strcat(fmtbuf3, fmtbuf4);
1653 if (requestp[13] == 0x11)
1654 ru_type = "ACTPU";
1655 if (requestp[13] == 0x0D)
1656 ru_type = "ACTLU";
1657 if (requestp[13] == 0x0E)
1658 ru_type = "DACTLU";
1659 if (requestp[13] == 0x12)
1660 ru_type = "DACTPU";
1661 if (requestp[13] == 0xA0)
1662 ru_type = "SDT";
1663 if (requestp[13] == 0x31)
1664 ru_type = "BIND";
1665 if (requestp[13] == 0x32)
1666 ru_type = "UNBIND";
1667 if (!memcmp(&requestp[13], R010201, 3))
1668 ru_type = "CONTACT";
1669 if (!memcmp(&requestp[13], R010202, 3))
1670 ru_type = "DISCONTACT";
1671 if (!memcmp(&requestp[13], R010203, 3))
1672 ru_type = "IPLINIT";
1673 if (!memcmp(&requestp[13], R010204, 3))
1674 ru_type = "IPLTEXT";
1675 if (!memcmp(&requestp[13], R010205, 3))
1676 ru_type = "IPLFINAL";
1677 if (!memcmp(&requestp[13], R01020A, 3))
1678 ru_type = "ACTLINK";
1679 if (!memcmp(&requestp[13], R01020B, 3))
1680 ru_type = "DACTLINK";
1681 if (!memcmp(&requestp[13], R010211, 3)) {
1682 sprintf(fmtbuf6, "%s[%02x]", "SETCV", requestp[18]);
1683 ru_type = fmtbuf6;
1684 if ((requestp[10] & 0x80) != 0)
1685 ru_type = "SETCV";
1686 }
1687 if (!memcmp(&requestp[13], R010280, 3))
1688 ru_type = "CONTACTED";
1689 if (!memcmp(&requestp[13], R010281, 3))
1690 ru_type = "INOP";
1691 if (!memcmp(&requestp[13], R010284, 3))
1692 ru_type = "REQCONT";
1693 if (!memcmp(&requestp[13], R01021B, 3))
1694 ru_type = "REQDISCONT";
1695 if (!memcmp(&requestp[13], R01021A, 3))
1696 ru_type = "FNA";
1697 if (!memcmp(&requestp[13], R01020F, 3))
1698 ru_type = "ABCONN";
1699 if (!memcmp(&requestp[13], R010219, 3))
1700 ru_type = "ANA";
1701 if (!memcmp(&requestp[13], R010216, 3))
1702 ru_type = "ACTCONNIN";
1703 if (!memcmp(&requestp[13], R010217, 3))
1704 ru_type = "DACTCONNIN";
1705 if ((requestp[10] & 0x08) == 0)
1706 ru_type = "";
1707 sprintf(fmtbuf5, "%4.4X: %s: %s %s %-6.6s %s\n", devnum, tag, fmtbuf, fmtbuf2, fmtbuf3, ru_type);
1708 logmsg(fmtbuf5);
1709 }
1710
make_sna_requests2(COMMADPT * ca)1711 static void make_sna_requests2 (COMMADPT *ca) {
1712 BYTE *respbuf;
1713 BYTE *ru_ptr;
1714 int ru_size;
1715 void *eleptr;
1716 int bufp = 0;
1717 while (ca->inpbufl > 0) {
1718 eleptr = get_bufpool(&ca->freeq);
1719 if (!eleptr) {
1720 logmsg("no buffers trying to send SNA request2\n");
1721 return;
1722 }
1723 respbuf = SIZEOF_INT_P + (BYTE*)eleptr;
1724
1725 /* first do the ten-byte FID1 TH */
1726 respbuf[0] = 0x1C;
1727 respbuf[1] = 0x00;
1728 respbuf[2] = ca->tso_addr0; // daf
1729 respbuf[3] = ca->tso_addr1;
1730 respbuf[4] = ca->lu_addr0; // oaf
1731 respbuf[5] = ca->lu_addr1; // oaf
1732 respbuf[6] = (unsigned char)(++ca->lu_lu_seqn >> 8) & 0xff;
1733 respbuf[7] = (unsigned char)( ca->lu_lu_seqn ) & 0xff;
1734
1735 /* do RH */
1736 respbuf[10] = 0x00;
1737 if (!bufp) {
1738 respbuf[10] |= 0x02; /* set first in chain */
1739 }
1740 respbuf[11] = 0x90;
1741 respbuf[12] = 0x00;
1742
1743 /* do RU */
1744
1745 // FIXME - max. ru_size should be based on BIND settings
1746 // A true fix would also require code changes to READ CCW processing
1747 // including possibly (gasp) segmenting long PIUs into multiple BTUs
1748 // JW: still not fixed but unitsz is now an external parameter
1749 // to allow easier modification
1750 ru_size = min(ca->unitsz-(BUFPD+10+3),ca->inpbufl);
1751 ru_ptr = &respbuf[13];
1752
1753 if (!ca->bindflag) {
1754 // send as character-coded logon to SSCP
1755 if (ru_size > 0 && (ca->inpbuf[ca->inpbufl-1] == 0x0d || ca->inpbuf[ca->inpbufl-1] == 0x25)) {
1756 ru_size--;
1757 }
1758 if (ru_size > 0 && (ca->inpbuf[ca->inpbufl-1] == 0x0d || ca->inpbuf[ca->inpbufl-1] == 0x25)) {
1759 ru_size--;
1760 }
1761 respbuf[2] = ca->sscp_addr0;
1762 respbuf[3] = ca->sscp_addr1;
1763 respbuf[11] = 0x80;
1764 respbuf[12] = 0x00;
1765 }
1766 memcpy(ru_ptr, &ca->inpbuf[bufp], ru_size);
1767 bufp += ru_size;
1768 ca->inpbufl -= ru_size;
1769 if (!ca->is_3270) {
1770 ca->inpbufl = 0;
1771 }
1772 if (!ca->inpbufl) {
1773 respbuf[10] |= 0x01; /* set last in chain */
1774 if (ca->bindflag) {
1775 respbuf[12] |= 0x20; /* set CD */
1776 }
1777 }
1778
1779 /* set length field in TH */
1780 ru_size += 3; /* for RH */
1781 respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff;
1782 respbuf[9] = (unsigned char)(ru_size ) & 0xff;
1783
1784 put_bufpool(&ca->sendq, eleptr);
1785 } /* end of while (ca->inpbufl > 0) */
1786 }
1787
make_sna_requests3(COMMADPT * ca)1788 static void make_sna_requests3 (COMMADPT *ca) {
1789 BYTE *respbuf;
1790 BYTE *ru_ptr;
1791 int ru_size;
1792 void *eleptr;
1793 if (!ca->telnet_int) return;
1794 eleptr = get_bufpool(&ca->freeq);
1795 if (!eleptr) {
1796 logmsg("no buffers trying to send SNA request3\n");
1797 return;
1798 }
1799 respbuf = SIZEOF_INT_P + (BYTE*)eleptr;
1800
1801 /* first do the ten-byte FID1 TH */
1802 respbuf[0] = 0x1D;
1803 respbuf[1] = 0x00;
1804 respbuf[2] = ca->tso_addr0; // daf
1805 respbuf[3] = ca->tso_addr1;
1806 respbuf[4] = ca->lu_addr0; // oaf
1807 respbuf[5] = ca->lu_addr1; // oaf
1808 respbuf[6] = 0x11;
1809 respbuf[7] = 0x11;
1810
1811 /* do RH */
1812 respbuf[10] = 0x4B;
1813 respbuf[11] = 0x80;
1814 respbuf[12] = 0x00;
1815
1816 /* do RU */
1817 ru_size = 0;
1818 ru_ptr = &respbuf[13];
1819
1820 ru_ptr[ru_size++] = 0xc9; // SIG
1821 ru_ptr[ru_size++] = 0x00;
1822 ru_ptr[ru_size++] = 0x01;
1823
1824 ru_size += 3; /* for RH */
1825 respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff;
1826 respbuf[9] = (unsigned char)(ru_size ) & 0xff;
1827
1828 put_bufpool(&ca->sendq, eleptr);
1829 ca->telnet_int = 0;
1830 }
1831
make_sna_requests4(COMMADPT * ca,int flag,BYTE pu_type)1832 static void make_sna_requests4 (COMMADPT *ca, int flag, BYTE pu_type) {
1833 /* send type flag: 0=REQCONT 1=REQDISCONT */
1834 BYTE *respbuf;
1835 BYTE *ru_ptr;
1836 int ru_size;
1837 U32 stids;
1838 void *eleptr;
1839 eleptr = get_bufpool(&ca->freeq);
1840 if (!eleptr) {
1841 logmsg("no buffers trying to send SNA request4\n");
1842 return;
1843 }
1844 respbuf = SIZEOF_INT_P + (BYTE*)eleptr;
1845
1846 /* first do the ten-byte FID1 TH */
1847 respbuf[0] = 0x1C;
1848 respbuf[1] = 0x00;
1849 respbuf[2] = ca->sscp_addr0; // daf
1850 respbuf[3] = ca->sscp_addr1;
1851 // set oaf
1852 if (flag == 0) {
1853 respbuf[4] = ca->ncp_addr0;
1854 respbuf[5] = ca->ncp_addr1;
1855 make_seq(ca, respbuf);
1856 } else {
1857 respbuf[4] = ca->pu_addr0;
1858 respbuf[5] = ca->pu_addr1;
1859 respbuf[6] = 0x00;
1860 respbuf[7] = 0x01;
1861 }
1862
1863 /* do RH */
1864 respbuf[10] = 0x0b;
1865 respbuf[11] = 0x00;
1866 respbuf[12] = 0x00;
1867
1868 /* do RU */
1869 ru_size = 0;
1870 ru_ptr = &respbuf[13];
1871 if (flag == 0) {
1872 ru_ptr[ru_size++] = 0x01; // REQCONT (REQUEST CONTACT)
1873 ru_ptr[ru_size++] = 0x02;
1874 ru_ptr[ru_size++] = 0x84;
1875
1876 ru_ptr[ru_size++] = (ca->rmtsuba >> 8); // network address of link
1877 ru_ptr[ru_size++] = 0x01;
1878
1879 ru_ptr[ru_size++] = pu_type; // PU type
1880
1881 ru_ptr[ru_size++] = 0x00;
1882
1883 stids = ((ca->idblk << 20) & 0xfff00000) | (ca->idnum & 0x000fffff); // 12 bit IDBLK, 20 bit IDNUM
1884 ru_ptr[ru_size++] = (stids >> 24) &0xff;
1885 ru_ptr[ru_size++] = (stids >> 16) &0xff;
1886 ru_ptr[ru_size++] = (stids >> 8) &0xff;
1887 ru_ptr[ru_size++] = stids &0xff;
1888 } else {
1889 ru_ptr[ru_size++] = 0x01; // REQDISCONT (REQUEST DISCONTACT)
1890 ru_ptr[ru_size++] = 0x02;
1891 ru_ptr[ru_size++] = 0x1B;
1892 ru_ptr[ru_size++] = 0x00;
1893 }
1894 ru_size += 3; /* for RH */
1895 respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff;
1896 respbuf[9] = (unsigned char)(ru_size ) & 0xff;
1897
1898 put_bufpool(&ca->sendq, eleptr);
1899 ca->telnet_int = 0;
1900 }
1901
make_sna_requests5(COMMADPT * ca)1902 static void make_sna_requests5 (COMMADPT *ca) {
1903 BYTE *respbuf;
1904 BYTE *ru_ptr;
1905 int ru_size;
1906 void *eleptr;
1907 eleptr = get_bufpool(&ca->freeq);
1908 if (!eleptr) {
1909 logmsg("no buffers trying to send SNA request5\n");
1910 return;
1911 }
1912 respbuf = SIZEOF_INT_P + (BYTE*)eleptr;
1913
1914 /* first do the ten-byte FID1 TH */
1915 respbuf[0] = 0x1C;
1916 respbuf[1] = 0x00;
1917 respbuf[2] = ca->sscp_addr0; // daf
1918 respbuf[3] = ca->sscp_addr1;
1919 respbuf[4] = ca->ncp_addr0; // oaf
1920 respbuf[5] = ca->ncp_addr1;
1921 // set seq no.
1922 make_seq(ca, respbuf);
1923 /* do RH */
1924 respbuf[10] = 0x0B;
1925 respbuf[11] = 0x00;
1926 respbuf[12] = 0x00;
1927
1928 /* do RU */
1929 ru_size = 0;
1930 ru_ptr = &respbuf[13];
1931
1932 ru_ptr[ru_size++] = 0x01; // INOP
1933 ru_ptr[ru_size++] = 0x02;
1934 ru_ptr[ru_size++] = 0x81;
1935 ru_ptr[ru_size++] = ca->pu_addr0;
1936 ru_ptr[ru_size++] = ca->pu_addr1;
1937 ru_ptr[ru_size++] = 0x01; // format/reason
1938
1939 ru_size += 3; /* for RH */
1940 respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff;
1941 respbuf[9] = (unsigned char)(ru_size ) & 0xff;
1942
1943 put_bufpool(&ca->sendq, eleptr);
1944 }
1945
make_sna_requests(BYTE * requestp,COMMADPT * ca)1946 void make_sna_requests (BYTE * requestp, COMMADPT *ca) {
1947 BYTE *respbuf;
1948 BYTE *ru_ptr;
1949 int ru_size;
1950 void *eleptr;
1951 if (memcmp(&requestp[13], R010201, 3)) return; // we only want to process CONTACT
1952 eleptr = get_bufpool(&ca->freeq);
1953 if (!eleptr) {
1954 logmsg("no buffers trying to send SNA request\n");
1955 return;
1956 }
1957 respbuf = SIZEOF_INT_P + (BYTE*)eleptr;
1958
1959 /* first do the ten-byte FID1 TH */
1960 // respbuf[0] = requestp[0];
1961 // respbuf[1] = requestp[1];
1962 respbuf[0] = 0x1c;
1963 respbuf[1] = 0x00;
1964 respbuf[2] = requestp[4]; // daf
1965 respbuf[3] = requestp[5];
1966 respbuf[4] = requestp[2]; // oaf
1967 respbuf[5] = requestp[3];
1968 make_seq(ca, respbuf);
1969 /* do RH */
1970 respbuf[10] = requestp[10];
1971 respbuf[11] = requestp[11];
1972 respbuf[11] = 0x00;
1973 respbuf[12] = requestp[12];
1974
1975 /* make a CONTACTED RU */
1976 ru_size = 0;
1977 ru_ptr = &respbuf[13];
1978 ru_ptr[ru_size++] = 0x01;
1979 ru_ptr[ru_size++] = 0x02;
1980 ru_ptr[ru_size++] = 0x80;
1981 ru_ptr[ru_size++] = requestp[16];
1982 ru_ptr[ru_size++] = requestp[17];
1983 ru_ptr[ru_size++] = 0x01;
1984
1985 /* set length field in TH */
1986 ru_size += 3; /* for RH */
1987 respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff;
1988 respbuf[9] = (unsigned char)(ru_size ) & 0xff;
1989
1990 put_bufpool(&ca->sendq, eleptr);
1991 }
1992
make_sna_response(BYTE * requestp,COMMADPT * ca)1993 void make_sna_response (BYTE * requestp, COMMADPT *ca) {
1994 BYTE *respbuf;
1995 BYTE *ru_ptr;
1996 int ru_size;
1997 void *eleptr;
1998 BYTE obuf[4096];
1999 BYTE buf[BUFLEN_3270];
2000 int amt;
2001 int i1;
2002
2003 if ((requestp[10] & 0x80) != 0) return; // disregard if this is a resp.
2004 if ((requestp[10] & (unsigned char)0xfc) == 0x00 && requestp[2] == ca->lu_addr0 && requestp[3] == ca->lu_addr1 && ca->sfd > 0) { /* if type=data, and DAF matches up, and socket exists */
2005 amt = (requestp[8] << 8) + requestp[9];
2006 amt -= 3;
2007 if (ca->is_3270) {
2008 memcpy(buf, &requestp[13], amt);
2009 /* Double up any IAC bytes in the data */
2010 amt = double_up_iac (buf, amt);
2011 /* Append telnet EOR marker at end of data */
2012 if ((requestp[10] & 0x01) == 0x01) { /* if last-in-chain is set */
2013 buf[amt++] = IAC;
2014 buf[amt++] = EOR_MARK;
2015 }
2016 /* Send the data to the client */
2017 logdump ("SEND", ca->dev, buf, amt);
2018 write_socket(ca->sfd,buf,amt);
2019 } else {
2020 // convert data portion to ASCII and write to remote user
2021 if (amt > 0) {
2022 memcpy(obuf, &requestp[13], amt);
2023 for (i1=0; i1<amt; i1++) {
2024 obuf[i1] = guest_to_host(obuf[i1]);
2025 }
2026 logdump ("SEND", ca->dev, obuf, amt);
2027 write_socket(ca->sfd,obuf,amt);
2028 }
2029 }
2030 }
2031 if ((requestp[11] & 0xf0) != 0x80) return; // disregard if not DR1 requested
2032
2033 eleptr = get_bufpool(&ca->freeq);
2034 if (!eleptr) {
2035 logmsg("no buffers trying to send SNA response\n");
2036 return;
2037 }
2038 respbuf = SIZEOF_INT_P + (BYTE*)eleptr;
2039
2040 /* first do the ten-byte FID1 TH */
2041 respbuf[0] = requestp[0];
2042 respbuf[1] = requestp[1];
2043 respbuf[2] = requestp[4]; // daf
2044 respbuf[3] = requestp[5];
2045 respbuf[4] = requestp[2]; // oaf
2046 respbuf[5] = requestp[3];
2047 respbuf[6] = requestp[6]; // seq #
2048 respbuf[7] = requestp[7];
2049
2050 /* do RH */
2051 respbuf[10] = requestp[10];
2052 respbuf[10] |= 0x83; // indicate this is a resp.
2053 respbuf[11] = requestp[11];
2054 // respbuf[12] = requestp[12];
2055 respbuf[12] = 0x00;
2056
2057 /* do RU */
2058 ru_size = 0;
2059 ru_ptr = &respbuf[13];
2060 if ((requestp[10] & 0x08) != 0)
2061 ru_ptr[ru_size++] = requestp[13];
2062 if (requestp[13] == 0x11 && requestp[14] == 0x02) { /* ACTPU (NCP)*/
2063 ca->ncp_addr0 = requestp[2];
2064 ca->ncp_addr1 = requestp[3];
2065 // ca->ncp_sscp_seqn = 0;
2066 ru_ptr[ru_size++] = 0x02;
2067 if (requestp[2] == (ca->rmtsuba >> 8)){ /* remote NCP */
2068 memcpy(&ru_ptr[ru_size],ca->rmtncpnm,8); /* load mod name */
2069 ru_size += 8;
2070 ca->ncpb_sscp_seqn = 0;
2071 } else
2072 if (requestp[2] == (ca->locsuba >> 8)){ /* local NCP */
2073 memcpy(&ru_ptr[ru_size],ca->locncpnm,8); /* load mod name */
2074 ru_size += 8;
2075 ca->ncpa_sscp_seqn = 0;
2076 }
2077 }
2078 if (requestp[13] == 0x11 && requestp[14] == 0x01) { /* ACTPU (PU)*/
2079 ru_ptr[ru_size++] = 0x01;
2080 /* save daf as our own net addr */
2081 ca->pu_addr0 = requestp[2];
2082 ca->pu_addr1 = requestp[3];
2083 }
2084 if (requestp[13] == 0x01) { /* 01XXXX Network Services */
2085 ru_ptr[ru_size++] = requestp[14];
2086 ru_ptr[ru_size++] = requestp[15];
2087 }
2088 if (!memcmp(&requestp[13], R010219, 3) && ca->sfd > 0) { /* ANA */
2089 if (!ca->is_3270) {
2090 connect_message(ca->sfd, (requestp[20] << 8) + requestp[21], 0);
2091 }
2092 }
2093 if (requestp[13] == 0x0D) { /* ACTLU */
2094 /* save daf as our own net addr */
2095 ca->lu_addr0 = requestp[2];
2096 ca->lu_addr1 = requestp[3];
2097 /* save oaf as our sscp net addr */
2098 ca->sscp_addr0 = requestp[4];
2099 ca->sscp_addr1 = requestp[5];
2100
2101 ca->lu_sscp_seqn = 0;
2102 ca->bindflag = 0;
2103 }
2104 if (requestp[13] == 0x0E || !memcmp(&requestp[13], R01020F, 3)) { // DACTLU or ABCONN
2105 if (!ca->is_3270) {
2106 connect_message(ca->sfd, 0, 1);
2107 }
2108 ca->hangup = 1;
2109 }
2110 if (requestp[13] == 0x31) { /* BIND */
2111 /* save oaf from BIND request */
2112 ca->tso_addr0 = requestp[4];
2113 ca->tso_addr1 = requestp[5];
2114 ca->lu_lu_seqn = 0;
2115 ca->bindflag = 1;
2116 }
2117 if (requestp[13] == 0x32 && requestp[14] != 0x02) { /* BIND */
2118 ca->bindflag = 0;
2119 }
2120 #if 0
2121 if (requestp[13] == 0x32 && requestp[14] == 0x01 && ca->sfd > 0) { /* UNBIND */
2122 close_socket(ca->sfd);
2123 ca->sfd=-1;
2124 }
2125 #endif
2126
2127 /* set length field in TH */
2128 ru_size += 3; /* for RH */
2129 respbuf[8] = (unsigned char)(ru_size >> 8) & 0xff;
2130 respbuf[9] = (unsigned char)(ru_size ) & 0xff;
2131
2132 put_bufpool(&ca->sendq, eleptr);
2133 }
2134
2135 enum fid_remap {
2136 MAP_FID1_FID2,
2137 MAP_FID2_FID1
2138 };
2139
th_remap(enum fid_remap r,BYTE * thptr,U16 locsuba)2140 static void th_remap(enum fid_remap r, BYTE * thptr, U16 locsuba)
2141 { /* for 3791 support, remaps SNA FID1 <--> FID2 TH headers */
2142 int thmpf;
2143 int thm2;
2144 int thdaf;
2145 int thoaf;
2146 int thsnf;
2147 int len;
2148
2149 if (r == MAP_FID1_FID2)
2150 {
2151 thmpf = thptr[0];
2152 thm2 = thptr[1];
2153 thdaf = (thptr[2] << 8) + thptr[3];
2154 thoaf = (thptr[4] << 8) + thptr[5];
2155 thsnf = (thptr[6] << 8) + thptr[7];
2156 len = (thptr[8] << 8) + thptr[9];
2157 len += 10;
2158 thptr[0] = (len >> 8) & 0xff;
2159 thptr[1] = len & 0xff;
2160 thptr[2] = 0x00;
2161 thptr[3] = 0x00;
2162 thptr[4] = 0x20 | (thmpf & 0x0f);
2163 thptr[5] = thm2;
2164 thptr[6] = thdaf & 0xff;
2165 thptr[7] = thoaf & 0xff;
2166 thptr[8] = (thsnf >> 8) & 0xff;
2167 thptr[9] = thsnf & 0xff;
2168 }
2169 else
2170 { /* map fid2 to fid1 */
2171 len = (thptr[0] << 8) + thptr[1];
2172 thmpf = thptr[4];
2173 thm2 = thptr[5];
2174 thdaf = thptr[6];
2175 thoaf = thptr[7];
2176 thsnf = (thptr[8] << 8) + thptr[9];
2177 thdaf |= locsuba;
2178 thoaf |= 0x0800; /* SSCP subarea = 1 (maxsuba=31) */
2179 len -= 10;
2180 thptr[0] = 0x10 | (thmpf & 0x0f);
2181 thptr[1] = thm2;
2182 thptr[2] = (thdaf >> 8) & 0xff;
2183 thptr[3] = thdaf & 0xff;
2184 thptr[4] = (thoaf >> 8) & 0xff;
2185 thptr[5] = thoaf & 0xff;
2186 thptr[6] = (thsnf >> 8) & 0xff;
2187 thptr[7] = thsnf & 0xff;
2188 thptr[8] = (len >> 8) & 0xff;
2189 thptr[9] = len & 0xff;
2190 }
2191 }
2192
2193 /*-------------------------------------------------------------------*/
2194 /* Execute a Channel Command Word */
2195 /*-------------------------------------------------------------------*/
commadpt_execute_ccw(DEVBLK * dev,BYTE code,BYTE flags,BYTE chained,U16 count,BYTE prevcode,int ccwseq,BYTE * iobuf,BYTE * more,BYTE * unitstat,U16 * residual)2196 static void commadpt_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags,
2197 BYTE chained, U16 count, BYTE prevcode, int ccwseq,
2198 BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual)
2199 {
2200 U32 num; /* Work : Actual CCW transfer count */
2201 BYTE *piudata;
2202 int piusize;
2203 void *eleptr;
2204 int llsize;
2205
2206 UNREFERENCED(flags);
2207 UNREFERENCED(chained);
2208 UNREFERENCED(prevcode);
2209 UNREFERENCED(ccwseq);
2210 *residual = 0;
2211 /*
2212 * Obtain the COMMADPT lock
2213 */
2214 if(dev->ccwtrace)
2215 {
2216 logmsg(_("HHCCA300D %4.4X:CCW Exec - Entry code = %x\n"),dev->devnum,code);
2217 }
2218 obtain_lock(&dev->commadpt->lock);
2219 switch (code) {
2220 /*---------------------------------------------------------------*/
2221 /* BASIC SENSE */
2222 /*---------------------------------------------------------------*/
2223 case 0x04:
2224 dev->commadpt->unack_attn_count = 0;
2225 num=count<dev->numsense?count:dev->numsense;
2226 *more=count<dev->numsense?1:0;
2227 memcpy(iobuf,dev->sense,num);
2228 *residual=count-num;
2229 *unitstat=CSW_CE|CSW_DE;
2230 break;
2231
2232 /*---------------------------------------------------------------*/
2233 /* READ type CCWs */
2234 /*---------------------------------------------------------------*/
2235 case 0x02: /* READ */
2236 dev->commadpt->read_ccw_count++;
2237 dev->commadpt->unack_attn_count = 0;
2238 *more = 0;
2239 make_sna_requests2(dev->commadpt);
2240 make_sna_requests3(dev->commadpt);
2241 eleptr = get_bufpool(&dev->commadpt->sendq);
2242 *residual=count;
2243 if (eleptr) {
2244 piudata = SIZEOF_INT_P + (BYTE*)eleptr;
2245 piusize = (piudata[8] << 8) + piudata[9];
2246 piusize += 10; // for FID1 TH
2247 iobuf[0] = BUFPD;
2248 memcpy (&iobuf[BUFPD], piudata, piusize);
2249 if (dev->commadpt->emu3791) {
2250 llsize = piusize + BUFPD;
2251 iobuf[0] = (llsize >> 8) & 0xff;
2252 iobuf[1] = llsize & 0xff;
2253 th_remap(MAP_FID1_FID2, &iobuf[BUFPD], dev->commadpt->locsuba);
2254 }
2255 *residual=count - (piusize + BUFPD);
2256 logdump("READ", dev, &iobuf[BUFPD], piusize);
2257 if (dev->commadpt->debug_sna)
2258 format_sna(piudata, "RD", dev->devnum);
2259 put_bufpool(&dev->commadpt->freeq, eleptr);
2260 }
2261 *unitstat=CSW_CE|CSW_DE;
2262 #if 0
2263 if (dev->commadpt->sendq) {
2264 *unitstat|=CSW_ATTN;
2265 }
2266 #endif
2267 *unitstat|=CSW_UX;
2268 break;
2269
2270 /*---------------------------------------------------------------*/
2271 /* 3791 WRITE BLOCK */
2272 /*---------------------------------------------------------------*/
2273 case 0x05:
2274 logdump("WRITE BLOCK", dev, iobuf, count);
2275 *residual=0;
2276 *unitstat=CSW_CE|CSW_DE;
2277 break;
2278
2279 /*---------------------------------------------------------------*/
2280 /* WRITE type CCWs */
2281 /*---------------------------------------------------------------*/
2282 case 0x09: /* WRITE BREAK */
2283 case 0x01: /* WRITE */
2284 dev->commadpt->write_ccw_count++;
2285 dev->commadpt->unack_attn_count = 0;
2286 logdump("WRITE", dev, iobuf, count);
2287 if (dev->commadpt->emu3791 && (iobuf[4] & 0xf0) == 0x20)
2288 th_remap(MAP_FID2_FID1, iobuf, dev->commadpt->locsuba);
2289 if ((iobuf[0] & 0xf0) == 0x10) { // if FID1
2290 if (dev->commadpt->debug_sna)
2291 format_sna(iobuf, "WR", dev->devnum);
2292 make_sna_response(iobuf, dev->commadpt);
2293 make_sna_requests(iobuf, dev->commadpt);
2294 }
2295 *residual=0;
2296 *unitstat=CSW_CE|CSW_DE;
2297 #if 0
2298 if (dev->commadpt->sendq) {
2299 *unitstat|=CSW_ATTN;
2300 *unitstat|=CSW_UX|CSW_ATTN;
2301 }
2302 #endif
2303 break;
2304
2305 /*---------------------------------------------------------------*/
2306 /* CCWs to be treated as NOPs */
2307 /*---------------------------------------------------------------*/
2308 case 0x03: /* NOP */
2309 case 0x93: /* RESTART */
2310 case 0x31: /* WS0 */
2311 case 0x51: /* WS1 */
2312 case 0x32: /* RS0 */
2313 case 0x52: /* RS1 */
2314 *residual=count;
2315 *unitstat=CSW_CE|CSW_DE;
2316 break;
2317
2318 default:
2319 /*---------------------------------------------------------------*/
2320 /* INVALID OPERATION */
2321 /*---------------------------------------------------------------*/
2322 /* Set command reject sense byte, and unit check status */
2323 *unitstat=CSW_CE+CSW_DE+CSW_UC;
2324 dev->sense[0]=SENSE_CR;
2325 break;
2326
2327 }
2328 release_lock(&dev->commadpt->lock);
2329 }
2330
2331
2332 /*---------------------------------------------------------------*/
2333 /* DEVICE FUNCTION POINTERS */
2334 /*---------------------------------------------------------------*/
2335
2336 #if defined(OPTION_DYNAMIC_LOAD)
2337 static
2338 #endif
2339 DEVHND com3705_device_hndinfo = {
2340 &commadpt_init_handler, /* Device Initialisation */
2341 &commadpt_execute_ccw, /* Device CCW execute */
2342 &commadpt_close_device, /* Device Close */
2343 &commadpt_query_device, /* Device Query */
2344 NULL, /* Device Start channel pgm */
2345 NULL, /* Device End channel pgm */
2346 NULL, /* Device Resume channel pgm */
2347 NULL, /* Device Suspend channel pgm */
2348 NULL, /* Device Read */
2349 NULL, /* Device Write */
2350 NULL, /* Device Query used */
2351 NULL, /* Device Reserve */
2352 NULL, /* Device Release */
2353 NULL, /* Device Attention */
2354 commadpt_immed_command, /* Immediate CCW Codes */
2355 NULL, /* Signal Adapter Input */
2356 NULL, /* Signal Adapter Output */
2357 NULL, /* Hercules suspend */
2358 NULL /* Hercules resume */
2359 };
2360
2361
2362 /* Libtool static name colision resolution */
2363 /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
2364 #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
2365 #define hdl_ddev hdt3705_LTX_hdl_ddev
2366 #define hdl_depc hdt3705_LTX_hdl_depc
2367 #define hdl_reso hdt3705_LTX_hdl_reso
2368 #define hdl_init hdt3705_LTX_hdl_init
2369 #define hdl_fini hdt3705_LTX_hdl_fini
2370 #endif
2371
2372
2373 #if defined(OPTION_DYNAMIC_LOAD)
2374 HDL_DEPENDENCY_SECTION;
2375 {
2376 HDL_DEPENDENCY(HERCULES);
2377 HDL_DEPENDENCY(DEVBLK);
2378 HDL_DEPENDENCY(SYSBLK);
2379 }
2380 END_DEPENDENCY_SECTION;
2381
2382
2383 #if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
2384 #undef sysblk
2385 HDL_RESOLVER_SECTION;
2386 {
2387 HDL_RESOLVE_PTRVAR( psysblk, sysblk );
2388 }
2389 END_RESOLVER_SECTION;
2390 #endif
2391
2392
2393 HDL_DEVICE_SECTION;
2394 {
2395 HDL_DEVICE(3705, com3705_device_hndinfo );
2396 }
2397 END_DEVICE_SECTION;
2398 #endif
2399