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