1 /*
2  * Copyright (c) 2007-2013 Michael Mondy
3  * Copyright (c) 2012-2016 Harry Reed
4  * Copyright (c) 2013-2016 Charles Anthony
5  * Copyright (c) 2016 Michal Tomek
6  * Copyright (c) 2021 The DPS8M Development Team
7  *
8  * All rights reserved.
9  *
10  * This software is made available under the terms of the ICU
11  * License, version 1.8.1 or later.  For more details, see the
12  * LICENSE.md file at the top-level directory of this distribution.
13  */
14 
15 #include <uv.h>
16 #include "libtelnet.h"
17 
18 #define encodeline(fnp,line) ((fnp) * MAX_LINES + (line))
19 #define decodefnp(coded) ((coded) / MAX_LINES)
20 #define decodeline(coded) ((coded) % MAX_LINES)
21 #define noassoc -1
22 
23 extern UNIT fnp_unit [N_FNP_UNITS_MAX];
24 extern DEVICE fnp_dev;
25 
26 #define MAX_LINES  96  /*  max number of FNP lines - hardware  */
27 
28 //
29 // MState_t state of an FNP
30 //
31 
32 // memset(0) sets service to serivce_undefined (0)
33 enum service_types {service_undefined = 0, service_login, service_3270, service_autocall, service_slave};
34 
35 typedef struct t_MState
36   {
37     t_bool accept_calls;
38     // 60132445 FEP Coupler Spec Nov77 - Unknown.pdf
39     // pg 59 (sheet 56):
40     //   bit       0: CS BAR
41     //             1: BT INH
42     //        2 -  7: RFU
43     //        8 - 15: Special L6 Intpr Level
44     word16 configRegA;
45     struct t_line
46       {
47         // From the CMF database
48         enum service_types service;
49 
50         // libuv hook
51         // For non-multiplexed lines, the connection to the remote is stored here;
52         // For multiplexed lines (3270), the connection to the currenty selected station is stored here. Used by wtx.
53         uv_tcp_t * line_client;
54 
55         // libtelnet hook
56         bool was_CR;
57 
58         // State as set by FNP commands
59         t_bool listen;
60         uint inputBufferSize;
61         uint ctrlStrIdx;
62         t_bool breakAll;
63         t_bool handleQuit;
64         t_bool fullDuplex;
65         t_bool echoPlex;    // echoes all characters types on the terminal
66         t_bool crecho;      // echos a CR when a LF is typed
67         t_bool lfecho;      // echos and inserts  a LF in the users input stream when a CR is typed
68         t_bool tabecho;     // echos the appropriate number of spaces when a TAB is typed
69         t_bool replay;
70         t_bool polite;
71         t_bool prefixnl;
72         t_bool eight_bit_out;
73         t_bool eight_bit_in;
74         t_bool odd_parity;
75         t_bool output_flow_control;
76         t_bool input_flow_control;
77         uint block_xfer_in_frame_sz, block_xfer_out_frame_sz;
78         uint delay_table [6];
79 #define FC_STR_SZ 4
80         uint inputSuspendLen;
81         unsigned char inputSuspendStr [4];
82         uint inputResumeLen;
83         unsigned char inputResumeStr [4];
84         uint outputSuspendLen;
85         unsigned char outputSuspendStr [4];
86         uint outputResumeLen;
87         unsigned char outputResumeStr [4];
88         uint frame_begin;
89         uint frame_end;
90 
91         // Echonego
92         bool echnego_break_table [256];
93         word18 echnego_sync_ctr; // Sent by MCS
94         word18 echnego_screen_left;
95         uint echnego_unechoed_cnt;
96         bool echnego_on;
97         bool echnego_synced;
98 
99         uint sync_msg_size;
100         // Pending requests
101         bool line_break;
102 #ifdef FNPDBG
103 # define SEND_OUTPUT_DELAY 100
104 #else
105 # define SEND_OUTPUT_DELAY 2
106 #endif
107         uint send_output;
108         bool accept_new_terminal;
109 #ifdef DISC_DELAY
110         uint line_disconnected;
111 #else
112         bool line_disconnected;
113 #endif
114         bool ack_echnego_init;
115         bool ack_echnego_stop;
116         bool acu_dial_failure;
117         bool sendLineStatus;
118         bool wru_timeout;
119         uint accept_input; // If non-zero, the number of centiseconds until
120                           // an accept_input message should be sent; this is
121                           // deal with 'reject_request' retries.
122         // The 3270 controller always uses ACCEPT_INPUT
123         bool force_accept_input;
124 
125         bool waitForMbxDone; // If set, the line has sent input to the CS,
126                              // but the CS has not completed the mbx transaction;
127                              // in order to prevent input data reordering, serialize
128                              // the commands by waiting for this to clear before
129                              // sending the next input.
130         bool input_reply_pending;
131         // Part of 'accept_input'
132         bool input_break;
133 
134         // Buffer being assembled for sending to Multics
135         unsigned char buffer[1024];   // line buffer for initial device selection and line discipline
136         uint nPos;           // position where *next* user input is to be stored
137 
138         // Incoming data from the connection
139         unsigned char * inBuffer;
140         uint inSize; // Number of bytes in inBuffer
141         uint inUsed; // Number of consumed bytes in buffer
142 
143 
144         // Dialout hooks
145         uv_connect_t doConnect;
146 
147         // Slave hooks
148         uv_tcp_t server;
149         int port;
150 
151 #ifdef TUN
152         // TUN hook
153         bool is_tun;
154         int tun_fd;
155         bool in_frame;
156         uint8_t frame [2+1500];
157         uint frameLen;
158 #endif
159 
160         word9 lineType;
161         word36 lineStatus0, lineStatus1;
162         bool sendEOT;
163       } line [MAX_LINES];
164   } t_MState;
165 
166 // for now, one controller
167 
168 #define IBM3270_CONTROLLERS_MAX 1
169 #define IBM3270_STATIONS_MAX 32
170 
171 struct ibm3270ctlr_s
172   {
173     bool configured;
174     uint fnpno;
175     uint lineno;
176     // polling and selection addresses
177 
178     unsigned char pollCtlrChar;
179     unsigned char pollDevChar;
180     unsigned char selCtlrChar;
181     unsigned char selDevChar;
182     bool sending_stn_in_buffer;
183     uint stn_no;
184     struct station_s
185       {
186         uv_tcp_t * client;
187         bool EORReceived;
188         bool hdr_sent;
189         unsigned char * stn_in_buffer;
190         uint stn_in_size; // Number of bytes in inBuffer
191         uint stn_in_used;
192         //uint stn_in_used; // Number of consumed bytes in buffer
193       } stations [IBM3270_STATIONS_MAX];
194     // Although this is nominally a per/station event, Multics will not
195     // resume polling until after the write is complete, so only
196     // one event would be pending at any time; moving it out of the
197     // 'stations' structure makes it easier for the emulator event
198     // loops to see.
199     bool write_complete;
200   };
201 
202 #define MAX_DEV_NAME_LEN 64
203 
204 // Indexed by sim unit number
205 struct fnpUnitData_s
206   {
207     char device_name [MAX_DEV_NAME_LEN];
208     word24 mailboxAddress;
209     bool fnpIsRunning;
210     bool fnpMBXinUse [4];  // 4 FNP submailboxes
211     bool lineWaiting [4]; // If set, fnpMBXlineno is waiting for the mailbox to be marked clear.
212     int fnpMBXlineno [4]; // Which HSLA line is using the mbx
213     char ipcName [MAX_DEV_NAME_LEN];
214 
215     t_MState MState;
216   };
217 
218 typedef struct s_fnpData
219   {
220     struct fnpUnitData_s fnpUnitData [N_FNP_UNITS_MAX];
221     struct ibm3270ctlr_s ibm3270ctlr [IBM3270_CONTROLLERS_MAX];
222     char * telnet_address;
223     int telnet_port;
224     int telnet3270_port;
225     uv_loop_t * loop;
226     uv_tcp_t du_server;
227     bool du_server_inited;
228     uv_tcp_t du3270_server;
229     bool du3270_server_inited;
230     int du3270_poll;
231   } t_fnpData;
232 
233 extern t_fnpData fnpData;
234 
235 // dn355_mailbox.incl.pl1
236 //   input_sub_mbx
237 //       pad1:8, line_number:10, n_free_buffers:18
238 //       n_chars:18, op_code:9, io_cmd:9
239 //       n_buffers
240 //       { abs_addr:24, tally:12 } [24]
241 //       command_data
242 
243 
244 //
245 // The FNP communicates with Multics with in-memory mailboxes
246 //
247 
248 struct dn355_submailbox
249   {
250     word36 word1; // dn355_no; is_hsla; la_no; slot_no
251     word36 word2; // cmd_data_len; op_code; io_cmd
252     word36 command_data [3];
253     word36 word6; // data_addr, word_cnt;
254     word36 pad3 [2];
255   };
256 
257 struct fnp_submailbox // 28 words
258   {
259                                                                  // AN85
260     word36 word1; // dn355_no; is_hsla; la_no; slot_no    // 0      word0
261     word36 word2; // cmd_data_len; op_code; io_cmd        // 1      word1
262     word36 mystery [26];                                         // word2...
263   };
264 
265 struct input_sub_mbx
266   {
267     word36 word1; // dn355_no; is_hsla; la_no; slot_no    // 0      word0
268     word36 word2; // cmd_data_len; op_code; io_cmd        // 1      word1
269     word36 n_buffers;
270     word36 dcws [24];
271     word36 command_data;
272   };
273 
274 struct mailbox
275   {
276     word36 dia_pcw;
277     word36 mailbox_requests;
278     word36 term_inpt_mpx_wd;
279     word36 last_mbx_req_count;
280     word36 num_in_use;
281     word36 mbx_used_flags;
282     word36 crash_data [2];
283     struct dn355_submailbox dn355_sub_mbxes [8];
284     struct fnp_submailbox fnp_sub_mbxes [4];
285   };
286 
287 #define MAILBOX_WORDS       (sizeof (struct mailbox) / sizeof (word36))
288 
289 #define DIA_PCW                     (offsetof (struct mailbox, dia_pcw) / sizeof (word36))
290 #define TERM_INPT_MPX_WD        (offsetof (struct mailbox, term_inpt_mpx_wd) / sizeof (word36))
291 #define CRASH_DATA              (offsetof (struct mailbox, crash_data) / sizeof (word36))
292 #define DN355_SUB_MBXES         (offsetof (struct mailbox, dn355_sub_mbxes) / sizeof (word36))
293 #define FNP_SUB_MBXES           (offsetof (struct mailbox, fnp_sub_mbxes) / sizeof (word36))
294 
295 
296 #define FNP_SUB_MBX_SIZE        (sizeof (struct fnp_submailbox) / sizeof (word36))
297 #define DN355_SUB_MBX_SIZE      (sizeof (struct dn355_submailbox) / sizeof (word36))
298 
299 #define WORD1                   0
300 #define WORD2                   1
301 #define COMMAND_DATA            2
302 #define MYSTERY                 2
303 #define WORD6                   5
304 #define N_BUFFERS               2
305 #define DCWS                    3
306 #define N_DCWS                  24
307 #define INP_COMMAND_DATA        27
308 
309 extern const unsigned char a2e [256];
310 extern const unsigned char e2a [256];
311 #define ADDR_MAP_ENTRIES 32
312 // map station number to selDevChar
313 // addr_map [stn_no] == selDevChar
314 extern const unsigned char addr_map [ADDR_MAP_ENTRIES];
315 
316 #define N_FW_ENTRIES 1024
317 extern int n_fw_entries;
318 struct fw_entry_s
319   {
320     uint line_0, line_1; // range of lines
321     uint32_t ipaddr;
322     uint cidr;
323     uint32_t cidr_mask;
324     bool accept;
325   };
326 extern struct fw_entry_s fw_entries [N_FW_ENTRIES];
327 
328 void fnpInit(void);
329 int lookupFnpsIomUnitNumber (int fnpUnitNum);
330 int lookupFnpLink (int fnpUnitNum);
331 void fnpProcessEvent (void);
332 t_stat diaCommand (int fnpUnitNum, char *arg3);
333 void fnpToCpuQueueMsg (int fnpUnitNum, char * msg);
334 iom_cmd_rc_t fnp_iom_cmd (uint iomUnitIdx, uint chan);
335 t_stat set_fnp_server_port (int32 arg, const char * buf);
336 t_stat set_fnp_server_address (int32 arg, const char * buf);
337 t_stat set_fnp_3270_server_port (int32 arg, const char * buf);
338 t_stat fnp_start (UNUSED int32 arg, UNUSED const char * buf);
339 void fnpConnectPrompt (uv_tcp_t * client);
340 void fnp3270ConnectPrompt (uv_tcp_t * client);
341 void processUserInput (uv_tcp_t * client, unsigned char * buf, ssize_t nread);
342 void processLineInput (uv_tcp_t * client, unsigned char * buf, ssize_t nread);
343 void fnpRecvEOR (uv_tcp_t * client);
344 void process3270Input (uv_tcp_t * client, unsigned char * buf, ssize_t nread);
345 void set_3270_write_complete (uv_tcp_t * client);
346 void startFNPListener (void);
347 void setTIMW (uint iom_unit_idx, uint chan, word24 mailboxAddress, int mbx);
348 #ifdef SCUMEM
349 uint get_scu_unit_idx_iom (uint fnp_unit_idx, word24 addr, word24 * offset);
350 #endif
351