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