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