This source file includes following definitions.
- setTIMW
- fnpInit
- fnpExit
- fnpReset
- findMbx
- notifyCS
- fnp_rcd_ack_echnego_init
- fnp_rcd_ack_echnego_stop
- fnp_rcd_line_disconnected
- fnp_rcd_input_in_mailbox
- fnp_rcd_line_status
- fnp_rcd_accept_input
- fnp_rcd_line_break
- fnp_rcd_send_output
- fnp_rcd_acu_dial_failure
- fnp_rcd_accept_new_terminal
- fnp_rcd_wru_timeout
- processInputCharacter
- fnpRecvEOR
- fnpProcessBuffer
- fnpProcessBuffers
- set_3270_write_complete
- send_3270_msg
- send_stn_in_buffer
- fnp_process_3270_event
- fnpProcessEvent
- fnpShowNUnits
- fnpSetNUnits
- fnpShowIPCname
- fnpSetIPCname
- fnpShowService
- fnpSetService
- fnpShowConfig
- parse_line
- parse_ipaddr
- fnpSetFW
- fnpShowFW
- fnpShowStatus
- fnp_show_device_name
- fnp_set_device_name
- fnpSetConfig
- set_fnp_server_port
- set_fnp_server_address
- set_fnp_3270_server_port
- fnp_start
- fnpConnectPrompt
- fnp3270Msg
- fnp3270ConnectPrompt
- processLineInput
- process3270Input
- reset_line
- processUserInput
- startFNPListener
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 #define ASSUME0 0
84
85 #include <stdio.h>
86 #include <ctype.h>
87 #include <limits.h>
88
89 #include "dps8.h"
90 #include "dps8_sys.h"
91 #include "dps8_iom.h"
92 #include "dps8_cable.h"
93 #include "dps8_cpu.h"
94 #include "dps8_scu.h"
95 #include "dps8_faults.h"
96 #include "dps8_fnp2.h"
97 #include "fnptelnet.h"
98 #include "fnpuv.h"
99 #include "dps8_utils.h"
100
101
102
103
104 #define FNP_MAX_PENDING_INPUT (16U * 1024U * 1024U)
105
106 #include "../simh/sim_defs.h"
107 #include "../simh/sim_tmxr.h"
108
109 #if !defined(CROSS_MINGW64) && !defined(CROSS_MINGW32)
110 # include <regex.h>
111 #endif
112
113 #if defined(FREE)
114 # undef FREE
115 #endif
116 #define FREE(p) do \
117 { \
118 free((p)); \
119 (p) = NULL; \
120 } while(0)
121
122 #define DBG_CTR 1
123
124 #if defined(THREADZ) || defined(LOCKLESS)
125 # include "threadz.h"
126 #endif
127
128 static t_stat fnpShowConfig (FILE *st, UNIT *uptr, int val, const void *desc);
129 static t_stat fnpSetConfig (UNIT * uptr, int value, const char * cptr, void * desc);
130 static t_stat fnpShowStatus (FILE *st, UNIT *uptr, int val, const void *desc);
131 static t_stat fnpShowNUnits (FILE *st, UNIT *uptr, int val, const void *desc);
132 static t_stat fnpSetNUnits (UNIT * uptr, int32 value, const char * cptr, void * desc);
133 static t_stat fnpShowIPCname (FILE *st, UNIT *uptr, int val, const void *desc);
134 static t_stat fnpSetIPCname (UNIT * uptr, int32 value, const char * cptr, void * desc);
135 static t_stat fnpShowService (FILE *st, UNIT *uptr, int val, const void *desc);
136 static t_stat fnpSetService (UNIT * uptr, int32 value, const char * cptr, void * desc);
137 static t_stat fnpShowFW (FILE *st, UNIT *uptr, int val, const void *desc);
138 static t_stat fnpSetFW (UNIT * uptr, int32 value, const char * cptr, void * desc);
139 static t_stat fnp_show_device_name (UNUSED FILE * st, UNIT * uptr,
140 UNUSED int val, UNUSED const void * desc);
141 static t_stat fnp_set_device_name (UNIT * uptr, UNUSED int32 value,
142 const char * cptr, UNUSED void * desc);
143
144 static int findMbx (uint fnpUnitIdx);
145
146 #define N_FNP_UNITS 1
147
148 UNIT fnp_unit [N_FNP_UNITS_MAX] = {
149 #if defined(NO_C_ELLIPSIS)
150 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
151 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
152 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
153 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
154 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
155 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
156 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
157 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
158 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
159 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
160 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
161 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
162 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
163 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
164 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL },
165 { UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL }
166 #else
167 [0 ... N_FNP_UNITS_MAX - 1] = {
168 UDATA (NULL, UNIT_DISABLE | UNIT_IDLE, 0), 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL
169 }
170 #endif
171 };
172
173 static DEBTAB fnpDT [] =
174 {
175 { "TRACE", DBG_TRACE, NULL },
176 { "NOTIFY", DBG_NOTIFY, NULL },
177 { "INFO", DBG_INFO, NULL },
178 { "ERR", DBG_ERR, NULL },
179 { "WARN", DBG_WARN, NULL },
180 { "DEBUG", DBG_DEBUG, NULL },
181 { "ALL", DBG_ALL, NULL },
182 { NULL, 0, NULL }
183 };
184
185 static MTAB fnpMod [] =
186 {
187 {
188 MTAB_unitonly_value,
189 0,
190 "CONFIG",
191 "CONFIG",
192 fnpSetConfig,
193 fnpShowConfig,
194 NULL,
195 NULL
196 },
197
198 {
199 MTAB_unitonly_value,
200 0,
201 "STATUS",
202 "STATUS",
203 NULL,
204 fnpShowStatus,
205 NULL,
206 NULL
207 },
208
209 {
210 MTAB_dev_value,
211 0,
212 "NUNITS",
213 "NUNITS",
214 fnpSetNUnits,
215 fnpShowNUnits,
216 "Number of FNP units in the system",
217 NULL
218 },
219 {
220 MTAB_unit_valr_nouc,
221 0,
222 "IPC_NAME",
223 "IPC_NAME",
224 fnpSetIPCname,
225 fnpShowIPCname,
226 "Set the device IPC name",
227 NULL
228 },
229 {
230 MTAB_unit_valr_nouc,
231 0,
232 "SERVICE",
233 "SERVICE",
234 fnpSetService,
235 fnpShowService,
236 "Set the device IPC name",
237 NULL
238 },
239
240 {
241 MTAB_dev_valr_noshow,
242 0,
243 "FW",
244 "FW",
245 fnpSetFW,
246 fnpShowFW,
247 "Edit firewall",
248 NULL
249 },
250 {
251 MTAB_XTD | MTAB_VUN | \
252 MTAB_VALR | MTAB_NC,
253 0,
254 "NAME",
255 "NAME",
256 fnp_set_device_name,
257 fnp_show_device_name,
258 "Set the device name",
259 NULL
260 },
261 MTAB_eol
262 };
263
264 #define FNP_UNIT_IDX(uptr) ((uptr) - fnp_unit)
265
266 static t_stat fnpReset (DEVICE * dptr);
267
268 DEVICE fnp_dev = {
269 "FNP",
270 fnp_unit,
271 NULL,
272 fnpMod,
273 N_FNP_UNITS,
274 10,
275 31,
276 1,
277 8,
278 9,
279 NULL,
280 NULL,
281 fnpReset,
282 NULL,
283 NULL,
284 NULL,
285 NULL,
286 DEV_DEBUG,
287 0,
288 fnpDT,
289 NULL,
290 NULL,
291 NULL,
292 NULL,
293 NULL,
294 NULL,
295 NULL
296 };
297
298 t_fnpData fnpData;
299
300 #define l_putbits36_1 putbits36_1
301 #define l_putbits36_3 putbits36_3
302 #define l_putbits36_6 putbits36_6
303 #define l_putbits36_9 putbits36_9
304 #define l_putbits36_12 putbits36_12
305 #define l_putbits36_18 putbits36_18
306
307 void setTIMW (uint iom_unit_idx, uint chan, word24 mailboxAddress, int mbx)
308 {
309 word24 timwAddress = mailboxAddress + TERM_INPT_MPX_WD;
310 word36 data;
311 iom_direct_data_service (iom_unit_idx, chan, timwAddress, & data, direct_read_clear);
312 l_putbits36_1 (& data, (uint) mbx, 1);
313 iom_direct_data_service (iom_unit_idx, chan, timwAddress, & data, direct_store);
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331 void fnpInit(void)
332 {
333
334 (void)memset(& fnpData, 0, sizeof(fnpData));
335 fnpData.telnet_address = strdup("0.0.0.0");
336 if (!fnpData.telnet_address)
337 {
338 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
339 __func__, __FILE__, __LINE__);
340 #if defined(USE_BACKTRACE)
341 # if defined(SIGUSR2)
342 (void)raise(SIGUSR2);
343
344 # endif
345 #endif
346 abort();
347 }
348 fnpData.telnet_port = 6180;
349 fnpData.telnet3270_port = 3270;
350 fnpTelnetInit ();
351 fnp3270Init ();
352 }
353
354 void fnpExit (void) {
355 fnpuvExit ();
356
357
358 for (uint fnpno = 0; fnpno < N_FNP_UNITS_MAX; fnpno ++)
359 for (uint lineno = 0; lineno < MAX_LINES; lineno ++)
360 {
361 struct t_line * linep = &fnpData.fnpUnitData[fnpno].MState.line[lineno];
362 FREE (linep->inBuffer);
363 linep->inSize = linep->inUsed = 0;
364 #if defined(TUN)
365 if (linep->tun_fd > 0)
366 {
367 (void)close (linep->tun_fd);
368 linep->tun_fd = 0;
369 }
370 #endif
371 }
372 for (uint station = 0; station < IBM3270_STATIONS_MAX; station ++)
373 {
374 struct station_s * stn = &fnpData.ibm3270ctlr[0].stations[station];
375 FREE (stn->stn_in_buffer);
376 stn->stn_in_size = stn->stn_in_used = 0;
377 }
378 if (fnpData.telnet_address) {
379 FREE (fnpData.telnet_address);
380 fnpData.telnet_address = NULL;
381 }
382 }
383
384 static t_stat fnpReset (UNUSED DEVICE * dptr)
385 {
386
387
388
389
390
391
392 return SCPE_OK;
393 }
394
395
396
397
398
399 static int findMbx (uint fnpUnitIdx)
400 {
401 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnpUnitIdx];
402 for (uint i = 0; i < 4; i ++)
403 if (! fudp -> fnpMBXinUse [i])
404 return (int) i;
405 return -1;
406 }
407
408 static void notifyCS (uint mbx, int fnp_unit_idx, int lineno)
409 {
410 #if defined(TESTING)
411 cpu_state_t * cpup = _cpup;
412 #endif
413 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
414 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
415
416 uint ctlr_port_num = 0;
417 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
418 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
419
420 word36 data = 0;
421 l_putbits36_3 (& data, 0, (word3) fnp_unit_idx);
422 l_putbits36_1 (& data, 8, 1);
423 l_putbits36_3 (& data, 9, 0);
424 l_putbits36_6 (& data, 12, (word6) lineno);
425 l_putbits36_18 (& data, 18, 256);
426 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD1, & data, direct_store);
427
428 fudp->fnpMBXinUse [mbx] = true;
429
430 setTIMW (iom_unit_idx, chan_num, fudp->mailboxAddress, (int)(mbx + 8));
431
432 fudp->lineWaiting [mbx] = true;
433 fudp->fnpMBXlineno [mbx] = lineno;
434 struct t_line * linep = & fudp->MState.line[lineno];
435 linep->waitForMbxDone = true;
436
437 sim_debug (DBG_TRACE, & fnp_dev, "[%d]notifyCS %d %d\r\n", lineno, mbx, chan_num);
438 }
439
440 static void fnp_rcd_ack_echnego_init (uint mbx, int fnp_unit_idx, int lineno)
441 {
442 #if defined(TESTING)
443 cpu_state_t * cpup = _cpup;
444 sim_debug (DBG_TRACE, & fnp_dev, "[%d]rcd ack_echnego_init\r\n", lineno);
445 #endif
446 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
447 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
448
449 uint ctlr_port_num = 0;
450 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
451 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
452
453 word36 data = 0;
454 l_putbits36_9 (& data, 9, 2);
455 l_putbits36_9 (& data, 18, 70);
456 l_putbits36_9 (& data, 27, 1);
457 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
458
459 notifyCS (mbx, fnp_unit_idx, lineno);
460 }
461
462 static void fnp_rcd_ack_echnego_stop (uint mbx, int fnp_unit_idx, int lineno)
463 {
464 #if defined(TESTING)
465 cpu_state_t * cpup = _cpup;
466 sim_debug (DBG_TRACE, & fnp_dev, "[%d]rcd ack_echnego_stop\r\n", lineno);
467 #endif
468 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
469 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
470
471 uint ctlr_port_num = 0;
472 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
473 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
474
475 word36 data = 0;
476 l_putbits36_9 (& data, 9, 2);
477 l_putbits36_9 (& data, 18, 71);
478 l_putbits36_9 (& data, 27, 1);
479 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
480
481 notifyCS (mbx, fnp_unit_idx, lineno);
482 }
483
484 static void fnp_rcd_line_disconnected (uint mbx, int fnp_unit_idx, int lineno)
485 {
486 #if defined(TESTING)
487 cpu_state_t * cpup = _cpup;
488 sim_debug (DBG_TRACE, & fnp_dev, "[%d]rcd line_disconnected\r\n", lineno);
489 #endif
490 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
491 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
492
493 uint ctlr_port_num = 0;
494 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
495 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
496
497 word36 data = 0;
498 l_putbits36_9 (& data, 9, 2);
499 l_putbits36_9 (& data, 18, 0101);
500 l_putbits36_9 (& data, 27, 1);
501 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
502
503 notifyCS (mbx, fnp_unit_idx, lineno);
504 }
505
506 static void fnp_rcd_input_in_mailbox (uint mbx, int fnp_unit_idx, int lineno)
507 {
508 #if defined(TESTING)
509 cpu_state_t * cpup = _cpup;
510 sim_debug (DBG_TRACE, & fnp_dev, "[%d]rcd input_in_mailbox\r\n", lineno);
511 #endif
512 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
513 struct t_line * linep = & fudp->MState.line[lineno];
514 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
515
516 uint ctlr_port_num = 0;
517 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
518 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
519
520 uint n_chars = min(linep->nPos, 100);
521
522
523 word36 data = 0;
524 l_putbits36_9 (& data, 9, (word9) n_chars);
525 l_putbits36_9 (& data, 18, 0102);
526 l_putbits36_9 (& data, 27, 1);
527 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558 uint j = 0;
559 for (uint i = 0; i < n_chars; i += 4, j++)
560 {
561 word36 v = 0;
562 if (i < linep->nPos)
563 l_putbits36_9 (& v, 0, linep->buffer [i]);
564 if (i + 1 < linep->nPos)
565 l_putbits36_9 (& v, 9, linep->buffer [i + 1]);
566 if (i + 2 < linep->nPos)
567 l_putbits36_9 (& v, 18, linep->buffer [i + 2]);
568 if (i + 3 < linep->nPos)
569 l_putbits36_9 (& v, 27, linep->buffer [i + 3]);
570 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+MYSTERY+j, & v, direct_store);
571 }
572
573
574
575
576 int output_chain_present = 0;
577
578 data = 0;
579 l_putbits36_1 (& data, 16, (word1) output_chain_present);
580 l_putbits36_1 (& data, 17, linep->input_break ? 1 : 0);
581 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+INP_COMMAND_DATA, & data, direct_store);
582
583
584
585
586
587
588
589
590
591 notifyCS (mbx, fnp_unit_idx, lineno);
592 }
593
594 static void fnp_rcd_line_status (uint mbx, int fnp_unit_idx, int lineno)
595 {
596 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
597 struct t_line * linep = & fudp->MState.line[lineno];
598 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
599
600 uint ctlr_port_num = 0;
601 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
602 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
603
604 word36 data = 0;
605 l_putbits36_9 (& data, 9, 2);
606 l_putbits36_9 (& data, 18, 0124);
607 l_putbits36_9 (& data, 27, 1);
608 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
609
610 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+MYSTERY+0, & linep->lineStatus0, direct_store);
611 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+MYSTERY+1, & linep->lineStatus1, direct_store);
612
613 notifyCS (mbx, fnp_unit_idx, lineno);
614 }
615
616 static void fnp_rcd_accept_input (uint mbx, int fnp_unit_idx, int lineno)
617 {
618 #if defined(TESTING)
619 cpu_state_t * cpup = _cpup;
620 sim_debug (DBG_TRACE, & fnp_dev, "[%d]rcd accept_input\r\n", lineno);
621 #endif
622 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
623 struct t_line * linep = & fudp->MState.line[lineno];
624 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
625
626 uint ctlr_port_num = 0;
627 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
628 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
629
630
631
632 word36 data = 0;
633 l_putbits36_18 (& data, 0, (word18) linep->nPos);
634 l_putbits36_9 (& data, 18, 0112);
635 l_putbits36_9 (& data, 27, 1);
636 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
637
638
639
640
641 data = 1;
642 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+N_BUFFERS, & data, direct_store);
643
644 data = 0;
645 l_putbits36_12 (& data, 24, (word12) linep->nPos);
646 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+DCWS+0, & data, direct_store);
647
648
649
650
651 word1 output_chain_present = 0;
652
653 data = 0;
654 l_putbits36_1 (& data, 16, (word1) output_chain_present);
655 l_putbits36_1 (& data, 17, linep->input_break ? 1 : 0);
656 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+INP_COMMAND_DATA, & data, direct_store);
657
658 fudp -> fnpMBXlineno [mbx] = lineno;
659 notifyCS (mbx, fnp_unit_idx, lineno);
660 }
661
662 static void fnp_rcd_line_break (uint mbx, int fnp_unit_idx, int lineno)
663 {
664 #if defined(TESTING)
665 cpu_state_t * cpup = _cpup;
666 sim_debug (DBG_TRACE, & fnp_dev, "[%d]rcd line_break\r\n", lineno);
667 #endif
668 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
669 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
670
671 uint ctlr_port_num = 0;
672 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
673 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
674
675 word36 data = 0;
676 l_putbits36_9 (& data, 9, 0);
677 l_putbits36_9 (& data, 18, 0113);
678 l_putbits36_9 (& data, 27, 1);
679 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
680
681 notifyCS (mbx, fnp_unit_idx, lineno);
682 }
683
684 static void fnp_rcd_send_output (uint mbx, int fnp_unit_idx, int lineno)
685 {
686 #if defined(TESTING)
687 cpu_state_t * cpup = _cpup;
688 sim_debug (DBG_TRACE, & fnp_dev, "[%d]rcd send_output\r\n", lineno);
689 #endif
690 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
691 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
692
693 uint ctlr_port_num = 0;
694 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
695 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
696
697 word36 data = 0;
698 l_putbits36_9 (& data, 9, 0);
699 l_putbits36_9 (& data, 18, 0105);
700 l_putbits36_9 (& data, 27, 1);
701 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
702
703 notifyCS (mbx, fnp_unit_idx, lineno);
704 }
705
706 static void fnp_rcd_acu_dial_failure (uint mbx, int fnp_unit_idx, int lineno)
707 {
708 #if defined(TESTING)
709 cpu_state_t * cpup = _cpup;
710 sim_debug (DBG_TRACE, & fnp_dev, "[%d]rcd acu_dial_failure\r\n", lineno);
711
712 #endif
713 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
714 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
715
716 uint ctlr_port_num = 0;
717 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
718 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
719
720 word36 data = 0;
721 l_putbits36_9 (& data, 9, 2);
722 l_putbits36_9 (& data, 18, 82);
723 l_putbits36_9 (& data, 27, 1);
724 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
725
726 notifyCS (mbx, fnp_unit_idx, lineno);
727 }
728
729 static void fnp_rcd_accept_new_terminal (uint mbx, int fnp_unit_idx, int lineno)
730 {
731 #if defined(TESTING)
732 cpu_state_t * cpup = _cpup;
733 sim_debug (DBG_TRACE, & fnp_dev, "[%d]rcd accept_new_terminal\r\n", lineno);
734
735 #endif
736 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
737 struct t_line * linep = & fudp->MState.line[lineno];
738 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
739
740 uint ctlr_port_num = 0;
741 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
742 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
743
744 word36 data = 0;
745 l_putbits36_9 (& data, 9, 2);
746 l_putbits36_9 (& data, 18, 64);
747 l_putbits36_9 (& data, 27, 1);
748 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788 data = 0;
789 l_putbits36_9 (& data, 27, linep->lineType);
790 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+MYSTERY+0, & data, direct_store);
791 data = 0;
792 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+MYSTERY+1, & data, direct_store);
793
794 notifyCS (mbx, fnp_unit_idx, lineno);
795 }
796
797 static void fnp_rcd_wru_timeout (uint mbx, int fnp_unit_idx, int lineno)
798 {
799 #if defined(TESTING)
800 cpu_state_t * cpup = _cpup;
801 sim_debug (DBG_TRACE, & fnp_dev, "[%d]rcd wru_timeout\r\n", lineno);
802
803 #endif
804 struct fnpUnitData_s * fudp = & fnpData.fnpUnitData [fnp_unit_idx];
805 word24 fsmbx = fudp->mailboxAddress + FNP_SUB_MBXES + mbx*FNP_SUB_MBX_SIZE;
806
807 uint ctlr_port_num = 0;
808 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
809 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
810
811 word36 data = 0;
812 l_putbits36_9 (& data, 9, 2);
813 l_putbits36_9 (& data, 18, 0114);
814 l_putbits36_9 (& data, 27, 1);
815 iom_direct_data_service (iom_unit_idx, chan_num, fsmbx+WORD2, & data, direct_store);
816
817 notifyCS (mbx, fnp_unit_idx, lineno);
818 }
819
820
821
822
823 static inline bool processInputCharacter (struct t_line * linep, unsigned char kar,
824 UNUSED bool endOfBuffer)
825 {
826 #if defined(TUN)
827 if (!linep->is_tun && !linep->line_client)
828 #else
829 if (! linep->line_client)
830 #endif
831 {
832 sim_warn ("processInputCharacter bad client\r\n");
833 return false;
834 }
835
836
837 if (linep->nPos >= sizeof (linep->buffer) - 1)
838 {
839 linep->accept_input = 1;
840 linep->input_break = false;
841 return true;
842 }
843 #if defined(TUN)
844
845 if (! linep->is_tun)
846 #endif
847 {
848
849 uvClientData * p = linep->line_client->data;
850
851
852
853 if (p && p->telnetp && linep->was_CR && kar == 0)
854 {
855
856 linep->was_CR = false;
857 return false;
858 }
859 linep->was_CR = kar == 015;
860
861 }
862
863
864 if (linep->service == service_login)
865 {
866 if (linep->echoPlex)
867 {
868
869
870
871 if (linep->crecho && kar == '\n')
872 {
873 fnpuv_start_writestr (linep->line_client, (unsigned char *) "\r\n");
874 }
875
876
877 else if (linep->lfecho && kar == '\r')
878 {
879 fnpuv_start_writestr (linep->line_client, (unsigned char *) "\r\n");
880 }
881
882
883 else if (linep->tabecho && kar == '\t')
884 {
885
886 uint nCol = linep->nPos;
887
888 nCol += 10;
889 int nSpaces = 10 - ((int) nCol % 10);
890 for(int i = 0 ; i < nSpaces ; i += 1)
891 fnpuv_start_writestr (linep->line_client, (unsigned char *) " ");
892 }
893
894
895
896 else if (kar == '\022' || kar == '\025' || kar == '\b' ||
897 kar == 127 || kar == '\n' || kar == '\r' ||
898 kar == '\f' || kar == '\003')
899 {
900
901 }
902
903
904 else
905 {
906 unsigned char str [2] = { kar, 0 };
907 fnpuv_start_writestr (linep->line_client, str);
908 }
909 }
910
911
912 if (linep->breakAll)
913 {
914 linep->buffer[linep->nPos ++] = kar;
915 linep->buffer[linep->nPos] = 0;
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936 #if defined(ECHNEGO_DEBUG)
937 sim_printf ("\r\nkar <%c>\r\n", isprint (kar) ? kar : '*');
938 #endif
939
940 if (linep->echnego_on)
941 {
942 if (linep->echnego_break_table[kar])
943 {
944
945 #if defined(ECHNEGO_DEBUG)
946 sim_printf ("break\r\n");
947 #endif
948
949
950
951
952
953
954
955 linep->echnego_on = false;
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976 linep->input_break = false;
977
978
979
980
981
982
983
984
985
986 linep->echnego_unechoed_cnt ++;
987 #if defined(ECHNEGO_DEBUG)
988 sim_printf ("echnego break nPos %d unechoed cnt %d\r\n",
989 linep->nPos, linep->echnego_unechoed_cnt);
990 #endif
991 linep->accept_input = 1;
992 return true;
993 }
994
995 #if defined(ECHNEGO_DEBUG)
996 sim_printf ("echoing '%c'\r\n", kar);
997 #endif
998
999 unsigned char str [2] = { kar, 0 };
1000 fnpuv_start_writestr (linep->line_client, str);
1001
1002
1003
1004
1005
1006
1007
1008
1009 linep->echnego_unechoed_cnt = 0;
1010
1011 if (linep->echnego_screen_left)
1012 linep->echnego_screen_left --;
1013 #if defined(ECHNEGO_DEBUG)
1014 sim_printf ("echnego_screen_left %u\r\n", linep->echnego_screen_left);
1015 #endif
1016
1017 if (linep->echnego_screen_left == 0)
1018 {
1019
1020 #if defined(ECHNEGO_DEBUG)
1021 sim_printf ("end of line\r\n");
1022 #endif
1023
1024
1025
1026
1027
1028
1029
1030 linep->echnego_on = false;
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046 linep->input_break = false;
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057 #if defined(ECHNEGO_DEBUG)
1058 sim_printf ("echnego end of line nPos %d unechoed cnt %d\r\n",
1059 linep->nPos, linep->echnego_unechoed_cnt);
1060 #endif
1061 linep->accept_input = 1;
1062 return true;
1063 }
1064
1065 return true;
1066 }
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076 linep->echnego_unechoed_cnt += linep->nPos;
1077
1078 linep->input_break = true;
1079 linep->accept_input = 1;
1080 #if defined(ECHNEGO_DEBUG)
1081 sim_printf ("break nPos %d unechoed cnt %d\r\n",
1082 linep->nPos, linep->echnego_unechoed_cnt);
1083 #endif
1084 return true;
1085 }
1086
1087 if ((linep-> frame_begin != 0 &&
1088 linep-> frame_begin == kar) ||
1089 (linep-> frame_end != 0 &&
1090 linep-> frame_end == kar))
1091 {
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104 linep->buffer[linep->nPos++] = kar;
1105
1106 uint frsz = linep->block_xfer_in_frame_sz;
1107 while ((size_t) linep->nPos < sizeof (linep->buffer) && linep->nPos < frsz)
1108 linep->buffer[linep->nPos++] = 0;
1109 linep->accept_input = 1;
1110 linep->input_break = true;
1111 return true;
1112
1113 }
1114
1115
1116 if (kar == '\r')
1117 kar = '\n';
1118
1119 switch (kar)
1120 {
1121 case '\n':
1122 case '\r':
1123 case '\f':
1124 {
1125 kar = '\n';
1126 linep->buffer[linep->nPos++] = kar;
1127 linep->buffer[linep->nPos] = 0;
1128 linep->accept_input = 1;
1129 linep->input_break = true;
1130
1131 return true;
1132 }
1133
1134 case 0x03:
1135 {
1136 if (linep->handleQuit)
1137 {
1138 linep->line_break=true;
1139
1140
1141
1142 return true;
1143 }
1144 }
1145 break;
1146
1147 case '\b':
1148 case 127:
1149 {
1150 if (linep->nPos > 0)
1151 {
1152 fnpuv_start_writestr (linep->line_client, (unsigned char *) "\b \b");
1153
1154 linep->nPos -= 1;
1155 linep->buffer[linep->nPos] = 0;
1156 }
1157 else
1158 {
1159
1160 fnpuv_start_writestr (linep->line_client, (unsigned char *) "\a");
1161 }
1162 return false;
1163 }
1164
1165 case 21:
1166 {
1167 linep->nPos = 0;
1168 linep->buffer[linep->nPos] = 0;
1169 fnpuv_start_writestr (linep->line_client, (unsigned char *) "^U\r\n");
1170 return false;
1171 }
1172
1173 case 0x12:
1174 {
1175 fnpuv_start_writestr (linep->line_client, (unsigned char *) "^R\r\n");
1176 fnpuv_start_writestr (linep->line_client, linep->buffer);
1177 return false;
1178 }
1179
1180 default:
1181 break;
1182 }
1183
1184 }
1185
1186
1187 linep->buffer[linep->nPos++] = kar;
1188 linep->buffer[linep->nPos] = 0;
1189
1190
1191
1192 if (
1193
1194 ((linep->service == service_autocall ||
1195 linep->service == service_slave) &&
1196 linep->inUsed >= linep->inSize) ||
1197
1198 (size_t) linep->nPos >= sizeof (linep->buffer) - 1 ||
1199
1200
1201
1202
1203
1204
1205
1206 ((linep->block_xfer_out_frame_sz != 0)
1207 ?
1208
1209 (linep->nPos >= linep->block_xfer_out_frame_sz)
1210 :
1211
1212 (linep->inputBufferSize != 0 && linep->nPos >= linep->inputBufferSize))
1213 )
1214 {
1215 linep->accept_input = 1;
1216 linep->input_break = false;
1217
1218 if (linep->service == service_slave || linep->service == service_autocall)
1219 {
1220 #if defined(TUN)
1221 if (linep->is_tun)
1222 linep->input_break = endOfBuffer;
1223 else
1224 #endif
1225 linep->input_break = true;
1226 }
1227
1228 return true;
1229 }
1230 return false;
1231 }
1232
1233
1234
1235 void fnpRecvEOR (uv_tcp_t * client)
1236 {
1237 if (! client || ! client->data)
1238 {
1239 sim_warn ("fnpRecvEOR bad client data\r\n");
1240 return;
1241 }
1242 uvClientData * p = client->data;
1243
1244
1245
1246 if (!p->assoc || p->read_cb != fnpuv_3270_readcb ||
1247 p->fnpno >= N_FNP_UNITS_MAX || p->lineno >= MAX_LINES ||
1248 p->stationNo >= IBM3270_STATIONS_MAX)
1249 return;
1250 if (fnpData.ibm3270ctlr[ASSUME0].stations[p->stationNo].client != client)
1251 return;
1252 struct t_line * linep = &fnpData.fnpUnitData[p->fnpno].MState.line[p->lineno];
1253 if (linep->service != service_3270)
1254 return;
1255 fnpData.ibm3270ctlr[ASSUME0].stations[p->stationNo].EORReceived = true;
1256 fnpData.ibm3270ctlr[ASSUME0].stations[p->stationNo].hdr_sent = false;
1257 }
1258
1259 static void fnpProcessBuffer (struct t_line * linep)
1260 {
1261
1262 #if defined(TUN)
1263 if ((! linep->is_tun) && ! linep->line_client)
1264 #else
1265 if (! linep->line_client)
1266 #endif
1267 {
1268 if (linep->inBuffer)
1269 FREE (linep->inBuffer);
1270 linep->inBuffer = NULL;
1271 linep->inSize = 0;
1272 linep->inUsed = 0;
1273 return;
1274 }
1275
1276 while (linep->inBuffer && linep->inUsed < linep->inSize)
1277 {
1278
1279
1280
1281 if (linep->nPos >= sizeof (linep->buffer) - 1)
1282 {
1283 linep->accept_input = 1;
1284 linep->input_break = false;
1285 break;
1286 }
1287 unsigned char c = linep->inBuffer [linep->inUsed ++];
1288
1289 bool eob = linep->inUsed >= linep->inSize;
1290 if (eob)
1291 {
1292 FREE (linep->inBuffer);
1293 linep->inBuffer = NULL;
1294 linep->inSize = 0;
1295 linep->inUsed = 0;
1296
1297 if (linep->line_client)
1298 fnpuv_read_start (linep->line_client);
1299 }
1300 if (linep->service == service_3270)
1301 {
1302 linep->buffer[linep->nPos++] = c;
1303 linep->buffer[linep->nPos] = 0;
1304 continue;
1305 }
1306 if (processInputCharacter (linep, c, eob))
1307 break;
1308 }
1309 }
1310
1311 static void fnpProcessBuffers (void)
1312 {
1313 uint numunits = (uint) fnp_dev.numunits;
1314 for (uint fnp_unit_idx = 0; fnp_unit_idx < numunits; fnp_unit_idx ++)
1315 {
1316 if (! fnpData.fnpUnitData[fnp_unit_idx].fnpIsRunning)
1317 continue;
1318 for (uint lineno = 0; lineno < MAX_LINES; lineno ++)
1319 {
1320 struct t_line * linep = & fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno];
1321
1322
1323 if (linep->accept_input)
1324 continue;
1325
1326
1327 if (linep->input_reply_pending || linep->input_in_mailbox_pending)
1328 continue;
1329
1330
1331 if (!linep->inBuffer)
1332 continue;
1333
1334 fnpProcessBuffer (linep);
1335 }
1336 }
1337 }
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363 void set_3270_write_complete (UNUSED uv_tcp_t * client)
1364 {
1365 #if defined(TESTING)
1366 cpu_state_t * cpup = _cpup;
1367 #endif
1368
1369
1370 sim_debug (DBG_TRACE, & fnp_dev, "set_3270_write_complete\r\n");
1371
1372 fnpData.ibm3270ctlr[ASSUME0].write_complete = true;
1373 }
1374
1375 static void send_3270_msg (uint ctlr_no, unsigned char * msg, size_t len, bool brk)
1376 {
1377
1378
1379
1380
1381
1382
1383
1384
1385 uint fnpno = fnpData.ibm3270ctlr[ctlr_no].fnpno;
1386 uint lineno = fnpData.ibm3270ctlr[ctlr_no].lineno;
1387 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
1388 if (linep->nPos >= sizeof (linep->buffer) ||
1389 len > sizeof (linep->buffer) - linep->nPos)
1390 sim_warn ("send_3270_msg overfull linep->buffer; dropping data\r\n");
1391 else
1392 {
1393 memcpy (linep->buffer + linep->nPos, msg, len);
1394 linep->nPos += len;
1395 }
1396
1397
1398
1399
1400
1401
1402
1403 linep->force_accept_input = true;
1404 linep->accept_input = 1;
1405 linep->input_break = brk ? 1 : 0;
1406 }
1407
1408 const unsigned char addr_map [ADDR_MAP_ENTRIES] =
1409 {
1410 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
1411 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1412 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
1413 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f
1414 };
1415
1416 static void send_stn_in_buffer (void)
1417 {
1418 #if defined(TESTING)
1419 cpu_state_t * cpup = _cpup;
1420 sim_debug (DBG_TRACE, & fnp_dev, "fnp2 send_stn_in_buffer\r\n");
1421 #endif
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437 uint fnpno = fnpData.ibm3270ctlr[ASSUME0].fnpno;
1438 uint lineno = fnpData.ibm3270ctlr[ASSUME0].lineno;
1439 if (fnpno >= N_FNP_UNITS_MAX || lineno >= MAX_LINES)
1440 return;
1441 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
1442
1443
1444 if (linep->accept_input)
1445 return;
1446 if (linep->input_reply_pending || linep->input_in_mailbox_pending)
1447 return;
1448
1449 struct ibm3270ctlr_s * ctlrp = & fnpData.ibm3270ctlr[ASSUME0];
1450 if (ctlrp->stn_no >= IBM3270_STATIONS_MAX)
1451 return;
1452 struct station_s * stnp = & fnpData.ibm3270ctlr[ASSUME0].stations[ctlrp->stn_no];
1453 if (stnp->stn_in_used > stnp->stn_in_size ||
1454 (stnp->stn_in_size && !stnp->stn_in_buffer))
1455 return;
1456
1457 uint left = linep->sync_msg_size;
1458 if (left < 4)
1459 return;
1460 if (left > sizeof (linep->buffer))
1461 left = sizeof (linep->buffer);
1462
1463 unsigned char * bufp = linep->buffer;
1464
1465 * bufp ++ = 0x2;
1466 left --;
1467
1468 if (! stnp->hdr_sent)
1469 {
1470 * bufp ++ = addr_map [ASSUME0];
1471 left --;
1472 * bufp ++ = addr_map [ctlrp->stn_no];
1473 left --;
1474 stnp->hdr_sent = true;
1475 }
1476
1477 uint n_to_send = stnp->stn_in_size - stnp->stn_in_used;
1478 if (n_to_send > left - 1)
1479 n_to_send = left - 1;
1480 if (n_to_send)
1481 {
1482 sim_debug (DBG_TRACE, & fnp_dev, "handling in used %u %u\r\n", stnp->stn_in_used, n_to_send);
1483
1484
1485 memcpy (bufp, stnp->stn_in_buffer + stnp->stn_in_used, n_to_send);
1486 bufp += n_to_send;
1487 stnp->stn_in_used += n_to_send;
1488 left -= n_to_send;
1489 }
1490
1491 if (stnp->stn_in_used >= stnp->stn_in_size && left)
1492 {
1493 * bufp ++ = 0x3;
1494 left --;
1495
1496 FREE (stnp->stn_in_buffer);
1497 stnp->stn_in_buffer = NULL;
1498 stnp->stn_in_size = 0;
1499 stnp->stn_in_used = 0;
1500
1501 linep->input_break = 1;
1502 fnpData.ibm3270ctlr[ASSUME0].sending_stn_in_buffer = false;
1503
1504
1505 }
1506 uint sz = (uint) (bufp - linep->buffer);
1507 if (sz)
1508 {
1509 linep->force_accept_input = true;
1510 linep->accept_input = 1;
1511 linep->nPos = sz;
1512 }
1513
1514
1515
1516
1517
1518
1519 }
1520
1521 static void fnp_process_3270_event (void)
1522 {
1523 #if defined(TESTING)
1524 cpu_state_t * cpup = _cpup;
1525 #endif
1526 uint fnpno = fnpData.ibm3270ctlr[ASSUME0].fnpno;
1527 uint lineno = fnpData.ibm3270ctlr[ASSUME0].lineno;
1528 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
1529
1530
1531
1532 if (fnpData.ibm3270ctlr[ASSUME0].sending_stn_in_buffer)
1533 {
1534 send_stn_in_buffer ();
1535 return;
1536 }
1537
1538 if (fnpData.ibm3270ctlr[ASSUME0].write_complete)
1539 {
1540 fnpData.ibm3270ctlr[ASSUME0].write_complete = false;
1541 linep->lineStatus0 = 6llu << 18;
1542 linep->lineStatus1 = 0;
1543 linep->sendLineStatus = true;
1544 }
1545
1546
1547
1548 if (! fnpData.du3270_poll)
1549 return;
1550 fnpData.du3270_poll --;
1551 if (fnpData.du3270_poll)
1552 return;
1553 struct ibm3270ctlr_s * ctlrp = & fnpData.ibm3270ctlr[ASSUME0];
1554
1555 sim_debug (DBG_TRACE, & fnp_dev, "fnp2 3270 poll\r\n");
1556
1557
1558
1559
1560
1561 if (ctlrp->pollDevChar == 127)
1562 {
1563 uint stn_cnt;
1564 for (stn_cnt = 0; stn_cnt < IBM3270_STATIONS_MAX; stn_cnt ++)
1565 {
1566 ctlrp->stn_no = (ctlrp->stn_no + 1) % IBM3270_STATIONS_MAX;
1567 struct station_s * stnp = & fnpData.ibm3270ctlr[ASSUME0].stations[ctlrp->stn_no];
1568 if (! stnp->client)
1569 continue;
1570 if (stnp->EORReceived)
1571 {
1572 stnp->EORReceived = false;
1573 ctlrp->sending_stn_in_buffer = true;
1574 fnpuv3270Poll (false);
1575 break;
1576 }
1577 }
1578 if (stn_cnt >= IBM3270_STATIONS_MAX)
1579 {
1580
1581
1582 unsigned char EOT = 0x37;
1583 send_3270_msg (ASSUME0, & EOT, 1, true);
1584 fnpuv3270Poll (false);
1585 }
1586 }
1587 else
1588 {
1589
1590 sim_debug (DBG_TRACE, & fnp_dev, "fnp2 specific poll\r\n");
1591 }
1592 }
1593
1594
1595
1596
1597
1598 void fnpProcessEvent (void)
1599 {
1600 #if defined(TESTING)
1601 cpu_state_t * cpup = _cpup;
1602 #endif
1603
1604
1605 fnpuvProcessEvent ();
1606
1607
1608
1609
1610 fnpProcessBuffers ();
1611
1612
1613 uint numunits = (uint) fnp_dev.numunits;
1614 for (uint fnp_unit_idx = 0; fnp_unit_idx < numunits; fnp_unit_idx ++)
1615 {
1616 if (! fnpData.fnpUnitData[fnp_unit_idx].fnpIsRunning)
1617 continue;
1618 int mbx = findMbx (fnp_unit_idx);
1619 if (mbx == -1)
1620 continue;
1621 bool need_intr = false;
1622 for (int lineno = 0; lineno < MAX_LINES; lineno ++)
1623 {
1624 struct t_line * linep = & fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno];
1625
1626 #if defined(DISC_DELAY)
1627
1628 if (linep -> line_disconnected > 1)
1629 {
1630
1631 if (linep->inBuffer && linep->inUsed < linep->inSize)
1632 {
1633
1634 linep -> line_disconnected = DISC_DELAY;
1635 }
1636 else
1637 {
1638
1639 -- linep -> line_disconnected;
1640 }
1641 }
1642 #endif
1643
1644
1645 if (linep->waitForMbxDone)
1646 continue;
1647
1648
1649
1650
1651
1652
1653 bool do_send_output = linep->send_output == 1 &&
1654 ! fnpuv_output_backlogged (linep->line_client);
1655
1656 if (linep -> send_output > 1 || do_send_output)
1657 linep->send_output --;
1658
1659 if (do_send_output)
1660 {
1661 fnp_rcd_send_output ((uint)mbx, (int) fnp_unit_idx, lineno);
1662 need_intr = true;
1663 }
1664
1665
1666
1667 else if (linep->acu_dial_failure)
1668 {
1669 fnp_rcd_acu_dial_failure ((uint)mbx, (int) fnp_unit_idx, lineno);
1670 linep->acu_dial_failure = false;
1671 need_intr = true;
1672 }
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682 else if (linep->listen && linep->accept_new_terminal)
1683 {
1684 fnp_rcd_accept_new_terminal ((uint)mbx, (int) fnp_unit_idx, lineno);
1685 linep->accept_new_terminal = false;
1686 need_intr = true;
1687 }
1688
1689
1690
1691 else if (linep -> ack_echnego_init)
1692 {
1693 fnp_rcd_ack_echnego_init ((uint)mbx, (int) fnp_unit_idx, lineno);
1694 linep -> ack_echnego_init = false;
1695 linep -> send_output = SEND_OUTPUT_DELAY;
1696 need_intr = true;
1697 }
1698
1699
1700
1701 else if (linep -> ack_echnego_stop)
1702 {
1703 fnp_rcd_ack_echnego_stop ((uint)mbx, (int) fnp_unit_idx, lineno);
1704 linep -> ack_echnego_stop = false;
1705 linep -> send_output = SEND_OUTPUT_DELAY;
1706 need_intr = true;
1707 }
1708
1709
1710
1711 #if defined(DISC_DELAY)
1712 else if (linep -> line_disconnected == 1)
1713 {
1714 fnp_rcd_line_disconnected ((uint)mbx, (int) fnp_unit_idx, lineno);
1715 linep -> line_disconnected = 0;
1716 linep -> listen = false;
1717 need_intr = true;
1718 }
1719 #else
1720 else if (linep -> line_disconnected)
1721 {
1722 fnp_rcd_line_disconnected ((uint)mbx, (int) fnp_unit_idx, lineno);
1723 linep -> line_disconnected = false;
1724 linep -> listen = false;
1725 need_intr = true;
1726 }
1727 #endif
1728
1729
1730
1731 else if (linep -> wru_timeout)
1732 {
1733 fnp_rcd_wru_timeout ((uint)mbx, (int) fnp_unit_idx, lineno);
1734 linep -> wru_timeout = false;
1735 need_intr = true;
1736 }
1737
1738
1739
1740 else if (linep->accept_input && ! linep->waitForMbxDone)
1741 {
1742
1743
1744 if (linep->input_retry_at_ns)
1745 {
1746 if (!fnpInputRetryDue (linep, uv_hrtime ()))
1747 continue;
1748 linep->input_retry_at_ns = 0;
1749 }
1750 if (linep->accept_input == 1)
1751 {
1752
1753
1754
1755
1756 if (0 && linep->nPos == 0)
1757 {
1758 sim_printf ("dropping nPos of 0");
1759 }
1760 else
1761 {
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790 if (linep->force_accept_input || linep->nPos > 100)
1791 {
1792 linep->input_reply_pending = true;
1793 fnp_rcd_accept_input ((uint)mbx, (int) fnp_unit_idx, lineno);
1794
1795
1796 need_intr = true;
1797 }
1798 else
1799 {
1800
1801
1802
1803 linep->input_in_mailbox_pending = true;
1804 fnp_rcd_input_in_mailbox ((uint)mbx, (int) fnp_unit_idx, lineno);
1805 sim_debug (DBG_TRACE, & fnp_dev, "FNP input_in_mailbox\r\n");
1806
1807 need_intr = true;
1808 }
1809
1810 }
1811 }
1812 linep->accept_input --;
1813 }
1814
1815
1816
1817
1818
1819 else if (linep->line_break)
1820 {
1821 fnp_rcd_line_break ((uint)mbx, (int) fnp_unit_idx, lineno);
1822 linep -> line_break = false;
1823 need_intr = true;
1824 linep -> send_output = SEND_OUTPUT_DELAY;
1825 }
1826
1827 else if (linep->sendLineStatus)
1828 {
1829 linep->sendLineStatus = false;
1830 fnp_rcd_line_status ((uint)mbx, (int) fnp_unit_idx, lineno);
1831 need_intr = true;
1832 }
1833
1834 else
1835 {
1836 continue;
1837 }
1838
1839
1840
1841
1842 mbx = findMbx (fnp_unit_idx);
1843 if (mbx == -1)
1844 break;
1845 }
1846
1847
1848 if (need_intr)
1849 {
1850 uint ctlr_port_num = 0;
1851 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
1852 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
1853 send_general_interrupt (iom_unit_idx, chan_num, imwTerminatePic);
1854 }
1855 }
1856
1857 #if defined(TUN)
1858 fnpTUNProcessEvent ();
1859 #endif
1860 fnp_process_3270_event ();
1861 }
1862
1863 static t_stat fnpShowNUnits (UNUSED FILE * st, UNUSED UNIT * uptr,
1864 UNUSED int val, UNUSED const void * desc)
1865 {
1866 sim_printf("Number of FNP units in system is %d\r\n", fnp_dev . numunits);
1867 return SCPE_OK;
1868 }
1869
1870 static t_stat fnpSetNUnits (UNUSED UNIT * uptr, UNUSED int32 value,
1871 const char * cptr, UNUSED void * desc)
1872 {
1873 if (! cptr)
1874 return SCPE_ARG;
1875 int n = atoi (cptr);
1876 if (n < 1 || n > N_FNP_UNITS_MAX)
1877 return SCPE_ARG;
1878 fnp_dev . numunits = (uint32) n;
1879
1880 return SCPE_OK;
1881 }
1882
1883 static t_stat fnpShowIPCname (UNUSED FILE * st, UNIT * uptr,
1884 UNUSED int val, UNUSED const void * desc)
1885 {
1886 long n = FNP_UNIT_IDX (uptr);
1887 if (n < 0 || n >= N_FNP_UNITS_MAX)
1888 return SCPE_ARG;
1889 sim_printf(" FNP IPC name: %s", fnpData.fnpUnitData [n] . ipcName);
1890 return SCPE_OK;
1891 }
1892
1893 static t_stat fnpSetIPCname (UNIT * uptr, UNUSED int32 value,
1894 UNUSED const char * cptr, UNUSED void * desc)
1895 {
1896 long n = FNP_UNIT_IDX (uptr);
1897 if (n < 0 || n >= N_FNP_UNITS_MAX)
1898 return SCPE_ARG;
1899 if (cptr)
1900 {
1901 strncpy (fnpData.fnpUnitData [n] . ipcName, cptr, MAX_DEV_NAME_LEN - 1);
1902 fnpData.fnpUnitData [n] . ipcName [MAX_DEV_NAME_LEN - 1] = 0;
1903 }
1904 else
1905 fnpData.fnpUnitData [n] . ipcName [0] = 0;
1906 return SCPE_OK;
1907 }
1908
1909 static t_stat fnpShowService (UNUSED FILE * st, UNIT * uptr,
1910 UNUSED int val, UNUSED const void * desc)
1911 {
1912 long devnum = FNP_UNIT_IDX (uptr);
1913 if (devnum < 0 || devnum >= N_FNP_UNITS_MAX)
1914 return SCPE_ARG;
1915 for (uint linenum = 0; linenum < MAX_LINES; linenum ++)
1916 {
1917 if (linenum == 0)
1918 sim_printf("\t");
1919 else
1920 sim_printf("\t\t");
1921 enum service_types st = fnpData.fnpUnitData[devnum].MState.line[linenum].service;
1922 switch (st)
1923 {
1924 case service_undefined:
1925 sim_printf("%c.%03d: undefined", (char)('a' + (int) devnum), linenum);
1926 break;
1927 case service_login:
1928 sim_printf("%c.%03d: login", (char)('a' + (int) devnum), linenum);
1929 break;
1930 case service_autocall:
1931 sim_printf("%c.%03d: autocall", (char)('a' + (int) devnum), linenum);
1932 break;
1933 case service_slave:
1934 sim_printf("%c.%03d: slave", (char)('a' + (int) devnum), linenum);
1935 break;
1936 default:
1937 sim_printf("%d.%03d: ERR (%u)", (char)('a' + (int) devnum), linenum, st);
1938 break;
1939 }
1940 if (linenum != (MAX_LINES - 1))
1941 sim_printf("\r\n");
1942 }
1943 return SCPE_OK;
1944 }
1945
1946 static t_stat fnpSetService (UNIT * uptr, UNUSED int32 value,
1947 const char * cptr, UNUSED void * desc)
1948 {
1949 if (! cptr)
1950 return SCPE_ARG;
1951 long devnum = FNP_UNIT_IDX (uptr);
1952 if (devnum < 0 || devnum >= N_FNP_UNITS_MAX)
1953 return SCPE_ARG;
1954
1955
1956 uint linenum;
1957 char sn [strlen (cptr) + 1];
1958 int nr = sscanf (cptr, "%u=%s", & linenum, sn);
1959 if (nr != 2)
1960 return SCPE_ARG;
1961 if (linenum >= MAX_LINES)
1962 return SCPE_ARG;
1963 if (strcasecmp (sn, "undefined") == 0)
1964 fnpData.fnpUnitData[devnum].MState.line[linenum].service = service_undefined;
1965 else if (strcasecmp (sn, "login") == 0)
1966 fnpData.fnpUnitData[devnum].MState.line[linenum].service = service_login;
1967 else if (strcmp (sn, "ibm3270") == 0)
1968 {
1969 fnpData.fnpUnitData[devnum].MState.line[linenum].service = service_3270;
1970 fnpData.ibm3270ctlr[ASSUME0].fnpno = (uint) devnum;
1971 fnpData.ibm3270ctlr[ASSUME0].lineno = linenum;
1972 }
1973 else if (strcasecmp (sn, "autocall") == 0)
1974 fnpData.fnpUnitData[devnum].MState.line[linenum].service = service_autocall;
1975 else if (strncasecmp (sn, "slave=", 6) == 0)
1976 {
1977 uint pn;
1978 int nr2 = sscanf (sn, "slave=%u", & pn);
1979 if (nr2 != 1)
1980 return SCPE_ARG;
1981 if (pn >= 65535)
1982 return SCPE_ARG;
1983 fnpData.fnpUnitData[devnum].MState.line[linenum].service = service_slave;
1984 fnpData.fnpUnitData[devnum].MState.line[linenum].port = (int) pn;
1985 }
1986 else
1987 return SCPE_ARG;
1988 return SCPE_OK;
1989 }
1990
1991 static t_stat fnpShowConfig (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
1992 UNUSED const void * desc)
1993 {
1994 #if defined(TESTING)
1995 cpu_state_t * cpup = _cpup;
1996 #endif
1997 long fnpUnitIdx = FNP_UNIT_IDX (uptr);
1998 if (fnpUnitIdx >= (long) N_FNP_UNITS_MAX)
1999 {
2000 sim_debug (DBG_ERR, & fnp_dev,
2001 "fnpShowConfig: Invalid unit number %ld\r\n", (long) fnpUnitIdx);
2002 sim_printf ("error: Invalid unit number %ld\r\n", (long) fnpUnitIdx);
2003 return SCPE_ARG;
2004 }
2005
2006 sim_printf ("FNP unit number %ld\r\n", (long) fnpUnitIdx);
2007 struct fnpUnitData_s * fudp = fnpData.fnpUnitData + fnpUnitIdx;
2008
2009 sim_printf ("FNP mailbox address: %04o(8)\r\n", fudp -> mailboxAddress);
2010
2011 return SCPE_OK;
2012 }
2013
2014
2015
2016
2017 int n_fw_entries = 0;
2018 struct fw_entry_s fw_entries [N_FW_ENTRIES];
2019
2020
2021
2022
2023 static int parse_line (char * line)
2024 {
2025 char fnp = line[0];
2026 if (fnp < 'A' || fnp > 'H')
2027 return -1;
2028 int fnpno = fnp - 'A';
2029
2030 if (line [1] != '.')
2031 return -2;
2032
2033 if (line[2] != 'H')
2034 return -3;
2035
2036 if (line[3] < '0' || line[3] > '9')
2037 return -4;
2038
2039 if (line[4] < '0' || line[4] > '9')
2040 return -5;
2041
2042 if (line[5] < '0' || line[5] > '9')
2043 return -6;
2044 int lineno = (line[3] - '0') * 100 +
2045 (line[4] - '0') * 10 +
2046 (line[5] - '0');
2047
2048 if (line[6] != 0 && line[6] != '-')
2049 return -7;
2050
2051 return encodeline (fnpno, lineno);
2052
2053 }
2054
2055
2056 static int parse_ipaddr (char * str, uint32_t * addr)
2057 {
2058 char * end1, * end2, * end3, * end4;
2059
2060 unsigned long o1 = strtoul (str, & end1, 10);
2061 if (end1 == str || * end1 != '.' || o1 > 255)
2062 return -1;
2063
2064 unsigned long o2 = strtoul (end1 + 1, & end2, 10);
2065 if (end2 == end1 || * end2 != '.' || o2 > 255)
2066 return -2;
2067
2068 unsigned long o3 = strtoul (end2 + 1, & end3, 10);
2069 if (end3 == end2 || * end3 != '.' || o3 > 255)
2070 return -3;
2071
2072 unsigned long o4 = strtoul (end3 + 1, & end4, 10);
2073 if (end4 == end3 || * end4 != 0 || o4 > 255)
2074 return -4;
2075 * addr = (uint32_t) ((o1 << 24) | (o2 << 16) | (o3 << 8) | o4);
2076 return 0;
2077 }
2078
2079 static t_stat fnpSetFW (UNIT * uptr, UNUSED int32 value,
2080 const char * cptr, UNUSED void * desc)
2081 {
2082 if (! cptr)
2083 return SCPE_ARG;
2084 long devnum = FNP_UNIT_IDX (uptr);
2085 if (devnum < 0 || devnum >= N_FNP_UNITS_MAX)
2086 return SCPE_ARG;
2087
2088 char sn [strlen (cptr) + 1];
2089 memcpy (sn, cptr, strlen (cptr) + 1);
2090 char * saveptr;
2091 char * tok;
2092
2093
2094 tok = strtok_r (sn, ":", & saveptr);
2095 if (strcasecmp (tok, "RESET") == 0)
2096 {
2097 n_fw_entries = 0;
2098 sim_printf ("FNP firewall table reset\r\n");
2099 return SCPE_OK;
2100 }
2101
2102 if (strcasecmp (tok, "ADD") == 0)
2103 {
2104 if (n_fw_entries >= N_FW_ENTRIES)
2105 {
2106 sim_printf ("FNP firewall table full\r\n");
2107 return SCPE_ARG;
2108 }
2109
2110 int line_0, line_1;
2111
2112 tok = strtok_r (NULL, ":", & saveptr);
2113 char * dash = strchr (tok, '-');
2114 if (dash)
2115 {
2116 line_0 = parse_line (tok);
2117 if (line_0 < 0)
2118 {
2119 sim_printf ("Cannot parse first line number\r\n");
2120 return SCPE_ARG;
2121 }
2122
2123 line_1 = parse_line (dash + 1);
2124 if (line_1 < 0)
2125 {
2126 sim_printf ("Cannot parse second line number\r\n");
2127 return SCPE_ARG;
2128 }
2129 if (line_0 > line_1)
2130 {
2131 sim_printf ("line_0 > line_1\r\n");
2132 return SCPE_ARG;
2133 }
2134
2135 }
2136 else
2137 {
2138 line_0 = line_1 = parse_line (tok);
2139 if (line_0 < 0)
2140 {
2141 sim_printf ("Cannot parse line number\r\n");
2142 return SCPE_ARG;
2143 }
2144 }
2145
2146
2147
2148 tok = strtok_r (NULL, ":", & saveptr);
2149 uint32_t ipaddr;
2150 int rc = parse_ipaddr (tok, & ipaddr);
2151 if (rc < 0)
2152 return SCPE_ARG;
2153
2154
2155
2156 tok = strtok_r (NULL, ":", & saveptr);
2157 char * end;
2158 unsigned long cidr = strtoul (tok, & end, 10);
2159 if (tok == end || * end != 0 || cidr > 32)
2160 return SCPE_OK;
2161 uint32_t cidr_mask = (cidr == 0) ? 0 :
2162 ((uint32_t)-1 << (32 - cidr)) & MASK32;
2163
2164
2165
2166 bool accept = false;
2167 tok = strtok_r (NULL, ":", & saveptr);
2168 if (strcmp (tok, "ACCEPT") == 0)
2169 accept = true;
2170 else if (strcmp (tok, "DENY") == 0)
2171 accept = false;
2172 else
2173 {
2174 sim_printf ("cannot parse rule ACCEPT/DENY\r\n");
2175 return SCPE_ARG;
2176 }
2177
2178 fw_entries[n_fw_entries].line_0 = (uint) line_0;
2179 fw_entries[n_fw_entries].line_1 = (uint) line_1;
2180 fw_entries[n_fw_entries].ipaddr = ipaddr;
2181 fw_entries[n_fw_entries].cidr = (uint) cidr;
2182 fw_entries[n_fw_entries].cidr_mask = (uint) cidr_mask;
2183 fw_entries[n_fw_entries].accept = accept;
2184 n_fw_entries ++;
2185
2186 return SCPE_OK;
2187 }
2188
2189 if (strcasecmp (tok, "LIST") == 0)
2190 {
2191 for (int i = 0; i < n_fw_entries; i ++)
2192 {
2193 struct fw_entry_s * p = fw_entries + i;
2194
2195 if (p->line_0 == p->line_1)
2196 {
2197 sim_printf (" %c.h%03d %d.%d.%d.%d/%d %s\r\n",
2198 decodefnp (p->line_0) + 'a',
2199 decodeline (p->line_0),
2200 (p->ipaddr>>24) & 255,
2201 (p->ipaddr>>16) & 255,
2202 (p->ipaddr>>8) & 255,
2203 p->ipaddr & 255,
2204 p->cidr,
2205 p->accept ? "accept" : "deny");
2206 }
2207 else
2208 {
2209 sim_printf (" %c.h%03d-%c.%03d %d.%d.%d.%d/%d %s\r\n",
2210 decodefnp (p->line_0) + 'a',
2211 decodeline (p->line_0),
2212 decodefnp (p->line_1) + 'a',
2213 decodeline (p->line_1),
2214 (p->ipaddr>>24) & 255,
2215 (p->ipaddr>>16) & 255,
2216 (p->ipaddr>>8) & 255,
2217 p->ipaddr & 255,
2218 p->cidr,
2219 p->accept ? "accept" : "deny");
2220 }
2221 }
2222 return SCPE_OK;
2223 }
2224
2225 return SCPE_ARG;
2226 }
2227
2228 static t_stat fnpShowFW (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
2229 UNUSED const void * desc)
2230 {
2231 #if defined(TESTING)
2232 cpu_state_t * cpup = _cpup;
2233 #endif
2234 long fnpUnitIdx = FNP_UNIT_IDX (uptr);
2235 if (fnpUnitIdx >= (long) N_FNP_UNITS_MAX)
2236 {
2237 sim_debug (DBG_ERR, & fnp_dev,
2238 "fnpShowConfig: Invalid unit number %ld\r\n",
2239 (long) fnpUnitIdx);
2240 sim_printf ("error: Invalid unit number %ld\r\n",
2241 (long) fnpUnitIdx);
2242 return SCPE_ARG;
2243 }
2244
2245
2246
2247
2248
2249
2250
2251 return SCPE_OK;
2252 }
2253
2254 static t_stat fnpShowStatus (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
2255 UNUSED const void * desc)
2256 {
2257 #if defined(TESTING)
2258 cpu_state_t * cpup = _cpup;
2259 #endif
2260 long fnpUnitIdx = FNP_UNIT_IDX (uptr);
2261 if (fnpUnitIdx >= (long) fnp_dev.numunits)
2262 {
2263 sim_debug (DBG_ERR, & fnp_dev,
2264 "fnpShowStatus: Invalid unit number %ld\r\n",
2265 (long) fnpUnitIdx);
2266 sim_printf ("error: Invalid unit number %ld\r\n",
2267 (long) fnpUnitIdx);
2268 return SCPE_ARG;
2269 }
2270
2271 sim_printf ("FNP unit number %ld:\r\n", (long) fnpUnitIdx);
2272 struct fnpUnitData_s * fudp = fnpData.fnpUnitData + fnpUnitIdx;
2273
2274 sim_printf ("\tmailboxAddress: %04o\r\n",
2275 fudp->mailboxAddress);
2276 sim_printf ("\tfnpIsRunning: %o\r\n",
2277 fudp->fnpIsRunning);
2278 sim_printf ("\tfnpMBXinUse: %o %o %o %o\r\n",
2279 fudp->fnpMBXinUse[0], fudp->fnpMBXinUse[1],
2280 fudp->fnpMBXinUse[2], fudp->fnpMBXinUse[3]);
2281 sim_printf ("\tlineWaiting: %o %o %o %o\r\n",
2282 fudp->lineWaiting[0], fudp->lineWaiting[1],
2283 fudp->lineWaiting[2], fudp->lineWaiting[3]);
2284 sim_printf ("\tfnpMBXlineno: %o %o %o %o\r\n",
2285 fudp->fnpMBXlineno[0], fudp->fnpMBXlineno[1],
2286 fudp->fnpMBXlineno[2], fudp->fnpMBXlineno[3]);
2287 sim_printf ("\taccept_calls: %o\r\n",
2288 fudp->MState.accept_calls);
2289 for (int l = 0; l < MAX_LINES; l ++)
2290 {
2291 sim_printf (" line %d:\r\n", l);
2292 sim_printf ("\tservice: %d\r\n",
2293 fudp->MState.line[l].service);
2294 sim_printf ("\tline_client: %p\r\n",
2295 (void *) fudp->MState.line[l].line_client);
2296 sim_printf ("\twas_CR: %d\r\n",
2297 fudp->MState.line[l].was_CR);
2298 sim_printf ("\tlisten: %d\r\n",
2299 fudp->MState.line[l].listen);
2300 sim_printf ("\tinputBufferSize: %d\r\n",
2301 fudp->MState.line[l].inputBufferSize);
2302 sim_printf ("\tline_break: %d\r\n",
2303 fudp->MState.line[l].line_break);
2304 sim_printf ("\tsend_output: %d\r\n",
2305 fudp->MState.line[l].send_output);
2306 sim_printf ("\taccept_new_terminal: %d\r\n",
2307 fudp->MState.line[l].accept_new_terminal);
2308 #if DISC_DELAY
2309 sim_printf ("\tline_disconnected: %d\r\n",
2310 fudp->MState.line[l].line_disconnected);
2311 #else
2312 sim_printf ("\tline_disconnected: %c\r\n",
2313 fudp->MState.line[l].line_disconnected ? 'T' : 'F');
2314 #endif
2315 sim_printf ("\tacu_dial_failure: %d\r\n",
2316 fudp->MState.line[l].acu_dial_failure);
2317 sim_printf ("\taccept_input: %d\r\n",
2318 fudp->MState.line[l].accept_input);
2319 sim_printf ("\twaitForMbxDone: %d\r\n",
2320 fudp->MState.line[l].waitForMbxDone);
2321 sim_printf ("\tinput_reply_pending: %d\r\n",
2322 fudp->MState.line[l].input_reply_pending);
2323 sim_printf ("\tinput_in_mailbox_pending: %d\r\n",
2324 fudp->MState.line[l].input_in_mailbox_pending);
2325 sim_printf ("\tinput_break: %d\r\n",
2326 fudp->MState.line[l].input_break);
2327 sim_printf ("\tnPos: %d\r\n",
2328 fudp->MState.line[l].nPos);
2329 sim_printf ("\tinBuffer: %p\r\n",
2330 (void *) fudp->MState.line[l].inBuffer);
2331 sim_printf ("\tinSize: %d\r\n",
2332 fudp->MState.line[l].inSize);
2333 sim_printf ("\tinUsed: %d\r\n",
2334 fudp->MState.line[l].inUsed);
2335
2336
2337
2338
2339 sim_printf ("\tport: %d\r\n",
2340 fudp->MState.line[l].port);
2341
2342 }
2343 return SCPE_OK;
2344 }
2345
2346 static t_stat fnp_show_device_name (UNUSED FILE * st, UNIT * uptr,
2347 UNUSED int val, UNUSED const void * desc)
2348 {
2349 int n = (int) FNP_UNIT_IDX (uptr);
2350 if (n < 0 || n >= N_FNP_UNITS_MAX)
2351 return SCPE_ARG;
2352 if (fnpData.fnpUnitData[n].device_name[0] != 0)
2353 sim_printf(" name: %s", fnpData.fnpUnitData[n].device_name);
2354 else
2355 sim_printf(" name: default");
2356 return SCPE_OK;
2357 }
2358
2359 static t_stat fnp_set_device_name (UNIT * uptr, UNUSED int32 value,
2360 const char * cptr, UNUSED void * desc)
2361 {
2362 int n = (int) FNP_UNIT_IDX (uptr);
2363 if (n < 0 || n >= N_FNP_UNITS_MAX)
2364 return SCPE_ARG;
2365 if (cptr)
2366 {
2367 strncpy (fnpData.fnpUnitData[n].device_name, cptr, MAX_DEV_NAME_LEN-1);
2368 fnpData.fnpUnitData[n].device_name[MAX_DEV_NAME_LEN-1] = 0;
2369 }
2370 else
2371 fnpData.fnpUnitData[n].device_name[0] = 0;
2372 return SCPE_OK;
2373 }
2374
2375 static config_list_t fnp_config_list [] =
2376 {
2377 { "mailbox", 0, 07777, NULL },
2378 { NULL, 0, 0, NULL }
2379 };
2380
2381 static t_stat fnpSetConfig (UNIT * uptr, UNUSED int value, const char * cptr, UNUSED void * desc)
2382 {
2383 #if defined(TESTING)
2384 cpu_state_t * cpup = _cpup;
2385 #endif
2386 uint fnpUnitIdx = (uint) FNP_UNIT_IDX (uptr);
2387
2388 if (fnpUnitIdx >= N_FNP_UNITS_MAX)
2389 {
2390 sim_debug (DBG_ERR, & fnp_dev, "fnpSetConfig: Invalid unit number %ld\r\n", (long) fnpUnitIdx);
2391 sim_printf ("error: fnpSetConfig: Invalid unit number %ld\r\n", (long) fnpUnitIdx);
2392 return SCPE_ARG;
2393 }
2394
2395 struct fnpUnitData_s * fudp = fnpData.fnpUnitData + fnpUnitIdx;
2396
2397 config_state_t cfg_state = { NULL, NULL };
2398
2399 for (;;)
2400 {
2401 int64_t v;
2402 int rc = cfg_parse ("fnpSetConfig", cptr, fnp_config_list, & cfg_state, & v);
2403 switch (rc)
2404 {
2405 case -2:
2406 cfg_parse_done (& cfg_state);
2407 return SCPE_ARG;
2408
2409 case -1:
2410 break;
2411
2412 case 0:
2413 fudp -> mailboxAddress = (uint) v;
2414 break;
2415
2416 default:
2417 sim_printf ("error: fnpSetConfig: Invalid cfg_parse rc <%ld>\r\n", (long) rc);
2418 cfg_parse_done (& cfg_state);
2419 return SCPE_ARG;
2420 }
2421 if (rc < 0)
2422 break;
2423 }
2424 cfg_parse_done (& cfg_state);
2425 return SCPE_OK;
2426 }
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528 t_stat set_fnp_server_port (UNUSED int32 arg, const char * buf)
2529 {
2530 if (fnpData.du_server_inited)
2531 {
2532 sim_printf ("[FNP emulation: TELNET server port error: FNP already initialized]\r\n");
2533 return SCPE_INCOMP;
2534 }
2535 if (! buf)
2536 return SCPE_ARG;
2537 int n = atoi (buf);
2538 if (n < 1 || n > 65535)
2539 return SCPE_ARG;
2540 fnpData.telnet_port = n;
2541 if (! sim_quiet)
2542 {
2543 sim_printf ("[FNP emulation: TELNET server port set to %ld]\r\n", (long) n);
2544 }
2545 return SCPE_OK;
2546 }
2547
2548 t_stat set_fnp_server_address (UNUSED int32 arg, const char * buf)
2549 {
2550 if (fnpData.du_server_inited)
2551 {
2552 sim_printf ("[FNP emulation: FNP server address error: FNP already initialized]\r\n");
2553 return SCPE_INCOMP;
2554 }
2555 if ( (!buf) || (buf[0] == 0) )
2556 return SCPE_ARG;
2557 if (fnpData.telnet_address)
2558 FREE (fnpData.telnet_address);
2559 fnpData.telnet_address = strdup (buf);
2560 if (!fnpData.telnet_address)
2561 {
2562 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2563 __func__, __FILE__, __LINE__);
2564 #if defined(USE_BACKTRACE)
2565 # if defined(SIGUSR2)
2566 (void)raise(SIGUSR2);
2567
2568 # endif
2569 #endif
2570 abort();
2571 }
2572 if (! sim_quiet)
2573 {
2574 sim_printf ("[FNP emulation: FNP server address set to %s]\r\n", fnpData.telnet_address);
2575 }
2576 return SCPE_OK;
2577 }
2578
2579 t_stat set_fnp_3270_server_port (UNUSED int32 arg, const char * buf)
2580 {
2581
2582 if ( (fnpData.du3270_server_inited) || (fnpData.du_server_inited) )
2583 {
2584 sim_printf ("[FNP emulation: TN3270 server port error: FNP already initialized]\r\n");
2585 return SCPE_INCOMP;
2586 }
2587 if (! buf)
2588 return SCPE_ARG;
2589 int n = atoi (buf);
2590 if (n < 1 || n > 65535)
2591 return SCPE_ARG;
2592 fnpData.telnet3270_port = n;
2593 if (! sim_quiet)
2594 {
2595 sim_printf ("[FNP emulation: TN3270 server port set to %ld]\r\n", (long) n);
2596 }
2597 return SCPE_OK;
2598 }
2599
2600 t_stat fnp_start (UNUSED int32 arg, UNUSED const char * buf)
2601 {
2602 int rc = 0;
2603 rc = fnpuvInit (fnpData.telnet_port, fnpData.telnet_address);
2604 if (rc != 0)
2605 return SCPE_INCOMP;
2606
2607
2608
2609 return SCPE_OK;
2610 }
2611
2612 #define PROMPT "HSLA Port ("
2613
2614 void fnpConnectPrompt (uv_tcp_t * client)
2615 {
2616 fnpuv_start_writestr (client, (unsigned char *) PROMPT);
2617 bool first = true;
2618 uint numunits = (uint) fnp_dev.numunits;
2619 for (uint fnp_unit_idx = 0; fnp_unit_idx < numunits; fnp_unit_idx ++)
2620 {
2621 if (! fnpData.fnpUnitData[fnp_unit_idx].fnpIsRunning)
2622 continue;
2623 for (uint lineno = 0; lineno < MAX_LINES; lineno ++)
2624 {
2625 struct t_line * linep = & fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno];
2626 if (! linep->listen)
2627 continue;
2628 if (linep->service == service_login &&
2629 ! linep->line_disconnected &&
2630 ! linep->line_client &&
2631 fnpData.fnpUnitData[fnp_unit_idx].MState.accept_calls)
2632 {
2633 if (! first)
2634 fnpuv_start_writestr (client, (unsigned char *) ",");
2635 char name [16];
2636 first = false;
2637 (void)sprintf (name, "%c.h%03d", 'a' + fnp_unit_idx, lineno);
2638 fnpuv_start_writestr (client, (unsigned char *) name);
2639 }
2640 }
2641 }
2642 fnpuv_start_writestr (client, (unsigned char *) ")? ");
2643 }
2644
2645
2646
2647
2648
2649 const unsigned char a2e[256] = {
2650 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
2651 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
2652 64, 79, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
2653 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
2654 124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
2655 215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 74, 224, 90, 95, 109,
2656 121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
2657 151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 106, 208, 161, 7,
2658 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
2659 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62, 225,
2660 65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87,
2661 88, 89, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, 115, 116, 117,
2662 118, 119, 120, 128, 138, 139, 140, 141, 142, 143, 144, 154, 155, 156, 157, 158,
2663 159, 160, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
2664 184, 185, 186, 187, 188, 189, 190, 191, 202, 203, 204, 205, 206, 207, 218, 219,
2665 220, 221, 222, 223, 234, 235, 236, 237, 238, 239, 250, 251, 252, 253, 254, 255
2666 };
2667
2668 const unsigned char e2a[256] = {
2669 0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
2670 16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
2671 128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
2672 144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
2673 32, 160, 161, 162, 163, 164, 165, 166, 167, 168, 91, 46, 60, 40, 43, 33,
2674 38, 169, 170, 171, 172, 173, 174, 175, 176, 177, 93, 36, 42, 41, 59, 94,
2675 45, 47, 178, 179, 180, 181, 182, 183, 184, 185, 124, 44, 37, 95, 62, 63,
2676 186, 187, 188, 189, 190, 191, 192, 193, 194, 96, 58, 35, 64, 39, 61, 34,
2677 195, 97, 98, 99, 100, 101, 102, 103, 104, 105, 196, 197, 198, 199, 200, 201,
2678 202, 106, 107, 108, 109, 110, 111, 112, 113, 114, 203, 204, 205, 206, 207, 208,
2679 209, 126, 115, 116, 117, 118, 119, 120, 121, 122, 210, 211, 212, 213, 214, 215,
2680 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
2681 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 232, 233, 234, 235, 236, 237,
2682 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 238, 239, 240, 241, 242, 243,
2683 92, 159, 83, 84, 85, 86, 87, 88, 89, 90, 244, 245, 246, 247, 248, 249,
2684 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 250, 251, 252, 253, 254, 255
2685 };
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699 static void fnp3270Msg (uv_tcp_t * client, unsigned char * msg)
2700 {
2701
2702 size_t l = strlen ((char *) msg);
2703 unsigned char buf [l + 1];
2704 for (uint i = 0; i < l; i ++)
2705 buf[i] = a2e[msg[i]];
2706 buf[l] = '\0';
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716 unsigned char EW [] = {245, 0xc3, 17, 64, 64 };
2717 fnpuv_start_3270_write (client, EW, sizeof (EW));
2718 fnpuv_start_3270_write (client, buf, (ssize_t) l);
2719 fnpuv_send_eor (client);
2720 }
2721
2722 void fnp3270ConnectPrompt (uv_tcp_t * client)
2723 {
2724 if (! client || ! client->data)
2725 {
2726 sim_warn ("fnp3270ConnectPrompt bad client data\r\n");
2727 return;
2728 }
2729 uint fnpno = fnpData.ibm3270ctlr[ASSUME0].fnpno;
2730 uint lineno = fnpData.ibm3270ctlr[ASSUME0].lineno;
2731
2732 uvClientData * p = client->data;
2733 p->assoc = true;
2734 p->fnpno = fnpno;
2735 p->lineno = lineno;
2736
2737
2738
2739
2740
2741 unsigned char buf [256];
2742 (void)snprintf ((char *) buf, sizeof buf,
2743 "DPS8/M 3270 connection to %c.%03d.%ld ttype %s\r\n",
2744 fnpno+'a',lineno, (long)p->stationNo,
2745 p->ttype ? p->ttype : "unknown");
2746 if (p->stationNo >= ADDR_MAP_ENTRIES)
2747 return;
2748 fnpData.ibm3270ctlr[ASSUME0].selDevChar = addr_map[p->stationNo];
2749 fnp3270Msg (client, buf);
2750
2751 }
2752
2753 void processLineInput (uv_tcp_t * client, unsigned char * buf, ssize_t nread)
2754 {
2755 if (! client || ! client->data)
2756 {
2757 sim_warn ("processLineInput bad client data\r\n");
2758 return;
2759 }
2760 uvClientData * p = (uvClientData *) client->data;
2761 uint fnpno = p -> fnpno;
2762 uint lineno = p -> lineno;
2763 if (fnpno >= N_FNP_UNITS_MAX || lineno >= MAX_LINES)
2764 {
2765 sim_printf ("bogus client data\r\n");
2766 return;
2767 }
2768
2769
2770
2771
2772
2773
2774
2775 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
2776
2777 if (nread <= 0 || !buf || (uint64_t)nread > UINT_MAX - linep->inSize ||
2778 (uint64_t)linep->inSize + (uint64_t)nread > FNP_MAX_PENDING_INPUT)
2779 {
2780 sim_warn ("FNP input would overflow line buffer; disconnecting\r\n");
2781 close_connection ((uv_stream_t *)client);
2782 return;
2783 }
2784
2785
2786
2787
2788
2789
2790
2791 if (linep->inBuffer)
2792 {
2793 if (! sim_quiet)
2794 {
2795 sim_warn ("inBuffer overrun\r\n");
2796 }
2797 unsigned char * new = realloc (linep->inBuffer, (unsigned long) (linep->inSize + nread));
2798 if (! new)
2799 {
2800 sim_warn ("FNP input allocation failed; disconnecting\r\n");
2801 close_connection ((uv_stream_t *)client);
2802 return;
2803 }
2804 memcpy (new + linep->inSize, buf, (unsigned long) nread);
2805 linep->inSize += nread;
2806 linep->inBuffer = new;
2807 }
2808 else
2809 {
2810 linep->inBuffer = malloc ((unsigned long) nread);
2811 if (! linep->inBuffer)
2812 {
2813 sim_warn ("FNP input allocation failed; disconnecting\r\n");
2814 close_connection ((uv_stream_t *)client);
2815 return;
2816 }
2817 memcpy (linep->inBuffer, buf, (unsigned long) nread);
2818 linep->inSize = (uint) nread;
2819 linep->inUsed = 0;
2820 }
2821
2822
2823 fnpuv_read_stop (client);
2824 }
2825
2826 void process3270Input (uv_tcp_t * client, unsigned char * buf, ssize_t nread)
2827 {
2828 #if defined(TESTING)
2829 cpu_state_t * cpup = _cpup;
2830 #endif
2831 if (! client || ! client->data)
2832 {
2833 sim_warn ("process3270Input bad client data\r\n");
2834 return;
2835 }
2836 uvClientData * p = (uvClientData *) client->data;
2837 uint fnpno = p->fnpno;
2838 uint lineno = p->lineno;
2839 uint stn_no = p->stationNo;
2840
2841 if (fnpno >= N_FNP_UNITS_MAX || lineno >= MAX_LINES ||
2842 stn_no >= IBM3270_STATIONS_MAX)
2843 {
2844 sim_printf ("bogus client data\r\n");
2845 return;
2846 }
2847 if (nread <= 0 || !buf)
2848 {
2849 sim_warn ("TN3270 invalid input; disconnecting\r\n");
2850 close_connection ((uv_stream_t *)client);
2851 return;
2852 }
2853 if_sim_debug (DBG_TRACE, & fnp_dev) {
2854 sim_debug (DBG_TRACE, & fnp_dev, "process3270Input nread %ld\r\n", (long)nread);
2855 for (int i = 0; i < nread; i ++) sim_debug (DBG_TRACE, & fnp_dev, "%c", isgraph (e2a[buf[i]]) ? e2a[buf[i]] : '.');
2856 sim_debug (DBG_TRACE, & fnp_dev, "\r\n");
2857 for (int i = 0; i < nread; i ++) sim_debug (DBG_TRACE, & fnp_dev, " %02x", buf[i]);
2858 sim_debug (DBG_TRACE, & fnp_dev, "\r\n");
2859 }
2860
2861 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
2862 if (! fnpData.fnpUnitData[fnpno].MState.accept_calls)
2863 {
2864 if (! linep->inBuffer)
2865 fnp3270Msg (client, (unsigned char *) "Multics is not accepting calls\r\n");
2866 return;
2867 }
2868 if (! linep->listen)
2869 {
2870 if (! linep->inBuffer)
2871 fnp3270Msg (client, (unsigned char *) "Multics is not listening to this line\r\n");
2872 return;
2873 }
2874
2875
2876
2877
2878
2879
2880
2881
2882 struct station_s * stn_p = & fnpData.ibm3270ctlr[ASSUME0].stations[stn_no];
2883 if ((uint64_t)nread > UINT_MAX - stn_p->stn_in_size ||
2884 (uint64_t)stn_p->stn_in_size + (uint64_t)nread > FNP_MAX_PENDING_INPUT)
2885 {
2886 sim_warn ("TN3270 input would overflow station buffer; disconnecting\r\n");
2887 close_connection ((uv_stream_t *)client);
2888 return;
2889 }
2890 if (stn_p->stn_in_buffer)
2891 {
2892 if (! sim_quiet)
2893 {
2894 sim_warn ("stn_in_buffer overrun\r\n");
2895 }
2896 unsigned char * new = realloc (stn_p->stn_in_buffer, (unsigned long) (stn_p->stn_in_size + nread));
2897 if (! new)
2898 {
2899 sim_warn ("TN3270 input allocation failed; disconnecting\r\n");
2900 close_connection ((uv_stream_t *)client);
2901 return;
2902 }
2903 memcpy (new + stn_p->stn_in_size, buf, (unsigned long) nread);
2904 stn_p->stn_in_size += nread;
2905 stn_p->stn_in_buffer = new;
2906 }
2907 else
2908 {
2909 stn_p->stn_in_buffer = malloc ((unsigned long) nread);
2910 if (! stn_p->stn_in_buffer)
2911 {
2912 sim_warn ("TN3270 input allocation failed; disconnecting\r\n");
2913 close_connection ((uv_stream_t *)client);
2914 return;
2915 }
2916 memcpy (stn_p->stn_in_buffer, buf, (unsigned long) nread);
2917 stn_p->stn_in_size = (uint) nread;
2918 stn_p->stn_in_used = 0;
2919 }
2920
2921 sim_debug (DBG_TRACE, & fnp_dev,
2922 "process3270Input stashed %lu bytes in stn %u; stn_in_size now %u\r\n",
2923 (unsigned long)nread, stn_no, stn_p->stn_in_size);
2924
2925
2926
2927 }
2928
2929 void reset_line (struct t_line * linep)
2930 {
2931 linep->was_CR = false;
2932 linep->inputBufferSize = 0;
2933 linep->ctrlStrIdx = 0;
2934 linep->breakAll = false;
2935 linep->handleQuit = false;
2936 linep->echoPlex = false;
2937 linep->crecho = false;
2938 linep->lfecho = false;
2939 linep->tabecho = false;
2940 linep->replay = false;
2941 linep->polite = false;
2942 linep->prefixnl = false;
2943 linep->eight_bit_out = false;
2944 linep->eight_bit_in = false;
2945 linep->odd_parity = false;
2946 linep->output_flow_control = false;
2947 linep->input_flow_control = false;
2948 linep->block_xfer_in_frame_sz = 0;
2949 linep->block_xfer_out_frame_sz = 0;
2950 (void)memset (linep->delay_table, 0, sizeof (linep->delay_table));
2951 linep->inputSuspendLen = 0;
2952 (void)memset (linep->inputSuspendStr, 0, sizeof (linep->inputSuspendStr));
2953 linep->inputResumeLen = 0;
2954 (void)memset (linep->inputResumeStr, 0, sizeof (linep->inputResumeStr));
2955 linep->outputSuspendLen = 0;
2956 (void)memset (linep->outputSuspendStr, 0, sizeof (linep->outputSuspendStr));
2957 linep->outputResumeLen = 0;
2958 (void)memset (linep->outputResumeStr, 0, sizeof (linep->outputResumeStr));
2959 linep->frame_begin = 0;
2960 linep->frame_end = 0;
2961 (void)memset (linep->echnego_break_table, 0, sizeof (linep->echnego_break_table));
2962 linep->echnego_sync_ctr = 0;
2963 linep->echnego_screen_left = 0;
2964 linep->echnego_unechoed_cnt = 0;
2965 linep->echnego_on = false;
2966 linep->echnego_synced = false;
2967 linep->line_break = false;
2968 }
2969
2970 void processUserInput (uv_tcp_t * client, unsigned char * buf, ssize_t nread)
2971 {
2972 if (! client || ! client->data)
2973 {
2974 sim_warn ("processUserInput bad client data\r\n");
2975 return;
2976 }
2977 uvClientData * p = (uvClientData *) client->data;
2978 for (ssize_t nchar = 0; nchar < nread; nchar ++)
2979 {
2980 unsigned char kar = buf [nchar];
2981
2982 if (kar == 0x1b || kar == 0x03)
2983 {
2984 close_connection ((uv_stream_t *) client);
2985 return;
2986 }
2987
2988
2989 if (p->nPos >= sizeof(p->buffer) - 1)
2990 {
2991
2992 switch (kar)
2993 {
2994 case '\b':
2995 case 127:
2996 {
2997 if (p->nPos)
2998 {
2999 fnpuv_start_writestr (client, (unsigned char *) "\b \b");
3000
3001 p->buffer[p->nPos] = 0;
3002 p->nPos -= 1;
3003 }
3004 }
3005 break;
3006
3007 case '\n':
3008 case '\r':
3009 {
3010 p->buffer[p->nPos] = 0;
3011 goto check;
3012 }
3013
3014 case 0x12:
3015 {
3016 fnpuv_start_writestr (client, (unsigned char *) "^R\r\n");
3017 fnpConnectPrompt (client);
3018 fnpuv_start_writestr (client, (unsigned char *) p->buffer);
3019 }
3020 break;
3021
3022 default:
3023 break;
3024 }
3025 continue;
3026 }
3027
3028 if (isprint (kar))
3029 {
3030 unsigned char str [2] = { kar, 0 };
3031 fnpuv_start_writestr (client, str);
3032 p->buffer[p->nPos++] = (char) kar;
3033 }
3034 else
3035 {
3036 switch (kar)
3037 {
3038 case '\b':
3039 case 127:
3040 {
3041 if (p->nPos)
3042 {
3043 fnpuv_start_writestr (client, (unsigned char *) "\b \b");
3044
3045 p->buffer[p->nPos] = 0;
3046 p->nPos -= 1;
3047 }
3048 }
3049 break;
3050
3051 case '\n':
3052 case '\r':
3053 {
3054 p->buffer[p->nPos] = 0;
3055 goto check;
3056 }
3057
3058 case 0x12:
3059 {
3060 fnpuv_start_writestr (client, (unsigned char *) "^R\r\n");
3061 fnpConnectPrompt (client);
3062 fnpuv_start_writestr (client, (unsigned char *) p->buffer);
3063 }
3064 break;
3065
3066 default:
3067 break;
3068 }
3069 }
3070 }
3071 return;
3072
3073 check:;
3074 char cpy [p->nPos + 1];
3075 memcpy (cpy, p->buffer, p->nPos);
3076 cpy [p->nPos] = 0;
3077 trim (cpy);
3078 #if defined(TESTING)
3079 if (! sim_quiet)
3080 {
3081 sim_printf ("[FNP emulation: Rcvd: '%s']\r\n", cpy);
3082 }
3083 #endif
3084 p->nPos = 0;
3085 fnpuv_start_writestr (client, (unsigned char *) "\r\n");
3086
3087 uint fnp_unit_idx = 0;
3088 uint lineno = 0;
3089
3090 if (strlen (cpy))
3091 {
3092 char fnpcode;
3093 int cnt = sscanf (cpy, "%c.h%u", & fnpcode, & lineno);
3094
3095 if (cnt != 2 || fnpcode < 'a' || fnpcode > 'h' || lineno >= MAX_LINES)
3096 {
3097 fnpuv_start_writestr (client, (unsigned char *) "can't parse\r\n");
3098 goto reprompt;
3099 }
3100 fnp_unit_idx = (uint) (fnpcode - 'a');
3101 if (fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].service != service_login ||
3102 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_client)
3103 {
3104 fnpuv_start_writestr (client, (unsigned char *) "not available\r\n");
3105 goto reprompt;
3106 }
3107 goto associate;
3108 }
3109 else
3110 {
3111 uint32 numunits = fnp_dev.numunits;
3112 for (fnp_unit_idx = 0; fnp_unit_idx < numunits; fnp_unit_idx ++)
3113 {
3114 if (! fnpData.fnpUnitData[fnp_unit_idx].fnpIsRunning)
3115 continue;
3116 for (lineno = 0; lineno < MAX_LINES; lineno ++)
3117 {
3118 if (fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].service == service_login &&
3119 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].listen &&
3120 ! fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_disconnected &&
3121 ! fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_client &&
3122 fnpData.fnpUnitData[fnp_unit_idx].MState.accept_calls)
3123 {
3124 goto associate;
3125 }
3126 }
3127 }
3128 fnpuv_start_writestr (client, (unsigned char *) "not available\r\n");
3129 goto reprompt;
3130 }
3131 reprompt:;
3132 fnpConnectPrompt (client);
3133 return;
3134
3135 associate:;
3136
3137 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_client = client;
3138 fnpuv_complete_selection (p);
3139
3140 p->assoc = true;
3141 p->fnpno = fnp_unit_idx;
3142 p->lineno = lineno;
3143 p->read_cb = fnpuv_associated_readcb;
3144 p->write_cb = fnpuv_start_write;
3145 p->write_actual_cb = fnpuv_start_write_actual;
3146
3147
3148
3149 char buf2 [1024];
3150
3151 char peer[128];
3152 const char * name = fnpuv_peer_name (client, peer, sizeof (peer));
3153 if (!name)
3154 {
3155 sim_printf ("\r[FNP emulation: CONNECT (address unavailable) to %c.h%03d]\r\n", fnp_unit_idx +'a', lineno);
3156 }
3157 else
3158 {
3159 sim_printf ("\r[FNP emulation: CONNECT %s to %c.h%03d]\r\n", name, fnp_unit_idx +'a', lineno);
3160 }
3161
3162 (void)sprintf (buf2, "Attached to line %c.h%03d\r\n", fnp_unit_idx +'a', lineno);
3163 fnpuv_start_writestr (client, (unsigned char *) buf2);
3164
3165 if (! fnpData.fnpUnitData[fnp_unit_idx].MState.accept_calls)
3166 fnpuv_start_writestr (client, (unsigned char *) "Multics is not accepting calls\r\n");
3167 else if (! fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].listen)
3168 fnpuv_start_writestr (client, (unsigned char *) "Multics is not listening to this line\r\n");
3169
3170
3171
3172 if (fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].lineType == 0)
3173 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].lineType = 1;
3174 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].accept_new_terminal = true;
3175 reset_line (& fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno]);
3176 }
3177
3178 void startFNPListener (void)
3179 {
3180 (void)fnpuvInit (fnpData.telnet_port, fnpData.telnet_address);
3181 }