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) + 1];
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 = (cidr == 0) ? 0 :
2095 ((uint32_t)-1 << (32 - cidr)) & MASK32;
2096
2097
2098
2099 bool accept = false;
2100 tok = strtok_r (NULL, ":", & saveptr);
2101 if (strcmp (tok, "ACCEPT") == 0)
2102 accept = true;
2103 else if (strcmp (tok, "DENY") == 0)
2104 accept = false;
2105 else
2106 {
2107 sim_printf ("cannot parse rule ACCEPT/DENY\r\n");
2108 return SCPE_ARG;
2109 }
2110
2111 fw_entries[n_fw_entries].line_0 = (uint) line_0;
2112 fw_entries[n_fw_entries].line_1 = (uint) line_1;
2113 fw_entries[n_fw_entries].ipaddr = ipaddr;
2114 fw_entries[n_fw_entries].cidr = (uint) cidr;
2115 fw_entries[n_fw_entries].cidr_mask = (uint) cidr_mask;
2116 fw_entries[n_fw_entries].accept = accept;
2117 n_fw_entries ++;
2118
2119 return SCPE_OK;
2120 }
2121
2122 if (strcasecmp (tok, "LIST") == 0)
2123 {
2124 for (int i = 0; i < n_fw_entries; i ++)
2125 {
2126 struct fw_entry_s * p = fw_entries + i;
2127
2128 if (p->line_0 == p->line_1)
2129 {
2130 sim_printf (" %c.h%03d %d.%d.%d.%d/%d %s\r\n",
2131 decodefnp (p->line_0) + 'a',
2132 decodeline (p->line_0),
2133 (p->ipaddr>>24) & 255,
2134 (p->ipaddr>>16) & 255,
2135 (p->ipaddr>>8) & 255,
2136 p->ipaddr & 255,
2137 p->cidr,
2138 p->accept ? "accept" : "deny");
2139 }
2140 else
2141 {
2142 sim_printf (" %c.h%03d-%c.%03d %d.%d.%d.%d/%d %s\r\n",
2143 decodefnp (p->line_0) + 'a',
2144 decodeline (p->line_0),
2145 decodefnp (p->line_1) + 'a',
2146 decodeline (p->line_1),
2147 (p->ipaddr>>24) & 255,
2148 (p->ipaddr>>16) & 255,
2149 (p->ipaddr>>8) & 255,
2150 p->ipaddr & 255,
2151 p->cidr,
2152 p->accept ? "accept" : "deny");
2153 }
2154 }
2155 return SCPE_OK;
2156 }
2157
2158 return SCPE_ARG;
2159 }
2160
2161 static t_stat fnpShowFW (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
2162 UNUSED const void * desc)
2163 {
2164 #if defined(TESTING)
2165 cpu_state_t * cpup = _cpup;
2166 #endif
2167 long fnpUnitIdx = FNP_UNIT_IDX (uptr);
2168 if (fnpUnitIdx >= (long) N_FNP_UNITS_MAX)
2169 {
2170 sim_debug (DBG_ERR, & fnp_dev,
2171 "fnpShowConfig: Invalid unit number %ld\n",
2172 (long) fnpUnitIdx);
2173 sim_printf ("error: Invalid unit number %ld\n",
2174 (long) fnpUnitIdx);
2175 return SCPE_ARG;
2176 }
2177
2178
2179
2180
2181
2182
2183
2184 return SCPE_OK;
2185 }
2186
2187 static t_stat fnpShowStatus (UNUSED FILE * st, UNIT * uptr, UNUSED int val,
2188 UNUSED const void * desc)
2189 {
2190 #if defined(TESTING)
2191 cpu_state_t * cpup = _cpup;
2192 #endif
2193 long fnpUnitIdx = FNP_UNIT_IDX (uptr);
2194 if (fnpUnitIdx >= (long) fnp_dev.numunits)
2195 {
2196 sim_debug (DBG_ERR, & fnp_dev,
2197 "fnpShowStatus: Invalid unit number %ld\n",
2198 (long) fnpUnitIdx);
2199 sim_printf ("error: Invalid unit number %ld\n",
2200 (long) fnpUnitIdx);
2201 return SCPE_ARG;
2202 }
2203
2204 sim_printf ("FNP unit number %ld:\n", (long) fnpUnitIdx);
2205 struct fnpUnitData_s * fudp = fnpData.fnpUnitData + fnpUnitIdx;
2206
2207 sim_printf ("\tmailboxAddress: %04o\n",
2208 fudp->mailboxAddress);
2209 sim_printf ("\tfnpIsRunning: %o\n",
2210 fudp->fnpIsRunning);
2211 sim_printf ("\tfnpMBXinUse: %o %o %o %o\n",
2212 fudp->fnpMBXinUse[0], fudp->fnpMBXinUse[1],
2213 fudp->fnpMBXinUse[2], fudp->fnpMBXinUse[3]);
2214 sim_printf ("\tlineWaiting: %o %o %o %o\n",
2215 fudp->lineWaiting[0], fudp->lineWaiting[1],
2216 fudp->lineWaiting[2], fudp->lineWaiting[3]);
2217 sim_printf ("\tfnpMBXlineno: %o %o %o %o\n",
2218 fudp->fnpMBXlineno[0], fudp->fnpMBXlineno[1],
2219 fudp->fnpMBXlineno[2], fudp->fnpMBXlineno[3]);
2220 sim_printf ("\taccept_calls: %o\n",
2221 fudp->MState.accept_calls);
2222 for (int l = 0; l < MAX_LINES; l ++)
2223 {
2224 sim_printf (" line %d:\n", l);
2225 sim_printf ("\tservice: %d\n",
2226 fudp->MState.line[l].service);
2227 sim_printf ("\tline_client: %p\n",
2228 (void *) fudp->MState.line[l].line_client);
2229 sim_printf ("\twas_CR: %d\n",
2230 fudp->MState.line[l].was_CR);
2231 sim_printf ("\tlisten: %d\n",
2232 fudp->MState.line[l].listen);
2233 sim_printf ("\tinputBufferSize: %d\n",
2234 fudp->MState.line[l].inputBufferSize);
2235 sim_printf ("\tline_break: %d\n",
2236 fudp->MState.line[l].line_break);
2237 sim_printf ("\tsend_output: %d\n",
2238 fudp->MState.line[l].send_output);
2239 sim_printf ("\taccept_new_terminal: %d\n",
2240 fudp->MState.line[l].accept_new_terminal);
2241 #if DISC_DELAY
2242 sim_printf ("\tline_disconnected: %d\n",
2243 fudp->MState.line[l].line_disconnected);
2244 #else
2245 sim_printf ("\tline_disconnected: %c\n",
2246 fudp->MState.line[l].line_disconnected ? 'T' : 'F');
2247 #endif
2248 sim_printf ("\tacu_dial_failure: %d\n",
2249 fudp->MState.line[l].acu_dial_failure);
2250 sim_printf ("\taccept_input: %d\n",
2251 fudp->MState.line[l].accept_input);
2252 sim_printf ("\twaitForMbxDone: %d\n",
2253 fudp->MState.line[l].waitForMbxDone);
2254 sim_printf ("\tinput_reply_pending: %d\n",
2255 fudp->MState.line[l].input_reply_pending);
2256 sim_printf ("\tinput_break: %d\n",
2257 fudp->MState.line[l].input_break);
2258 sim_printf ("\tnPos: %d\n",
2259 fudp->MState.line[l].nPos);
2260 sim_printf ("\tinBuffer: %p\n",
2261 (void *) fudp->MState.line[l].inBuffer);
2262 sim_printf ("\tinSize: %d\n",
2263 fudp->MState.line[l].inSize);
2264 sim_printf ("\tinUsed: %d\n",
2265 fudp->MState.line[l].inUsed);
2266
2267
2268
2269
2270 sim_printf ("\tport: %d\n",
2271 fudp->MState.line[l].port);
2272
2273 }
2274 return SCPE_OK;
2275 }
2276
2277 static t_stat fnp_show_device_name (UNUSED FILE * st, UNIT * uptr,
2278 UNUSED int val, UNUSED const void * desc)
2279 {
2280 int n = (int) FNP_UNIT_IDX (uptr);
2281 if (n < 0 || n >= N_FNP_UNITS_MAX)
2282 return SCPE_ARG;
2283 if (fnpData.fnpUnitData[n].device_name[0] != 0)
2284 sim_printf(" name: %s", fnpData.fnpUnitData[n].device_name);
2285 else
2286 sim_printf(" name: default");
2287 return SCPE_OK;
2288 }
2289
2290 static t_stat fnp_set_device_name (UNIT * uptr, UNUSED int32 value,
2291 const char * cptr, UNUSED void * desc)
2292 {
2293 int n = (int) FNP_UNIT_IDX (uptr);
2294 if (n < 0 || n >= N_FNP_UNITS_MAX)
2295 return SCPE_ARG;
2296 if (cptr)
2297 {
2298 strncpy (fnpData.fnpUnitData[n].device_name, cptr, MAX_DEV_NAME_LEN-1);
2299 fnpData.fnpUnitData[n].device_name[MAX_DEV_NAME_LEN-1] = 0;
2300 }
2301 else
2302 fnpData.fnpUnitData[n].device_name[0] = 0;
2303 return SCPE_OK;
2304 }
2305
2306 static config_list_t fnp_config_list [] =
2307 {
2308 { "mailbox", 0, 07777, NULL },
2309 { NULL, 0, 0, NULL }
2310 };
2311
2312 static t_stat fnpSetConfig (UNIT * uptr, UNUSED int value, const char * cptr, UNUSED void * desc)
2313 {
2314 #if defined(TESTING)
2315 cpu_state_t * cpup = _cpup;
2316 #endif
2317 uint fnpUnitIdx = (uint) FNP_UNIT_IDX (uptr);
2318
2319 if (fnpUnitIdx >= N_FNP_UNITS_MAX)
2320 {
2321 sim_debug (DBG_ERR, & fnp_dev, "fnpSetConfig: Invalid unit number %ld\n", (long) fnpUnitIdx);
2322 sim_printf ("error: fnpSetConfig: Invalid unit number %ld\n", (long) fnpUnitIdx);
2323 return SCPE_ARG;
2324 }
2325
2326 struct fnpUnitData_s * fudp = fnpData.fnpUnitData + fnpUnitIdx;
2327
2328 config_state_t cfg_state = { NULL, NULL };
2329
2330 for (;;)
2331 {
2332 int64_t v;
2333 int rc = cfg_parse ("fnpSetConfig", cptr, fnp_config_list, & cfg_state, & v);
2334 switch (rc)
2335 {
2336 case -2:
2337 cfg_parse_done (& cfg_state);
2338 return SCPE_ARG;
2339
2340 case -1:
2341 break;
2342
2343 case 0:
2344 fudp -> mailboxAddress = (uint) v;
2345 break;
2346
2347 default:
2348 sim_printf ("error: fnpSetConfig: Invalid cfg_parse rc <%ld>\n", (long) rc);
2349 cfg_parse_done (& cfg_state);
2350 return SCPE_ARG;
2351 }
2352 if (rc < 0)
2353 break;
2354 }
2355 cfg_parse_done (& cfg_state);
2356 return SCPE_OK;
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
2459 t_stat set_fnp_server_port (UNUSED int32 arg, const char * buf)
2460 {
2461 if (fnpData.du_server_inited)
2462 {
2463 sim_printf ("[FNP emulation: TELNET server port error: FNP already initialized]\n");
2464 return SCPE_INCOMP;
2465 }
2466 if (! buf)
2467 return SCPE_ARG;
2468 int n = atoi (buf);
2469 if (n < 1 || n > 65535)
2470 return SCPE_ARG;
2471 fnpData.telnet_port = n;
2472 if (!sim_quiet)
2473 {
2474 sim_printf ("[FNP emulation: TELNET server port set to %ld]\n", (long) n);
2475 }
2476 return SCPE_OK;
2477 }
2478
2479 t_stat set_fnp_server_address (UNUSED int32 arg, const char * buf)
2480 {
2481 if (fnpData.du_server_inited)
2482 {
2483 sim_printf ("[FNP emulation: FNP server address error: FNP already initialized]\n");
2484 return SCPE_INCOMP;
2485 }
2486 if ( (!buf) || (buf[0] == 0) )
2487 return SCPE_ARG;
2488 if (fnpData.telnet_address)
2489 FREE (fnpData.telnet_address);
2490 fnpData.telnet_address = strdup (buf);
2491 if (!fnpData.telnet_address)
2492 {
2493 (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
2494 __func__, __FILE__, __LINE__);
2495 #if defined(USE_BACKTRACE)
2496 # if defined(SIGUSR2)
2497 (void)raise(SIGUSR2);
2498
2499 # endif
2500 #endif
2501 abort();
2502 }
2503 if (!sim_quiet)
2504 {
2505 sim_printf ("[FNP emulation: FNP server address set to %s]\n", fnpData.telnet_address);
2506 }
2507 return SCPE_OK;
2508 }
2509
2510 t_stat set_fnp_3270_server_port (UNUSED int32 arg, const char * buf)
2511 {
2512
2513 if ( (fnpData.du3270_server_inited) || (fnpData.du_server_inited) )
2514 {
2515 sim_printf ("[FNP emulation: TN3270 server port error: FNP already initialized]\n");
2516 return SCPE_INCOMP;
2517 }
2518 if (! buf)
2519 return SCPE_ARG;
2520 int n = atoi (buf);
2521 if (n < 1 || n > 65535)
2522 return SCPE_ARG;
2523 fnpData.telnet3270_port = n;
2524 if (!sim_quiet)
2525 {
2526 sim_printf ("[FNP emulation: TN3270 server port set to %ld]\n", (long) n);
2527 }
2528 return SCPE_OK;
2529 }
2530
2531 t_stat fnp_start (UNUSED int32 arg, UNUSED const char * buf)
2532 {
2533 int rc = 0;
2534 rc = fnpuvInit (fnpData.telnet_port, fnpData.telnet_address);
2535 if (rc != 0)
2536 return SCPE_INCOMP;
2537
2538
2539
2540 return SCPE_OK;
2541 }
2542
2543 #define PROMPT "HSLA Port ("
2544
2545 void fnpConnectPrompt (uv_tcp_t * client)
2546 {
2547 fnpuv_start_writestr (client, (unsigned char *) PROMPT);
2548 bool first = true;
2549 uint numunits = (uint) fnp_dev.numunits;
2550 for (uint fnp_unit_idx = 0; fnp_unit_idx < numunits; fnp_unit_idx ++)
2551 {
2552 if (! fnpData.fnpUnitData[fnp_unit_idx].fnpIsRunning)
2553 continue;
2554 for (uint lineno = 0; lineno < MAX_LINES; lineno ++)
2555 {
2556 struct t_line * linep = & fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno];
2557 if (! linep->listen)
2558 continue;
2559 if (linep->service == service_login &&
2560 ! linep->line_disconnected &&
2561 ! linep->line_client &&
2562 fnpData.fnpUnitData[fnp_unit_idx].MState.accept_calls)
2563 {
2564 if (! first)
2565 fnpuv_start_writestr (client, (unsigned char *) ",");
2566 char name [16];
2567 first = false;
2568 (void)sprintf (name, "%c.h%03d", 'a' + fnp_unit_idx, lineno);
2569 fnpuv_start_writestr (client, (unsigned char *) name);
2570 }
2571 }
2572 }
2573 fnpuv_start_writestr (client, (unsigned char *) ")? ");
2574 }
2575
2576
2577
2578
2579
2580 const unsigned char a2e[256] = {
2581 0, 1, 2, 3, 55, 45, 46, 47, 22, 5, 37, 11, 12, 13, 14, 15,
2582 16, 17, 18, 19, 60, 61, 50, 38, 24, 25, 63, 39, 28, 29, 30, 31,
2583 64, 79, 127, 123, 91, 108, 80, 125, 77, 93, 92, 78, 107, 96, 75, 97,
2584 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 122, 94, 76, 126, 110, 111,
2585 124, 193, 194, 195, 196, 197, 198, 199, 200, 201, 209, 210, 211, 212, 213, 214,
2586 215, 216, 217, 226, 227, 228, 229, 230, 231, 232, 233, 74, 224, 90, 95, 109,
2587 121, 129, 130, 131, 132, 133, 134, 135, 136, 137, 145, 146, 147, 148, 149, 150,
2588 151, 152, 153, 162, 163, 164, 165, 166, 167, 168, 169, 192, 106, 208, 161, 7,
2589 32, 33, 34, 35, 36, 21, 6, 23, 40, 41, 42, 43, 44, 9, 10, 27,
2590 48, 49, 26, 51, 52, 53, 54, 8, 56, 57, 58, 59, 4, 20, 62, 225,
2591 65, 66, 67, 68, 69, 70, 71, 72, 73, 81, 82, 83, 84, 85, 86, 87,
2592 88, 89, 98, 99, 100, 101, 102, 103, 104, 105, 112, 113, 114, 115, 116, 117,
2593 118, 119, 120, 128, 138, 139, 140, 141, 142, 143, 144, 154, 155, 156, 157, 158,
2594 159, 160, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
2595 184, 185, 186, 187, 188, 189, 190, 191, 202, 203, 204, 205, 206, 207, 218, 219,
2596 220, 221, 222, 223, 234, 235, 236, 237, 238, 239, 250, 251, 252, 253, 254, 255
2597 };
2598
2599 const unsigned char e2a[256] = {
2600 0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15,
2601 16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31,
2602 128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7,
2603 144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26,
2604 32, 160, 161, 162, 163, 164, 165, 166, 167, 168, 91, 46, 60, 40, 43, 33,
2605 38, 169, 170, 171, 172, 173, 174, 175, 176, 177, 93, 36, 42, 41, 59, 94,
2606 45, 47, 178, 179, 180, 181, 182, 183, 184, 185, 124, 44, 37, 95, 62, 63,
2607 186, 187, 188, 189, 190, 191, 192, 193, 194, 96, 58, 35, 64, 39, 61, 34,
2608 195, 97, 98, 99, 100, 101, 102, 103, 104, 105, 196, 197, 198, 199, 200, 201,
2609 202, 106, 107, 108, 109, 110, 111, 112, 113, 114, 203, 204, 205, 206, 207, 208,
2610 209, 126, 115, 116, 117, 118, 119, 120, 121, 122, 210, 211, 212, 213, 214, 215,
2611 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231,
2612 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 232, 233, 234, 235, 236, 237,
2613 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 238, 239, 240, 241, 242, 243,
2614 92, 159, 83, 84, 85, 86, 87, 88, 89, 90, 244, 245, 246, 247, 248, 249,
2615 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 250, 251, 252, 253, 254, 255
2616 };
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630 static void fnp3270Msg (uv_tcp_t * client, unsigned char * msg)
2631 {
2632
2633 size_t l = strlen ((char *) msg);
2634 unsigned char buf [l + 1];
2635 for (uint i = 0; i < l; i ++)
2636 buf[i] = a2e[msg[i]];
2637 buf[l] = '\0';
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647 unsigned char EW [] = {245, 0xc3, 17, 64, 64 };
2648 fnpuv_start_3270_write (client, EW, sizeof (EW));
2649 fnpuv_start_3270_write (client, buf, (ssize_t) l);
2650 fnpuv_send_eor (client);
2651 }
2652
2653 void fnp3270ConnectPrompt (uv_tcp_t * client)
2654 {
2655 if (! client || ! client->data)
2656 {
2657 sim_warn ("fnp3270ConnectPrompt bad client data\r\n");
2658 return;
2659 }
2660 uint fnpno = fnpData.ibm3270ctlr[ASSUME0].fnpno;
2661 uint lineno = fnpData.ibm3270ctlr[ASSUME0].lineno;
2662
2663 uvClientData * p = client->data;
2664 p->assoc = true;
2665 p->fnpno = fnpno;
2666 p->lineno = lineno;
2667
2668
2669
2670
2671
2672 unsigned char buf [256];
2673 (void)sprintf ((char *) buf, "DPS8/M 3270 connection to %c.%03d.%ld ttype %s\n",
2674 fnpno+'a',lineno, (long)p->stationNo, p->ttype);
2675 fnpData.ibm3270ctlr[ASSUME0].selDevChar = addr_map[p->stationNo];
2676 fnp3270Msg (client, buf);
2677
2678 }
2679
2680 void processLineInput (uv_tcp_t * client, unsigned char * buf, ssize_t nread)
2681 {
2682 if (! client || ! client->data)
2683 {
2684 sim_warn ("processLineInput bad client data\r\n");
2685 return;
2686 }
2687 uvClientData * p = (uvClientData *) client->data;
2688 uint fnpno = p -> fnpno;
2689 uint lineno = p -> lineno;
2690 if (fnpno >= N_FNP_UNITS_MAX || lineno >= MAX_LINES)
2691 {
2692 sim_printf ("bogus client data\n");
2693 return;
2694 }
2695
2696
2697
2698
2699
2700
2701
2702 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
2703
2704
2705
2706
2707
2708
2709
2710 if (linep->inBuffer)
2711 {
2712 sim_warn ("inBuffer overrun\n");
2713 unsigned char * new = realloc (linep->inBuffer, (unsigned long) (linep->inSize + nread));
2714 if (! new)
2715 {
2716 sim_warn ("inBuffer realloc fail; dropping data\n");
2717 goto done;
2718 }
2719 memcpy (new + linep->inSize, buf, (unsigned long) nread);
2720 linep->inSize += nread;
2721 linep->inBuffer = new;
2722 }
2723 else
2724 {
2725 linep->inBuffer = malloc ((unsigned long) nread);
2726 if (! linep->inBuffer)
2727 {
2728 sim_warn ("inBuffer malloc fail; dropping data\n");
2729 goto done;
2730 }
2731 memcpy (linep->inBuffer, buf, (unsigned long) nread);
2732 linep->inSize = (uint) nread;
2733 linep->inUsed = 0;
2734 }
2735
2736 done:;
2737
2738 fnpuv_read_stop (client);
2739 }
2740
2741 void process3270Input (uv_tcp_t * client, unsigned char * buf, ssize_t nread)
2742 {
2743 #if defined(TESTING)
2744 cpu_state_t * cpup = _cpup;
2745 #endif
2746 if (! client || ! client->data)
2747 {
2748 sim_warn ("process3270Input bad client data\r\n");
2749 return;
2750 }
2751 uvClientData * p = (uvClientData *) client->data;
2752 uint fnpno = p->fnpno;
2753 uint lineno = p->lineno;
2754 uint stn_no = p->stationNo;
2755
2756 if (fnpno >= N_FNP_UNITS_MAX || lineno >= MAX_LINES)
2757 {
2758 sim_printf ("bogus client data\n");
2759 return;
2760 }
2761 if_sim_debug (DBG_TRACE, & fnp_dev) {
2762 sim_debug (DBG_TRACE, & fnp_dev, "process3270Input nread %ld\n", (long)nread);
2763 for (int i = 0; i < nread; i ++) sim_debug (DBG_TRACE, & fnp_dev, "%c", isgraph (e2a[buf[i]]) ? e2a[buf[i]] : '.');
2764 sim_debug (DBG_TRACE, & fnp_dev, "\r\n");
2765 for (int i = 0; i < nread; i ++) sim_debug (DBG_TRACE, & fnp_dev, " %02x", buf[i]);
2766 sim_debug (DBG_TRACE, & fnp_dev, "\r\n");
2767 }
2768
2769 struct t_line * linep = & fnpData.fnpUnitData[fnpno].MState.line[lineno];
2770 if (! fnpData.fnpUnitData[fnpno].MState.accept_calls)
2771 {
2772 if (! linep->inBuffer)
2773 fnp3270Msg (client, (unsigned char *) "Multics is not accepting calls\r\n");
2774 return;
2775 }
2776 if (! linep->listen)
2777 {
2778 if (! linep->inBuffer)
2779 fnp3270Msg (client, (unsigned char *) "Multics is not listening to this line\r\n");
2780 return;
2781 }
2782
2783
2784
2785
2786
2787
2788
2789
2790 struct station_s * stn_p = & fnpData.ibm3270ctlr[ASSUME0].stations[stn_no];
2791 if (stn_p->stn_in_buffer)
2792 {
2793 sim_warn ("stn_in_buffer overrun\n");
2794 unsigned char * new = realloc (stn_p->stn_in_buffer, (unsigned long) (stn_p->stn_in_size + nread));
2795 if (! new)
2796 {
2797 sim_warn ("stn_in_buffer realloc fail; dropping data\n");
2798 goto done;
2799 }
2800 memcpy (new + stn_p->stn_in_size, buf, (unsigned long) nread);
2801 stn_p->stn_in_size += nread;
2802 stn_p->stn_in_buffer = new;
2803 }
2804 else
2805 {
2806 stn_p->stn_in_buffer = malloc ((unsigned long) nread);
2807 if (! stn_p->stn_in_buffer)
2808 {
2809 sim_warn ("stn_in_buffer malloc fail; dropping data\n");
2810 goto done;
2811 }
2812 memcpy (stn_p->stn_in_buffer, buf, (unsigned long) nread);
2813 stn_p->stn_in_size = (uint) nread;
2814 stn_p->stn_in_used = 0;
2815 }
2816
2817 sim_debug (DBG_TRACE, & fnp_dev,
2818 "process3270Input stashed %lu bytes in stn %u; stn_in_size now %u\n",
2819 (unsigned long)nread, stn_no, stn_p->stn_in_size);
2820 done:;
2821
2822
2823
2824 }
2825
2826 void reset_line (struct t_line * linep)
2827 {
2828 linep->was_CR = false;
2829 linep->inputBufferSize = 0;
2830 linep->ctrlStrIdx = 0;
2831 linep->breakAll = false;
2832 linep->handleQuit = false;
2833 linep->echoPlex = false;
2834 linep->crecho = false;
2835 linep->lfecho = false;
2836 linep->tabecho = false;
2837 linep->replay = false;
2838 linep->polite = false;
2839 linep->prefixnl = false;
2840 linep->eight_bit_out = false;
2841 linep->eight_bit_in = false;
2842 linep->odd_parity = false;
2843 linep->output_flow_control = false;
2844 linep->input_flow_control = false;
2845 linep->block_xfer_in_frame_sz = 0;
2846 linep->block_xfer_out_frame_sz = 0;
2847 (void)memset (linep->delay_table, 0, sizeof (linep->delay_table));
2848 linep->inputSuspendLen = 0;
2849 (void)memset (linep->inputSuspendStr, 0, sizeof (linep->inputSuspendStr));
2850 linep->inputResumeLen = 0;
2851 (void)memset (linep->inputResumeStr, 0, sizeof (linep->inputResumeStr));
2852 linep->outputSuspendLen = 0;
2853 (void)memset (linep->outputSuspendStr, 0, sizeof (linep->outputSuspendStr));
2854 linep->outputResumeLen = 0;
2855 (void)memset (linep->outputResumeStr, 0, sizeof (linep->outputResumeStr));
2856 linep->frame_begin = 0;
2857 linep->frame_end = 0;
2858 (void)memset (linep->echnego_break_table, 0, sizeof (linep->echnego_break_table));
2859 linep->echnego_sync_ctr = 0;
2860 linep->echnego_screen_left = 0;
2861 linep->echnego_unechoed_cnt = 0;
2862 linep->echnego_on = false;
2863 linep->echnego_synced = false;
2864 linep->line_break = false;
2865 }
2866
2867 void processUserInput (uv_tcp_t * client, unsigned char * buf, ssize_t nread)
2868 {
2869 if (! client || ! client->data)
2870 {
2871 sim_warn ("processUserInput bad client data\r\n");
2872 return;
2873 }
2874 uvClientData * p = (uvClientData *) client->data;
2875 for (ssize_t nchar = 0; nchar < nread; nchar ++)
2876 {
2877 unsigned char kar = buf [nchar];
2878
2879 if (kar == 0x1b || kar == 0x03)
2880 {
2881 close_connection ((uv_stream_t *) client);
2882 return;
2883 }
2884
2885
2886 if (p->nPos >= sizeof(p->buffer) - 1)
2887 {
2888
2889 switch (kar)
2890 {
2891 case '\b':
2892 case 127:
2893 {
2894 if (p->nPos)
2895 {
2896 fnpuv_start_writestr (client, (unsigned char *) "\b \b");
2897
2898 p->buffer[p->nPos] = 0;
2899 p->nPos -= 1;
2900 }
2901 }
2902 break;
2903
2904 case '\n':
2905 case '\r':
2906 {
2907 p->buffer[p->nPos] = 0;
2908 goto check;
2909 }
2910
2911 case 0x12:
2912 {
2913 fnpuv_start_writestr (client, (unsigned char *) "^R\r\n");
2914 fnpConnectPrompt (client);
2915 fnpuv_start_writestr (client, (unsigned char *) p->buffer);
2916 }
2917 break;
2918
2919 default:
2920 break;
2921 }
2922 continue;
2923 }
2924
2925 if (isprint (kar))
2926 {
2927 unsigned char str [2] = { kar, 0 };
2928 fnpuv_start_writestr (client, str);
2929 p->buffer[p->nPos++] = (char) kar;
2930 }
2931 else
2932 {
2933 switch (kar)
2934 {
2935 case '\b':
2936 case 127:
2937 {
2938 if (p->nPos)
2939 {
2940 fnpuv_start_writestr (client, (unsigned char *) "\b \b");
2941
2942 p->buffer[p->nPos] = 0;
2943 p->nPos -= 1;
2944 }
2945 }
2946 break;
2947
2948 case '\n':
2949 case '\r':
2950 {
2951 p->buffer[p->nPos] = 0;
2952 goto check;
2953 }
2954
2955 case 0x12:
2956 {
2957 fnpuv_start_writestr (client, (unsigned char *) "^R\r\n");
2958 fnpConnectPrompt (client);
2959 fnpuv_start_writestr (client, (unsigned char *) p->buffer);
2960 }
2961 break;
2962
2963 default:
2964 break;
2965 }
2966 }
2967 }
2968 return;
2969
2970 check:;
2971 char cpy [p->nPos + 1];
2972 memcpy (cpy, p->buffer, p->nPos);
2973 cpy [p->nPos] = 0;
2974 trim (cpy);
2975 sim_printf ("<%s>", cpy);
2976 p->nPos = 0;
2977 fnpuv_start_writestr (client, (unsigned char *) "\r\n");
2978
2979 uint fnp_unit_idx = 0;
2980 uint lineno = 0;
2981
2982 if (strlen (cpy))
2983 {
2984 char fnpcode;
2985 int cnt = sscanf (cpy, "%c.h%u", & fnpcode, & lineno);
2986
2987 if (cnt != 2 || fnpcode < 'a' || fnpcode > 'h' || lineno >= MAX_LINES)
2988 {
2989 fnpuv_start_writestr (client, (unsigned char *) "can't parse\r\n");
2990 goto reprompt;
2991 }
2992 fnp_unit_idx = (uint) (fnpcode - 'a');
2993 if (fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].service != service_login ||
2994 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_client)
2995 {
2996 fnpuv_start_writestr (client, (unsigned char *) "not available\r\n");
2997 goto reprompt;
2998 }
2999 goto associate;
3000 }
3001 else
3002 {
3003 uint32 numunits = fnp_dev.numunits;
3004 for (fnp_unit_idx = 0; fnp_unit_idx < numunits; fnp_unit_idx ++)
3005 {
3006 if (! fnpData.fnpUnitData[fnp_unit_idx].fnpIsRunning)
3007 continue;
3008 for (lineno = 0; lineno < MAX_LINES; lineno ++)
3009 {
3010 if (fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].service == service_login &&
3011 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].listen &&
3012 ! fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_disconnected &&
3013 ! fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_client &&
3014 fnpData.fnpUnitData[fnp_unit_idx].MState.accept_calls)
3015 {
3016 goto associate;
3017 }
3018 }
3019 }
3020 fnpuv_start_writestr (client, (unsigned char *) "not available\r\n");
3021 goto reprompt;
3022 }
3023 reprompt:;
3024 fnpConnectPrompt (client);
3025 return;
3026
3027 associate:;
3028
3029 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].line_client = client;
3030
3031 p->assoc = true;
3032 p->fnpno = fnp_unit_idx;
3033 p->lineno = lineno;
3034 p->read_cb = fnpuv_associated_readcb;
3035 p->write_cb = fnpuv_start_write;
3036 p->write_actual_cb = fnpuv_start_write_actual;
3037
3038
3039
3040 char buf2 [1024];
3041
3042 struct sockaddr name;
3043 int namelen = sizeof (name);
3044 int ret = uv_tcp_getpeername (client, & name, & namelen);
3045 if (ret < 0)
3046 {
3047 sim_printf ("CONNECT (addr err %d) to %c.h%03d\n", ret, fnp_unit_idx +'a', lineno);
3048 }
3049 else
3050 {
3051 struct sockaddr_in * p = (struct sockaddr_in *) & name;
3052 sim_printf ("CONNECT %s to %c.h%03d\n", inet_ntoa (p -> sin_addr), fnp_unit_idx +'a', lineno);
3053 }
3054
3055 (void)sprintf (buf2, "Attached to line %c.h%03d\r\n", fnp_unit_idx +'a', lineno);
3056 fnpuv_start_writestr (client, (unsigned char *) buf2);
3057
3058 if (! fnpData.fnpUnitData[fnp_unit_idx].MState.accept_calls)
3059 fnpuv_start_writestr (client, (unsigned char *) "Multics is not accepting calls\r\n");
3060 else if (! fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].listen)
3061 fnpuv_start_writestr (client, (unsigned char *) "Multics is not listening to this line\r\n");
3062
3063
3064
3065 if (fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].lineType == 0)
3066 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].lineType = 1;
3067 fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno].accept_new_terminal = true;
3068 reset_line (& fnpData.fnpUnitData[fnp_unit_idx].MState.line[lineno]);
3069 }
3070
3071 void startFNPListener (void)
3072 {
3073 (void)fnpuvInit (fnpData.telnet_port, fnpData.telnet_address);
3074 }