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 "sim_defs.h"
100 #include "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\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\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\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\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\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\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\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\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\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\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\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 ("\nkar <%c>\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\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\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\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 fnpData.ibm3270ctlr[ASSUME0].stations[p->stationNo].EORReceived = true;
1225 fnpData.ibm3270ctlr[ASSUME0].stations[p->stationNo].hdr_sent = false;
1226 }
1227
1228 static void fnpProcessBuffer (struct t_line * linep)
1229 {
1230
1231 #if defined(TUN)
1232 if ((! linep->is_tun) && ! linep->line_client)
1233 #else
1234 if (! linep->line_client)
1235 #endif
1236 {
1237 if (linep->inBuffer)
1238 FREE (linep->inBuffer);
1239 linep->inBuffer = NULL;
1240 linep->inSize = 0;
1241 linep->inUsed = 0;
1242 return;
1243 }
1244
1245 while (linep->inBuffer && linep->inUsed < linep->inSize)
1246 {
1247 unsigned char c = linep->inBuffer [linep->inUsed ++];
1248
1249 bool eob = linep->inUsed >= linep->inSize;
1250 if (eob)
1251 {
1252 FREE (linep->inBuffer);
1253 linep->inBuffer = NULL;
1254 linep->inSize = 0;
1255 linep->inUsed = 0;
1256
1257 if (linep->line_client)
1258 fnpuv_read_start (linep->line_client);
1259 }
1260 if (linep->service == service_3270)
1261 {
1262 linep->buffer[linep->nPos++] = c;
1263 linep->buffer[linep->nPos] = 0;
1264 continue;
1265 }
1266 if (processInputCharacter (linep, c, eob))
1267 break;
1268 }
1269 }
1270
1271 static void fnpProcessBuffers (void)
1272 {
1273 uint numunits = (uint) fnp_dev.numunits;
1274 for (uint fnp_unit_idx = 0; fnp_unit_idx < numunits; fnp_unit_idx ++)
1275 {
1276 if (! fnpData.fnpUnitData[fnp_unit_idx].fnpIsRunning)
1277 continue;
1278 for (uint lineno = 0; lineno < MAX_LINES; lineno ++)
1279 {
1280 struct t_line * linep = & fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno];
1281
1282
1283 if (linep->accept_input)
1284 continue;
1285
1286
1287 if (linep->input_reply_pending)
1288 continue;
1289
1290
1291 if (!linep->inBuffer)
1292 continue;
1293
1294 fnpProcessBuffer (linep);
1295 }
1296 }
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 void set_3270_write_complete (UNUSED uv_tcp_t * client)
1324 {
1325 #if defined(TESTING)
1326 cpu_state_t * cpup = _cpup;
1327 #endif
1328
1329
1330 sim_debug (DBG_TRACE, & fnp_dev, "set_3270_write_complete\n");
1331
1332 fnpData.ibm3270ctlr[ASSUME0].write_complete = true;
1333 }
1334
1335 static void send_3270_msg (uint ctlr_no, unsigned char * msg, size_t len, bool brk)
1336 {
1337
1338
1339
1340
1341
1342
1343
1344
1345 uint fnpno = fnpData.ibm3270ctlr[ctlr_no].fnpno;
1346 uint lineno = fnpData.ibm3270ctlr[ctlr_no].lineno;
1347 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
1348 if ((unsigned long) linep->nPos + len > sizeof (linep->buffer))
1349 sim_warn ("send_3270_msg overfull linep->buffer; dropping data\r\n");
1350 else
1351 {
1352 memcpy (linep->buffer + linep->nPos, msg, len);
1353 linep->nPos += len;
1354 }
1355
1356
1357
1358
1359
1360
1361
1362 linep->force_accept_input = true;
1363 linep->accept_input = 1;
1364 linep->input_break = brk ? 1 : 0;
1365 }
1366
1367 const unsigned char addr_map [ADDR_MAP_ENTRIES] =
1368 {
1369 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
1370 0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
1371 0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
1372 0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f
1373 };
1374
1375 static void send_stn_in_buffer (void)
1376 {
1377 #if defined(TESTING)
1378 cpu_state_t * cpup = _cpup;
1379 sim_debug (DBG_TRACE, & fnp_dev, "fnp2 send_stn_in_buffer\r\n");
1380 #endif
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396 uint fnpno = fnpData.ibm3270ctlr[ASSUME0].fnpno;
1397 uint lineno = fnpData.ibm3270ctlr[ASSUME0].lineno;
1398 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
1399
1400
1401 if (linep->accept_input)
1402 return;
1403 if (linep->input_reply_pending)
1404 return;
1405
1406 struct ibm3270ctlr_s * ctlrp = & fnpData.ibm3270ctlr[ASSUME0];
1407 struct station_s * stnp = & fnpData.ibm3270ctlr[ASSUME0].stations[ctlrp->stn_no];
1408
1409 uint left = linep->sync_msg_size;
1410
1411 unsigned char * bufp = linep->buffer;
1412
1413 * bufp ++ = 0x2;
1414 left --;
1415
1416 if (! stnp->hdr_sent)
1417 {
1418 * bufp ++ = addr_map [ASSUME0];
1419 left --;
1420 * bufp ++ = addr_map [ctlrp->stn_no];
1421 left --;
1422 stnp->hdr_sent = true;
1423 }
1424
1425 uint n_to_send = stnp->stn_in_size - stnp->stn_in_used;
1426 if (n_to_send > left)
1427 n_to_send = left;
1428 if (n_to_send)
1429 {
1430 sim_debug (DBG_TRACE, & fnp_dev, "handling in used %u %u\r\n", stnp->stn_in_used, n_to_send);
1431
1432
1433 memcpy (bufp, stnp->stn_in_buffer + stnp->stn_in_used, n_to_send);
1434 bufp += n_to_send;
1435 stnp->stn_in_used += n_to_send;
1436 left -= n_to_send;
1437 }
1438
1439 if (stnp->stn_in_used >= stnp->stn_in_size && left)
1440 {
1441 * bufp ++ = 0x3;
1442 left --;
1443
1444 FREE (stnp->stn_in_buffer);
1445 stnp->stn_in_buffer = NULL;
1446 stnp->stn_in_size = 0;
1447 stnp->stn_in_used = 0;
1448
1449 linep->input_break = 1;
1450 fnpData.ibm3270ctlr[ASSUME0].sending_stn_in_buffer = false;
1451
1452
1453 }
1454 uint sz = (uint) (bufp - linep->buffer);
1455 if (sz)
1456 {
1457 linep->force_accept_input = true;
1458 linep->accept_input = 1;
1459 linep->nPos = sz;
1460 }
1461
1462
1463
1464
1465
1466
1467 }
1468
1469 static void fnp_process_3270_event (void)
1470 {
1471 #if defined(TESTING)
1472 cpu_state_t * cpup = _cpup;
1473 #endif
1474 uint fnpno = fnpData.ibm3270ctlr[ASSUME0].fnpno;
1475 uint lineno = fnpData.ibm3270ctlr[ASSUME0].lineno;
1476 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
1477
1478
1479
1480 if (fnpData.ibm3270ctlr[ASSUME0].sending_stn_in_buffer)
1481 {
1482 send_stn_in_buffer ();
1483 return;
1484 }
1485
1486 if (fnpData.ibm3270ctlr[ASSUME0].write_complete)
1487 {
1488 fnpData.ibm3270ctlr[ASSUME0].write_complete = false;
1489 linep->lineStatus0 = 6llu << 18;
1490 linep->lineStatus1 = 0;
1491 linep->sendLineStatus = true;
1492 }
1493
1494
1495
1496 if (! fnpData.du3270_poll)
1497 return;
1498 fnpData.du3270_poll --;
1499 if (fnpData.du3270_poll)
1500 return;
1501 struct ibm3270ctlr_s * ctlrp = & fnpData.ibm3270ctlr[ASSUME0];
1502
1503 sim_debug (DBG_TRACE, & fnp_dev, "fnp2 3270 poll\n");
1504
1505
1506
1507
1508
1509 if (ctlrp->pollDevChar == 127)
1510 {
1511 uint stn_cnt;
1512 for (stn_cnt = 0; stn_cnt < IBM3270_STATIONS_MAX; stn_cnt ++)
1513 {
1514 ctlrp->stn_no = (ctlrp->stn_no + 1) % IBM3270_STATIONS_MAX;
1515 struct station_s * stnp = & fnpData.ibm3270ctlr[ASSUME0].stations[ctlrp->stn_no];
1516 if (! stnp->client)
1517 continue;
1518 if (stnp->EORReceived)
1519 {
1520 stnp->EORReceived = false;
1521 ctlrp->sending_stn_in_buffer = true;
1522 fnpuv3270Poll (false);
1523 break;
1524 }
1525 }
1526 if (stn_cnt >= IBM3270_STATIONS_MAX)
1527 {
1528
1529
1530 unsigned char EOT = 0x37;
1531 send_3270_msg (ASSUME0, & EOT, 1, true);
1532 fnpuv3270Poll (false);
1533 }
1534 }
1535 else
1536 {
1537
1538 sim_debug (DBG_TRACE, & fnp_dev, "fnp2 specific poll\n");
1539 }
1540 }
1541
1542
1543
1544
1545
1546 void fnpProcessEvent (void)
1547 {
1548 #if defined(TESTING)
1549 cpu_state_t * cpup = _cpup;
1550 #endif
1551
1552
1553 fnpuvProcessEvent ();
1554
1555
1556
1557
1558 fnpProcessBuffers ();
1559
1560
1561 uint numunits = (uint) fnp_dev.numunits;
1562 for (uint fnp_unit_idx = 0; fnp_unit_idx < numunits; fnp_unit_idx ++)
1563 {
1564 if (! fnpData.fnpUnitData[fnp_unit_idx].fnpIsRunning)
1565 continue;
1566 int mbx = findMbx (fnp_unit_idx);
1567 if (mbx == -1)
1568 continue;
1569 bool need_intr = false;
1570 for (int lineno = 0; lineno < MAX_LINES; lineno ++)
1571 {
1572 struct t_line * linep = & fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno];
1573
1574 #if defined(DISC_DELAY)
1575
1576 if (linep -> line_disconnected > 1)
1577 {
1578
1579 if (linep->inBuffer && linep->inUsed < linep->inSize)
1580 {
1581
1582 linep -> line_disconnected = DISC_DELAY;
1583 }
1584 else
1585 {
1586
1587 -- linep -> line_disconnected;
1588 }
1589 }
1590 #endif
1591
1592
1593 if (linep->waitForMbxDone)
1594 continue;
1595
1596
1597
1598 bool do_send_output = linep->send_output == 1;
1599
1600 if (linep -> send_output > 0)
1601 linep->send_output --;
1602
1603 if (do_send_output)
1604 {
1605 fnp_rcd_send_output ((uint)mbx, (int) fnp_unit_idx, lineno);
1606 need_intr = true;
1607 }
1608
1609
1610
1611 else if (linep->acu_dial_failure)
1612 {
1613 fnp_rcd_acu_dial_failure ((uint)mbx, (int) fnp_unit_idx, lineno);
1614 linep->acu_dial_failure = false;
1615 need_intr = true;
1616 }
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626 else if (linep->listen && linep->accept_new_terminal)
1627 {
1628 fnp_rcd_accept_new_terminal ((uint)mbx, (int) fnp_unit_idx, lineno);
1629 linep->accept_new_terminal = false;
1630 need_intr = true;
1631 }
1632
1633
1634
1635 else if (linep -> ack_echnego_init)
1636 {
1637 fnp_rcd_ack_echnego_init ((uint)mbx, (int) fnp_unit_idx, lineno);
1638 linep -> ack_echnego_init = false;
1639 linep -> send_output = SEND_OUTPUT_DELAY;
1640 need_intr = true;
1641 }
1642
1643
1644
1645 else if (linep -> ack_echnego_stop)
1646 {
1647 fnp_rcd_ack_echnego_stop ((uint)mbx, (int) fnp_unit_idx, lineno);
1648 linep -> ack_echnego_stop = false;
1649 linep -> send_output = SEND_OUTPUT_DELAY;
1650 need_intr = true;
1651 }
1652
1653
1654
1655 #if defined(DISC_DELAY)
1656 else if (linep -> line_disconnected == 1)
1657 {
1658 fnp_rcd_line_disconnected ((uint)mbx, (int) fnp_unit_idx, lineno);
1659 linep -> line_disconnected = 0;
1660 linep -> listen = false;
1661 need_intr = true;
1662 }
1663 #else
1664 else if (linep -> line_disconnected)
1665 {
1666 fnp_rcd_line_disconnected ((uint)mbx, (int) fnp_unit_idx, lineno);
1667 linep -> line_disconnected = false;
1668 linep -> listen = false;
1669 need_intr = true;
1670 }
1671 #endif
1672
1673
1674
1675 else if (linep -> wru_timeout)
1676 {
1677 fnp_rcd_wru_timeout ((uint)mbx, (int) fnp_unit_idx, lineno);
1678 linep -> wru_timeout = false;
1679 need_intr = true;
1680 }
1681
1682
1683
1684 else if (linep->accept_input && ! linep->waitForMbxDone)
1685 {
1686 if (linep->accept_input == 1)
1687 {
1688
1689
1690
1691
1692 if (0 && linep->nPos == 0)
1693 {
1694 sim_printf ("dropping nPos of 0");
1695 }
1696 else
1697 {
1698
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 if (linep->force_accept_input || linep->nPos > 100)
1727 {
1728 fnp_rcd_accept_input ((uint)mbx, (int) fnp_unit_idx, lineno);
1729
1730 linep->input_reply_pending = true;
1731
1732 need_intr = true;
1733 }
1734 else
1735 {
1736 fnp_rcd_input_in_mailbox ((uint)mbx, (int) fnp_unit_idx, lineno);
1737 sim_debug (DBG_TRACE, & fnp_dev, "FNP input_in_mailbox\n");
1738 linep->nPos = 0;
1739
1740 need_intr = true;
1741 }
1742
1743 }
1744 }
1745 linep->accept_input --;
1746 }
1747
1748
1749
1750
1751
1752 else if (linep->line_break)
1753 {
1754 fnp_rcd_line_break ((uint)mbx, (int) fnp_unit_idx, lineno);
1755 linep -> line_break = false;
1756 need_intr = true;
1757 linep -> send_output = SEND_OUTPUT_DELAY;
1758 }
1759
1760 else if (linep->sendLineStatus)
1761 {
1762 linep->sendLineStatus = false;
1763 fnp_rcd_line_status ((uint)mbx, (int) fnp_unit_idx, lineno);
1764 need_intr = true;
1765 }
1766
1767 else
1768 {
1769 continue;
1770 }
1771
1772
1773
1774
1775 mbx = findMbx (fnp_unit_idx);
1776 if (mbx == -1)
1777 break;
1778 }
1779
1780
1781 if (need_intr)
1782 {
1783 uint ctlr_port_num = 0;
1784 uint iom_unit_idx = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].iom_unit_idx;
1785 uint chan_num = cables->fnp_to_iom[fnp_unit_idx][ctlr_port_num].chan_num;
1786 send_general_interrupt (iom_unit_idx, chan_num, imwTerminatePic);
1787 }
1788 }
1789
1790 #if defined(TUN)
1791 fnpTUNProcessEvent ();
1792 #endif
1793 fnp_process_3270_event ();
1794 }
1795
1796 static t_stat fnpShowNUnits (UNUSED FILE * st, UNUSED UNIT * uptr,
1797 UNUSED int val, UNUSED const void * desc)
1798 {
1799 sim_printf("Number of FNP units in system is %d\n", fnp_dev . numunits);
1800 return SCPE_OK;
1801 }
1802
1803 static t_stat fnpSetNUnits (UNUSED UNIT * uptr, UNUSED int32 value,
1804 const char * cptr, UNUSED void * desc)
1805 {
1806 if (! cptr)
1807 return SCPE_ARG;
1808 int n = atoi (cptr);
1809 if (n < 1 || n > N_FNP_UNITS_MAX)
1810 return SCPE_ARG;
1811 fnp_dev . numunits = (uint32) n;
1812
1813 return SCPE_OK;
1814 }
1815
1816 static t_stat fnpShowIPCname (UNUSED FILE * st, UNIT * uptr,
1817 UNUSED int val, UNUSED const void * desc)
1818 {
1819 long n = FNP_UNIT_IDX (uptr);
1820 if (n < 0 || n >= N_FNP_UNITS_MAX)
1821 return SCPE_ARG;
1822 sim_printf(" FNP IPC name: %s", fnpData.fnpUnitData [n] . ipcName);
1823 return SCPE_OK;
1824 }
1825
1826 static t_stat fnpSetIPCname (UNIT * uptr, UNUSED int32 value,
1827 UNUSED const char * cptr, UNUSED void * desc)
1828 {
1829 long n = FNP_UNIT_IDX (uptr);
1830 if (n < 0 || n >= N_FNP_UNITS_MAX)
1831 return SCPE_ARG;
1832 if (cptr)
1833 {
1834 strncpy (fnpData.fnpUnitData [n] . ipcName, cptr, MAX_DEV_NAME_LEN - 1);
1835 fnpData.fnpUnitData [n] . ipcName [MAX_DEV_NAME_LEN - 1] = 0;
1836 }
1837 else
1838 fnpData.fnpUnitData [n] . ipcName [0] = 0;
1839 return SCPE_OK;
1840 }
1841
1842 static t_stat fnpShowService (UNUSED FILE * st, UNIT * uptr,
1843 UNUSED int val, UNUSED const void * desc)
1844 {
1845 long devnum = FNP_UNIT_IDX (uptr);
1846 if (devnum < 0 || devnum >= N_FNP_UNITS_MAX)
1847 return SCPE_ARG;
1848 for (uint linenum = 0; linenum < MAX_LINES; linenum ++)
1849 {
1850 if (linenum == 0)
1851 sim_printf("\t");
1852 else
1853 sim_printf("\t\t");
1854 enum service_types st = fnpData.fnpUnitData[devnum].MState.line[linenum].service;
1855 switch (st)
1856 {
1857 case service_undefined:
1858 sim_printf("%c.%03d: undefined", (char)('a' + (int) devnum), linenum);
1859 break;
1860 case service_login:
1861 sim_printf("%c.%03d: login", (char)('a' + (int) devnum), linenum);
1862 break;
1863 case service_autocall:
1864 sim_printf("%c.%03d: autocall", (char)('a' + (int) devnum), linenum);
1865 break;
1866 case service_slave:
1867 sim_printf("%c.%03d: slave", (char)('a' + (int) devnum), linenum);
1868 break;
1869 default:
1870 sim_printf("%d.%03d: ERR (%u)", (char)('a' + (int) devnum), linenum, st);
1871 break;
1872 }
1873 if (linenum != (MAX_LINES - 1))
1874 sim_printf("\r\n");
1875 }
1876 return SCPE_OK;
1877 }
1878
1879 static t_stat fnpSetService (UNIT * uptr, UNUSED int32 value,
1880 const char * cptr, UNUSED void * desc)
1881 {
1882 if (! cptr)
1883 return SCPE_ARG;
1884 long devnum = FNP_UNIT_IDX (uptr);
1885 if (devnum < 0 || devnum >= N_FNP_UNITS_MAX)
1886 return SCPE_ARG;
1887
1888
1889 uint linenum;
1890 char sn [strlen (cptr)];
1891 int nr = sscanf (cptr, "%u=%s", & linenum, sn);
1892 if (nr != 2)
1893 return SCPE_ARG;
1894 if (linenum >= MAX_LINES)
1895 return SCPE_ARG;
1896 if (strcasecmp (sn, "undefined") == 0)
1897 fnpData.fnpUnitData[devnum].MState.line[linenum].service = service_undefined;
1898 else if (strcasecmp (sn, "login") == 0)
1899 fnpData.fnpUnitData[devnum].MState.line[linenum].service = service_login;
1900 else if (strcmp (sn, "ibm3270") == 0)
1901 {
1902 fnpData.fnpUnitData[devnum].MState.line[linenum].service = service_3270;
1903 fnpData.ibm3270ctlr[ASSUME0].fnpno = (uint) devnum;
1904 fnpData.ibm3270ctlr[ASSUME0].lineno = linenum;
1905 }
1906 else if (strcasecmp (sn, "autocall") == 0)
1907 fnpData.fnpUnitData[devnum].MState.line[linenum].service = service_autocall;
1908 else if (strncasecmp (sn, "slave=", 6) == 0)
1909 {
1910 uint pn;
1911 int nr2 = sscanf (sn, "slave=%u", & pn);
1912 if (nr2 != 1)
1913 return SCPE_ARG;
1914 if (pn >= 65535)
1915 return SCPE_ARG;
1916 fnpData.fnpUnitData[devnum].MState.line[linenum].service = service_slave;
1917 fnpData.fnpUnitData[devnum].MState.line[linenum].port = (int) pn;
1918 }
1919 else
1920 return SCPE_ARG;
1921 return SCPE_OK;
1922 }
1923
1924 static t_stat fnpShowConfig (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
1925 UNUSED const void * desc)
1926 {
1927 #if defined(TESTING)
1928 cpu_state_t * cpup = _cpup;
1929 #endif
1930 long fnpUnitIdx = FNP_UNIT_IDX (uptr);
1931 if (fnpUnitIdx >= (long) N_FNP_UNITS_MAX)
1932 {
1933 sim_debug (DBG_ERR, & fnp_dev,
1934 "fnpShowConfig: Invalid unit number %ld\n", (long) fnpUnitIdx);
1935 sim_printf ("error: Invalid unit number %ld\n", (long) fnpUnitIdx);
1936 return SCPE_ARG;
1937 }
1938
1939 sim_printf ("FNP unit number %ld\n", (long) fnpUnitIdx);
1940 struct fnpUnitData_s * fudp = fnpData.fnpUnitData + fnpUnitIdx;
1941
1942 sim_printf ("FNP mailbox address: %04o(8)\n", fudp -> mailboxAddress);
1943
1944 return SCPE_OK;
1945 }
1946
1947
1948
1949
1950 int n_fw_entries = 0;
1951 struct fw_entry_s fw_entries [N_FW_ENTRIES];
1952
1953
1954
1955
1956 static int parse_line (char * line)
1957 {
1958 char fnp = line[0];
1959 if (fnp < 'A' || fnp > 'H')
1960 return -1;
1961 int fnpno = fnp - 'A';
1962
1963 if (line [1] != '.')
1964 return -2;
1965
1966 if (line[2] != 'H')
1967 return -3;
1968
1969 if (line[3] < '0' || line[3] > '9')
1970 return -4;
1971
1972 if (line[4] < '0' || line[4] > '9')
1973 return -5;
1974
1975 if (line[5] < '0' || line[5] > '9')
1976 return -6;
1977 int lineno = (line[3] - '0') * 100 +
1978 (line[4] - '0') * 10 +
1979 (line[5] - '0');
1980
1981 if (line[6] != 0 && line[6] != '-')
1982 return -7;
1983
1984 return encodeline (fnpno, lineno);
1985
1986 }
1987
1988
1989 static int parse_ipaddr (char * str, uint32_t * addr)
1990 {
1991 char * end1, * end2, * end3, * end4;
1992
1993 unsigned long o1 = strtoul (str, & end1, 10);
1994 if (end1 == str || * end1 != '.' || o1 > 255)
1995 return -1;
1996
1997 unsigned long o2 = strtoul (end1 + 1, & end2, 10);
1998 if (end2 == end1 || * end2 != '.' || o2 > 255)
1999 return -2;
2000
2001 unsigned long o3 = strtoul (end2 + 1, & end3, 10);
2002 if (end3 == end2 || * end3 != '.' || o3 > 255)
2003 return -3;
2004
2005 unsigned long o4 = strtoul (end3 + 1, & end4, 10);
2006 if (end4 == end3 || * end4 != 0 || o4 > 255)
2007 return -4;
2008 * addr = (uint32_t) ((o1 << 24) | (o2 << 16) | (o3 << 8) | o4);
2009 return 0;
2010 }
2011
2012 static t_stat fnpSetFW (UNIT * uptr, UNUSED int32 value,
2013 const char * cptr, UNUSED void * desc)
2014 {
2015 if (! cptr)
2016 return SCPE_ARG;
2017 long devnum = FNP_UNIT_IDX (uptr);
2018 if (devnum < 0 || devnum >= N_FNP_UNITS_MAX)
2019 return SCPE_ARG;
2020
2021 char sn [strlen (cptr) + 1];
2022 memcpy (sn, cptr, strlen (cptr) + 1);
2023 char * saveptr;
2024 char * tok;
2025
2026
2027 tok = strtok_r (sn, ":", & saveptr);
2028 if (strcasecmp (tok, "RESET") == 0)
2029 {
2030 n_fw_entries = 0;
2031 sim_printf ("FNP firewall table reset\r\n");
2032 return SCPE_OK;
2033 }
2034
2035 if (strcasecmp (tok, "ADD") == 0)
2036 {
2037 if (n_fw_entries >= N_FW_ENTRIES)
2038 {
2039 sim_printf ("FNP firewall table full\r\n");
2040 return SCPE_ARG;
2041 }
2042
2043 int line_0, line_1;
2044
2045 tok = strtok_r (NULL, ":", & saveptr);
2046 char * dash = strchr (tok, '-');
2047 if (dash)
2048 {
2049 line_0 = parse_line (tok);
2050 if (line_0 < 0)
2051 {
2052 sim_printf ("Cannot parse first line number\r\n");
2053 return SCPE_ARG;
2054 }
2055
2056 line_1 = parse_line (dash + 1);
2057 if (line_1 < 0)
2058 {
2059 sim_printf ("Cannot parse second line number\r\n");
2060 return SCPE_ARG;
2061 }
2062 if (line_0 > line_1)
2063 {
2064 sim_printf ("line_0 > line_1\r\n");
2065 return SCPE_ARG;
2066 }
2067
2068 }
2069 else
2070 {
2071 line_0 = line_1 = parse_line (tok);
2072 if (line_0 < 0)
2073 {
2074 sim_printf ("Cannot parse line number\r\n");
2075 return SCPE_ARG;
2076 }
2077 }
2078
2079
2080
2081 tok = strtok_r (NULL, ":", & saveptr);
2082 uint32_t ipaddr;
2083 int rc = parse_ipaddr (tok, & ipaddr);
2084 if (rc < 0)
2085 return SCPE_ARG;
2086
2087
2088
2089 tok = strtok_r (NULL, ":", & saveptr);
2090 char * end;
2091 unsigned long cidr = strtoul (tok, & end, 10);
2092 if (tok == end || * end != 0 || cidr > 32)
2093 return SCPE_OK;
2094 uint32_t cidr_mask = ((uint32_t)-1) << (32-cidr) & MASK32;
2095
2096
2097
2098 bool accept = false;
2099 tok = strtok_r (NULL, ":", & saveptr);
2100 if (strcmp (tok, "ACCEPT") == 0)
2101 accept = true;
2102 else if (strcmp (tok, "DENY") == 0)
2103 accept = false;
2104 else
2105 {
2106 sim_printf ("cannot parse rule ACCEPT/DENY\r\n");
2107 return SCPE_ARG;
2108 }
2109
2110 fw_entries[n_fw_entries].line_0 = (uint) line_0;
2111 fw_entries[n_fw_entries].line_1 = (uint) line_1;
2112 fw_entries[n_fw_entries].ipaddr = ipaddr;
2113 fw_entries[n_fw_entries].cidr = (uint) cidr;
2114 fw_entries[n_fw_entries].cidr_mask = (uint) cidr_mask;
2115 fw_entries[n_fw_entries].accept = accept;
2116 n_fw_entries ++;
2117
2118 return SCPE_OK;
2119 }
2120
2121 if (strcasecmp (tok, "LIST") == 0)
2122 {
2123 for (int i = 0; i < n_fw_entries; i ++)
2124 {
2125 struct fw_entry_s * p = fw_entries + i;
2126
2127 if (p->line_0 == p->line_1)
2128 {
2129 sim_printf (" %c.h%03d %d.%d.%d.%d/%d %s\r\n",
2130 decodefnp (p->line_0) + 'a',
2131 decodeline (p->line_0),
2132 (p->ipaddr>>24) & 255,
2133 (p->ipaddr>>16) & 255,
2134 (p->ipaddr>>8) & 255,
2135 p->ipaddr & 255,
2136 p->cidr,
2137 p->accept ? "accept" : "deny");
2138 }
2139 else
2140 {
2141 sim_printf (" %c.h%03d-%c.%03d %d.%d.%d.%d/%d %s\r\n",
2142 decodefnp (p->line_0) + 'a',
2143 decodeline (p->line_0),
2144 decodefnp (p->line_1) + 'a',
2145 decodeline (p->line_1),
2146 (p->ipaddr>>24) & 255,
2147 (p->ipaddr>>16) & 255,
2148 (p->ipaddr>>8) & 255,
2149 p->ipaddr & 255,
2150 p->cidr,
2151 p->accept ? "accept" : "deny");
2152 }
2153 }
2154 return SCPE_OK;
2155 }
2156
2157 return SCPE_ARG;
2158 }
2159
2160 static t_stat fnpShowFW (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
2161 UNUSED const void * desc)
2162 {
2163 #if defined(TESTING)
2164 cpu_state_t * cpup = _cpup;
2165 #endif
2166 long fnpUnitIdx = FNP_UNIT_IDX (uptr);
2167 if (fnpUnitIdx >= (long) N_FNP_UNITS_MAX)
2168 {
2169 sim_debug (DBG_ERR, & fnp_dev,
2170 "fnpShowConfig: Invalid unit number %ld\n",
2171 (long) fnpUnitIdx);
2172 sim_printf ("error: Invalid unit number %ld\n",
2173 (long) fnpUnitIdx);
2174 return SCPE_ARG;
2175 }
2176
2177
2178
2179
2180
2181
2182
2183 return SCPE_OK;
2184 }
2185
2186 static t_stat fnpShowStatus (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
2187 UNUSED const void * desc)
2188 {
2189 #if defined(TESTING)
2190 cpu_state_t * cpup = _cpup;
2191 #endif
2192 long fnpUnitIdx = FNP_UNIT_IDX (uptr);
2193 if (fnpUnitIdx >= (long) fnp_dev.numunits)
2194 {
2195 sim_debug (DBG_ERR, & fnp_dev,
2196 "fnpShowStatus: Invalid unit number %ld\n",
2197 (long) fnpUnitIdx);
2198 sim_printf ("error: Invalid unit number %ld\n",
2199 (long) fnpUnitIdx);
2200 return SCPE_ARG;
2201 }
2202
2203 sim_printf ("FNP unit number %ld:\n", (long) fnpUnitIdx);
2204 struct fnpUnitData_s * fudp = fnpData.fnpUnitData + fnpUnitIdx;
2205
2206 sim_printf ("\tmailboxAddress: %04o\n",
2207 fudp->mailboxAddress);
2208 sim_printf ("\tfnpIsRunning: %o\n",
2209 fudp->fnpIsRunning);
2210 sim_printf ("\tfnpMBXinUse: %o %o %o %o\n",
2211 fudp->fnpMBXinUse[0], fudp->fnpMBXinUse[1],
2212 fudp->fnpMBXinUse[2], fudp->fnpMBXinUse[3]);
2213 sim_printf ("\tlineWaiting: %o %o %o %o\n",
2214 fudp->lineWaiting[0], fudp->lineWaiting[1],
2215 fudp->lineWaiting[2], fudp->lineWaiting[3]);
2216 sim_printf ("\tfnpMBXlineno: %o %o %o %o\n",
2217 fudp->fnpMBXlineno[0], fudp->fnpMBXlineno[1],
2218 fudp->fnpMBXlineno[2], fudp->fnpMBXlineno[3]);
2219 sim_printf ("\taccept_calls: %o\n",
2220 fudp->MState.accept_calls);
2221 for (int l = 0; l < MAX_LINES; l ++)
2222 {
2223 sim_printf (" line %d:\n", l);
2224 sim_printf ("\tservice: %d\n",
2225 fudp->MState.line[l].service);
2226 sim_printf ("\tline_client: %p\n",
2227 (void *) fudp->MState.line[l].line_client);
2228 sim_printf ("\twas_CR: %d\n",
2229 fudp->MState.line[l].was_CR);
2230 sim_printf ("\tlisten: %d\n",
2231 fudp->MState.line[l].listen);
2232 sim_printf ("\tinputBufferSize: %d\n",
2233 fudp->MState.line[l].inputBufferSize);
2234 sim_printf ("\tline_break: %d\n",
2235 fudp->MState.line[l].line_break);
2236 sim_printf ("\tsend_output: %d\n",
2237 fudp->MState.line[l].send_output);
2238 sim_printf ("\taccept_new_terminal: %d\n",
2239 fudp->MState.line[l].accept_new_terminal);
2240 #if DISC_DELAY
2241 sim_printf ("\tline_disconnected: %d\n",
2242 fudp->MState.line[l].line_disconnected);
2243 #else
2244 sim_printf ("\tline_disconnected: %c\n",
2245 fudp->MState.line[l].line_disconnected ? 'T' : 'F');
2246 #endif
2247 sim_printf ("\tacu_dial_failure: %d\n",
2248 fudp->MState.line[l].acu_dial_failure);
2249 sim_printf ("\taccept_input: %d\n",
2250 fudp->MState.line[l].accept_input);
2251 sim_printf ("\twaitForMbxDone: %d\n",
2252 fudp->MState.line[l].waitForMbxDone);
2253 sim_printf ("\tinput_reply_pending: %d\n",
2254 fudp->MState.line[l].input_reply_pending);
2255 sim_printf ("\tinput_break: %d\n",
2256 fudp->MState.line[l].input_break);
2257 sim_printf ("\tnPos: %d\n",
2258 fudp->MState.line[l].nPos);
2259 sim_printf ("\tinBuffer: %p\n",
2260 (void *) fudp->MState.line[l].inBuffer);
2261 sim_printf ("\tinSize: %d\n",
2262 fudp->MState.line[l].inSize);
2263 sim_printf ("\tinUsed: %d\n",
2264 fudp->MState.line[l].inUsed);
2265
2266
2267
2268
2269 sim_printf ("\tport: %d\n",
2270 fudp->MState.line[l].port);
2271
2272 }
2273 return SCPE_OK;
2274 }
2275
2276 static t_stat fnp_show_device_name (UNUSED FILE * st, UNIT * uptr,
2277 UNUSED int val, UNUSED const void * desc)
2278 {
2279 int n = (int) FNP_UNIT_IDX (uptr);
2280 if (n < 0 || n >= N_FNP_UNITS_MAX)
2281 return SCPE_ARG;
2282 if (fnpData.fnpUnitData[n].device_name[0] != 0)
2283 sim_printf(" name: %s", fnpData.fnpUnitData[n].device_name);
2284 else
2285 sim_printf(" name: default");
2286 return SCPE_OK;
2287 }
2288
2289 static t_stat fnp_set_device_name (UNIT * uptr, UNUSED int32 value,
2290 const char * cptr, UNUSED void * desc)
2291 {
2292 int n = (int) FNP_UNIT_IDX (uptr);
2293 if (n < 0 || n >= N_FNP_UNITS_MAX)
2294 return SCPE_ARG;
2295 if (cptr)
2296 {
2297 strncpy (fnpData.fnpUnitData[n].device_name, cptr, MAX_DEV_NAME_LEN-1);
2298 fnpData.fnpUnitData[n].device_name[MAX_DEV_NAME_LEN-1] = 0;
2299 }
2300 else
2301 fnpData.fnpUnitData[n].device_name[0] = 0;
2302 return SCPE_OK;
2303 }
2304
2305 static config_list_t fnp_config_list [] =
2306 {
2307 { "mailbox", 0, 07777, NULL },
2308 { NULL, 0, 0, NULL }
2309 };
2310
2311 static t_stat fnpSetConfig (UNIT * uptr, UNUSED int value, const char * cptr, UNUSED void * desc)
2312 {
2313 #if defined(TESTING)
2314 cpu_state_t * cpup = _cpup;
2315 #endif
2316 uint fnpUnitIdx = (uint) FNP_UNIT_IDX (uptr);
2317
2318 if (fnpUnitIdx >= N_FNP_UNITS_MAX)
2319 {
2320 sim_debug (DBG_ERR, & fnp_dev, "fnpSetConfig: Invalid unit number %ld\n", (long) fnpUnitIdx);
2321 sim_printf ("error: fnpSetConfig: Invalid unit number %ld\n", (long) fnpUnitIdx);
2322 return SCPE_ARG;
2323 }
2324
2325 struct fnpUnitData_s * fudp = fnpData.fnpUnitData + fnpUnitIdx;
2326
2327 config_state_t cfg_state = { NULL, NULL };
2328
2329 for (;;)
2330 {
2331 int64_t v;
2332 int rc = cfg_parse ("fnpSetConfig", cptr, fnp_config_list, & cfg_state, & v);
2333 switch (rc)
2334 {
2335 case -2:
2336 cfg_parse_done (& cfg_state);
2337 return SCPE_ARG;
2338
2339 case -1:
2340 break;
2341
2342 case 0:
2343 fudp -> mailboxAddress = (uint) v;
2344 break;
2345
2346 default:
2347 sim_printf ("error: fnpSetConfig: Invalid cfg_parse rc <%ld>\n", (long) rc);
2348 cfg_parse_done (& cfg_state);
2349 return SCPE_ARG;
2350 }
2351 if (rc < 0)
2352 break;
2353 }
2354 cfg_parse_done (& cfg_state);
2355 return SCPE_OK;
2356 }
2357
2358
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 t_stat set_fnp_server_port (UNUSED int32 arg, const char * buf)
2459 {
2460 if (fnpData.du_server_inited)
2461 {
2462 sim_printf ("[FNP emulation: TELNET server port error: FNP already initialized]\n");
2463 return SCPE_INCOMP;
2464 }
2465 if (! buf)
2466 return SCPE_ARG;
2467 int n = atoi (buf);
2468 if (n < 1 || n > 65535)
2469 return SCPE_ARG;
2470 fnpData.telnet_port = n;
2471 if (!sim_quiet)
2472 {
2473 sim_printf ("[FNP emulation: TELNET server port set to %ld]\n", (long) n);
2474 }
2475 return SCPE_OK;
2476 }
2477
2478 t_stat set_fnp_server_address (UNUSED int32 arg, const char * buf)
2479 {
2480 if (fnpData.du_server_inited)
2481 {
2482 sim_printf ("[FNP emulation: FNP server address error: FNP already initialized]\n");
2483 return SCPE_INCOMP;
2484 }
2485 if ( (!buf) || (buf[0] == 0) )
2486 return SCPE_ARG;
2487 if (fnpData.telnet_address)
2488 FREE (fnpData.telnet_address);
2489 fnpData.telnet_address = strdup (buf);
2490 if (!fnpData.telnet_address)
2491 {
2492 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2493 __func__, __FILE__, __LINE__);
2494 #if defined(USE_BACKTRACE)
2495 # if defined(SIGUSR2)
2496 (void)raise(SIGUSR2);
2497
2498 # endif
2499 #endif
2500 abort();
2501 }
2502 if (!sim_quiet)
2503 {
2504 sim_printf ("[FNP emulation: FNP server address set to %s]\n", fnpData.telnet_address);
2505 }
2506 return SCPE_OK;
2507 }
2508
2509 t_stat set_fnp_3270_server_port (UNUSED int32 arg, const char * buf)
2510 {
2511
2512 if ( (fnpData.du3270_server_inited) || (fnpData.du_server_inited) )
2513 {
2514 sim_printf ("[FNP emulation: TN3270 server port error: FNP already initialized]\n");
2515 return SCPE_INCOMP;
2516 }
2517 if (! buf)
2518 return SCPE_ARG;
2519 int n = atoi (buf);
2520 if (n < 1 || n > 65535)
2521 return SCPE_ARG;
2522 fnpData.telnet3270_port = n;
2523 if (!sim_quiet)
2524 {
2525 sim_printf ("[FNP emulation: TN3270 server port set to %ld]\n", (long) n);
2526 }
2527 return SCPE_OK;
2528 }
2529
2530 t_stat fnp_start (UNUSED int32 arg, UNUSED const char * buf)
2531 {
2532 int rc = 0;
2533 rc = fnpuvInit (fnpData.telnet_port, fnpData.telnet_address);
2534 if (rc != 0)
2535 return SCPE_INCOMP;
2536
2537
2538
2539 return SCPE_OK;
2540 }
2541
2542 #define PROMPT "HSLA Port ("
2543
2544 void fnpConnectPrompt (uv_tcp_t * client)
2545 {
2546 fnpuv_start_writestr (client, (unsigned char *) PROMPT);
2547 bool first = true;
2548 uint numunits = (uint) fnp_dev.numunits;
2549 for (uint fnp_unit_idx = 0; fnp_unit_idx < numunits; fnp_unit_idx ++)
2550 {
2551 if (! fnpData.fnpUnitData[fnp_unit_idx].fnpIsRunning)
2552 continue;
2553 for (uint lineno = 0; lineno < MAX_LINES; lineno ++)
2554 {
2555 struct t_line * linep = & fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno];
2556 if (! linep->listen)
2557 continue;
2558 if (linep->service == service_login &&
2559 ! linep->line_disconnected &&
2560 ! linep->line_client &&
2561 fnpData.fnpUnitData[fnp_unit_idx].MState.accept_calls)
2562 {
2563 if (! first)
2564 fnpuv_start_writestr (client, (unsigned char *) ",");
2565 char name [16];
2566 first = false;
2567 (void)sprintf (name, "%c.h%03d", 'a' + fnp_unit_idx, lineno);
2568 fnpuv_start_writestr (client, (unsigned char *) name);
2569 }
2570 }
2571 }
2572 fnpuv_start_writestr (client, (unsigned char *) ")? ");
2573 }
2574
2575
2576
2577
2578
2579 const unsigned char a2e[256] = {
2580 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
2581 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
2582 64, 79, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
2583 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
2584 124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
2585 215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 74, 224, 90, 95, 109,
2586 121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
2587 151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 106, 208, 161, 7,
2588 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
2589 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62, 225,
2590 65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87,
2591 88, 89, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, 115, 116, 117,
2592 118, 119, 120, 128, 138, 139, 140, 141, 142, 143, 144, 154, 155, 156, 157, 158,
2593 159, 160, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
2594 184, 185, 186, 187, 188, 189, 190, 191, 202, 203, 204, 205, 206, 207, 218, 219,
2595 220, 221, 222, 223, 234, 235, 236, 237, 238, 239, 250, 251, 252, 253, 254, 255
2596 };
2597
2598 const unsigned char e2a[256] = {
2599 0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
2600 16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
2601 128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
2602 144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
2603 32, 160, 161, 162, 163, 164, 165, 166, 167, 168, 91, 46, 60, 40, 43, 33,
2604 38, 169, 170, 171, 172, 173, 174, 175, 176, 177, 93, 36, 42, 41, 59, 94,
2605 45, 47, 178, 179, 180, 181, 182, 183, 184, 185, 124, 44, 37, 95, 62, 63,
2606 186, 187, 188, 189, 190, 191, 192, 193, 194, 96, 58, 35, 64, 39, 61, 34,
2607 195, 97, 98, 99, 100, 101, 102, 103, 104, 105, 196, 197, 198, 199, 200, 201,
2608 202, 106, 107, 108, 109, 110, 111, 112, 113, 114, 203, 204, 205, 206, 207, 208,
2609 209, 126, 115, 116, 117, 118, 119, 120, 121, 122, 210, 211, 212, 213, 214, 215,
2610 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
2611 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 232, 233, 234, 235, 236, 237,
2612 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 238, 239, 240, 241, 242, 243,
2613 92, 159, 83, 84, 85, 86, 87, 88, 89, 90, 244, 245, 246, 247, 248, 249,
2614 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 250, 251, 252, 253, 254, 255
2615 };
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629 static void fnp3270Msg (uv_tcp_t * client, unsigned char * msg)
2630 {
2631
2632 size_t l = strlen ((char *) msg);
2633 unsigned char buf [l];
2634 for (uint i = 0; i < l; i ++)
2635 buf[i] = a2e[msg[i]];
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645 unsigned char EW [] = {245, 0xc3, 17, 64, 64 };
2646 fnpuv_start_3270_write (client, EW, sizeof (EW));
2647 fnpuv_start_3270_write (client, buf, (ssize_t) l);
2648 fnpuv_send_eor (client);
2649 }
2650
2651 void fnp3270ConnectPrompt (uv_tcp_t * client)
2652 {
2653 if (! client || ! client->data)
2654 {
2655 sim_warn ("fnp3270ConnectPrompt bad client data\r\n");
2656 return;
2657 }
2658 uint fnpno = fnpData.ibm3270ctlr[ASSUME0].fnpno;
2659 uint lineno = fnpData.ibm3270ctlr[ASSUME0].lineno;
2660
2661 uvClientData * p = client->data;
2662 p->assoc = true;
2663 p->fnpno = fnpno;
2664 p->lineno = lineno;
2665
2666
2667
2668
2669
2670 unsigned char buf [256];
2671 (void)sprintf ((char *) buf, "DPS8/M 3270 connection to %c.%03d.%ld ttype %s\n",
2672 fnpno+'a',lineno, (long)p->stationNo, p->ttype);
2673 fnpData.ibm3270ctlr[ASSUME0].selDevChar = addr_map[p->stationNo];
2674 fnp3270Msg (client, buf);
2675
2676 }
2677
2678 void processLineInput (uv_tcp_t * client, unsigned char * buf, ssize_t nread)
2679 {
2680 if (! client || ! client->data)
2681 {
2682 sim_warn ("processLineInput bad client data\r\n");
2683 return;
2684 }
2685 uvClientData * p = (uvClientData *) client->data;
2686 uint fnpno = p -> fnpno;
2687 uint lineno = p -> lineno;
2688 if (fnpno >= N_FNP_UNITS_MAX || lineno >= MAX_LINES)
2689 {
2690 sim_printf ("bogus client data\n");
2691 return;
2692 }
2693
2694
2695
2696
2697
2698
2699
2700 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
2701
2702
2703
2704
2705
2706
2707
2708 if (linep->inBuffer)
2709 {
2710 sim_warn ("inBuffer overrun\n");
2711 unsigned char * new = realloc (linep->inBuffer, (unsigned long) (linep->inSize + nread));
2712 if (! new)
2713 {
2714 sim_warn ("inBuffer realloc fail; dropping data\n");
2715 goto done;
2716 }
2717 memcpy (new + linep->inSize, buf, (unsigned long) nread);
2718 linep->inSize += nread;
2719 linep->inBuffer = new;
2720 }
2721 else
2722 {
2723 linep->inBuffer = malloc ((unsigned long) nread);
2724 if (! linep->inBuffer)
2725 {
2726 sim_warn ("inBuffer malloc fail; dropping data\n");
2727 goto done;
2728 }
2729 memcpy (linep->inBuffer, buf, (unsigned long) nread);
2730 linep->inSize = (uint) nread;
2731 linep->inUsed = 0;
2732 }
2733
2734 done:;
2735
2736 fnpuv_read_stop (client);
2737 }
2738
2739 void process3270Input (uv_tcp_t * client, unsigned char * buf, ssize_t nread)
2740 {
2741 #if defined(TESTING)
2742 cpu_state_t * cpup = _cpup;
2743 #endif
2744 if (! client || ! client->data)
2745 {
2746 sim_warn ("process3270Input bad client data\r\n");
2747 return;
2748 }
2749 uvClientData * p = (uvClientData *) client->data;
2750 uint fnpno = p->fnpno;
2751 uint lineno = p->lineno;
2752 uint stn_no = p->stationNo;
2753
2754 if (fnpno >= N_FNP_UNITS_MAX || lineno >= MAX_LINES)
2755 {
2756 sim_printf ("bogus client data\n");
2757 return;
2758 }
2759 if_sim_debug (DBG_TRACE, & fnp_dev) {
2760 sim_debug (DBG_TRACE, & fnp_dev, "process3270Input nread %ld\n", (long)nread);
2761 for (int i = 0; i < nread; i ++) sim_debug (DBG_TRACE, & fnp_dev, "%c", isgraph (e2a[buf[i]]) ? e2a[buf[i]] : '.');
2762 sim_debug (DBG_TRACE, & fnp_dev, "\r\n");
2763 for (int i = 0; i < nread; i ++) sim_debug (DBG_TRACE, & fnp_dev, " %02x", buf[i]);
2764 sim_debug (DBG_TRACE, & fnp_dev, "\r\n");
2765 }
2766
2767 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
2768 if (! fnpData.fnpUnitData[fnpno].MState.accept_calls)
2769 {
2770 if (! linep->inBuffer)
2771 fnp3270Msg (client, (unsigned char *) "Multics is not accepting calls\r\n");
2772 return;
2773 }
2774 if (! linep->listen)
2775 {
2776 if (! linep->inBuffer)
2777 fnp3270Msg (client, (unsigned char *) "Multics is not listening to this line\r\n");
2778 return;
2779 }
2780
2781
2782
2783
2784
2785
2786
2787
2788 struct station_s * stn_p = & fnpData.ibm3270ctlr[ASSUME0].stations[stn_no];
2789 if (stn_p->stn_in_buffer)
2790 {
2791 sim_warn ("stn_in_buffer overrun\n");
2792 unsigned char * new = realloc (stn_p->stn_in_buffer, (unsigned long) (stn_p->stn_in_size + nread));
2793 if (! new)
2794 {
2795 sim_warn ("stn_in_buffer realloc fail; dropping data\n");
2796 goto done;
2797 }
2798 memcpy (new + stn_p->stn_in_size, buf, (unsigned long) nread);
2799 stn_p->stn_in_size += nread;
2800 stn_p->stn_in_buffer = new;
2801 }
2802 else
2803 {
2804 stn_p->stn_in_buffer = malloc ((unsigned long) nread);
2805 if (! stn_p->stn_in_buffer)
2806 {
2807 sim_warn ("stn_in_buffer malloc fail; dropping data\n");
2808 goto done;
2809 }
2810 memcpy (stn_p->stn_in_buffer, buf, (unsigned long) nread);
2811 stn_p->stn_in_size = (uint) nread;
2812 stn_p->stn_in_used = 0;
2813 }
2814
2815 sim_debug (DBG_TRACE, & fnp_dev,
2816 "process3270Input stashed %lu bytes in stn %u; stn_in_size now %u\n",
2817 (unsigned long)nread, stn_no, stn_p->stn_in_size);
2818 done:;
2819
2820
2821
2822 }
2823
2824 void reset_line (struct t_line * linep)
2825 {
2826 linep->was_CR = false;
2827 linep->inputBufferSize = 0;
2828 linep->ctrlStrIdx = 0;
2829 linep->breakAll = false;
2830 linep->handleQuit = false;
2831 linep->echoPlex = false;
2832 linep->crecho = false;
2833 linep->lfecho = false;
2834 linep->tabecho = false;
2835 linep->replay = false;
2836 linep->polite = false;
2837 linep->prefixnl = false;
2838 linep->eight_bit_out = false;
2839 linep->eight_bit_in = false;
2840 linep->odd_parity = false;
2841 linep->output_flow_control = false;
2842 linep->input_flow_control = false;
2843 linep->block_xfer_in_frame_sz = 0;
2844 linep->block_xfer_out_frame_sz = 0;
2845 (void)memset (linep->delay_table, 0, sizeof (linep->delay_table));
2846 linep->inputSuspendLen = 0;
2847 (void)memset (linep->inputSuspendStr, 0, sizeof (linep->inputSuspendStr));
2848 linep->inputResumeLen = 0;
2849 (void)memset (linep->inputResumeStr, 0, sizeof (linep->inputResumeStr));
2850 linep->outputSuspendLen = 0;
2851 (void)memset (linep->outputSuspendStr, 0, sizeof (linep->outputSuspendStr));
2852 linep->outputResumeLen = 0;
2853 (void)memset (linep->outputResumeStr, 0, sizeof (linep->outputResumeStr));
2854 linep->frame_begin = 0;
2855 linep->frame_end = 0;
2856 (void)memset (linep->echnego_break_table, 0, sizeof (linep->echnego_break_table));
2857 linep->echnego_sync_ctr = 0;
2858 linep->echnego_screen_left = 0;
2859 linep->echnego_unechoed_cnt = 0;
2860 linep->echnego_on = false;
2861 linep->echnego_synced = false;
2862 linep->line_break = false;
2863 }
2864
2865 void processUserInput (uv_tcp_t * client, unsigned char * buf, ssize_t nread)
2866 {
2867 if (! client || ! client->data)
2868 {
2869 sim_warn ("processUserInput bad client data\r\n");
2870 return;
2871 }
2872 uvClientData * p = (uvClientData *) client->data;
2873 for (ssize_t nchar = 0; nchar < nread; nchar ++)
2874 {
2875 unsigned char kar = buf [nchar];
2876
2877 if (kar == 0x1b || kar == 0x03)
2878 {
2879 close_connection ((uv_stream_t *) client);
2880 return;
2881 }
2882
2883
2884 if (p->nPos >= sizeof(p->buffer) - 1)
2885 {
2886
2887 switch (kar)
2888 {
2889 case '\b':
2890 case 127:
2891 {
2892 if (p->nPos)
2893 {
2894 fnpuv_start_writestr (client, (unsigned char *) "\b \b");
2895
2896 p->buffer[p->nPos] = 0;
2897 p->nPos -= 1;
2898 }
2899 }
2900 break;
2901
2902 case '\n':
2903 case '\r':
2904 {
2905 p->buffer[p->nPos] = 0;
2906 goto check;
2907 }
2908
2909 case 0x12:
2910 {
2911 fnpuv_start_writestr (client, (unsigned char *) "^R\r\n");
2912 fnpConnectPrompt (client);
2913 fnpuv_start_writestr (client, (unsigned char *) p->buffer);
2914 }
2915 break;
2916
2917 default:
2918 break;
2919 }
2920 continue;
2921 }
2922
2923 if (isprint (kar))
2924 {
2925 unsigned char str [2] = { kar, 0 };
2926 fnpuv_start_writestr (client, str);
2927 p->buffer[p->nPos++] = (char) kar;
2928 }
2929 else
2930 {
2931 switch (kar)
2932 {
2933 case '\b':
2934 case 127:
2935 {
2936 if (p->nPos)
2937 {
2938 fnpuv_start_writestr (client, (unsigned char *) "\b \b");
2939
2940 p->buffer[p->nPos] = 0;
2941 p->nPos -= 1;
2942 }
2943 }
2944 break;
2945
2946 case '\n':
2947 case '\r':
2948 {
2949 p->buffer[p->nPos] = 0;
2950 goto check;
2951 }
2952
2953 case 0x12:
2954 {
2955 fnpuv_start_writestr (client, (unsigned char *) "^R\r\n");
2956 fnpConnectPrompt (client);
2957 fnpuv_start_writestr (client, (unsigned char *) p->buffer);
2958 }
2959 break;
2960
2961 default:
2962 break;
2963 }
2964 }
2965 }
2966 return;
2967
2968 check:;
2969 char cpy [p->nPos + 1];
2970 memcpy (cpy, p->buffer, p->nPos);
2971 cpy [p->nPos] = 0;
2972 trim (cpy);
2973 sim_printf ("<%s>", cpy);
2974 p->nPos = 0;
2975 fnpuv_start_writestr (client, (unsigned char *) "\r\n");
2976
2977 uint fnp_unit_idx = 0;
2978 uint lineno = 0;
2979
2980 if (strlen (cpy))
2981 {
2982 char fnpcode;
2983 int cnt = sscanf (cpy, "%c.h%u", & fnpcode, & lineno);
2984
2985 if (cnt != 2 || fnpcode < 'a' || fnpcode > 'h' || lineno >= MAX_LINES)
2986 {
2987 fnpuv_start_writestr (client, (unsigned char *) "can't parse\r\n");
2988 goto reprompt;
2989 }
2990 fnp_unit_idx = (uint) (fnpcode - 'a');
2991 if (fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].service != service_login ||
2992 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_client)
2993 {
2994 fnpuv_start_writestr (client, (unsigned char *) "not available\r\n");
2995 goto reprompt;
2996 }
2997 goto associate;
2998 }
2999 else
3000 {
3001 uint32 numunits = fnp_dev.numunits;
3002 for (fnp_unit_idx = 0; fnp_unit_idx < numunits; fnp_unit_idx ++)
3003 {
3004 if (! fnpData.fnpUnitData[fnp_unit_idx].fnpIsRunning)
3005 continue;
3006 for (lineno = 0; lineno < MAX_LINES; lineno ++)
3007 {
3008 if (fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].service == service_login &&
3009 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].listen &&
3010 ! fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_disconnected &&
3011 ! fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_client &&
3012 fnpData.fnpUnitData[fnp_unit_idx].MState.accept_calls)
3013 {
3014 goto associate;
3015 }
3016 }
3017 }
3018 fnpuv_start_writestr (client, (unsigned char *) "not available\r\n");
3019 goto reprompt;
3020 }
3021 reprompt:;
3022 fnpConnectPrompt (client);
3023 return;
3024
3025 associate:;
3026
3027 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_client = client;
3028
3029 p->assoc = true;
3030 p->fnpno = fnp_unit_idx;
3031 p->lineno = lineno;
3032 p->read_cb = fnpuv_associated_readcb;
3033 p->write_cb = fnpuv_start_write;
3034 p->write_actual_cb = fnpuv_start_write_actual;
3035
3036
3037
3038 char buf2 [1024];
3039
3040 struct sockaddr name;
3041 int namelen = sizeof (name);
3042 int ret = uv_tcp_getpeername (client, & name, & namelen);
3043 if (ret < 0)
3044 {
3045 sim_printf ("CONNECT (addr err %d) to %c.h%03d\n", ret, fnp_unit_idx +'a', lineno);
3046 }
3047 else
3048 {
3049 struct sockaddr_in * p = (struct sockaddr_in *) & name;
3050 sim_printf ("CONNECT %s to %c.h%03d\n", inet_ntoa (p -> sin_addr), fnp_unit_idx +'a', lineno);
3051 }
3052
3053 (void)sprintf (buf2, "Attached to line %c.h%03d\r\n", fnp_unit_idx +'a', lineno);
3054 fnpuv_start_writestr (client, (unsigned char *) buf2);
3055
3056 if (! fnpData.fnpUnitData[fnp_unit_idx].MState.accept_calls)
3057 fnpuv_start_writestr (client, (unsigned char *) "Multics is not accepting calls\r\n");
3058 else if (! fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].listen)
3059 fnpuv_start_writestr (client, (unsigned char *) "Multics is not listening to this line\r\n");
3060
3061
3062
3063 if (fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].lineType == 0)
3064 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].lineType = 1;
3065 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].accept_new_terminal = true;
3066 reset_line (& fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno]);
3067 }
3068
3069 void startFNPListener (void)
3070 {
3071 (void)fnpuvInit (fnpData.telnet_port, fnpData.telnet_address);
3072 }