root/src/dps8/dps8_mgp.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hash32s
  2. mgp_show_nunits
  3. mgp_set_nunits
  4. mgp_show_device_name
  5. mgp_set_device_name
  6. mgp_reset
  7. mgpAttach
  8. mgpDetach
  9. mgp_init
  10. get_ddcw
  11. cmd_name
  12. mgp_cmd
  13. mgp_iom_cmd
  14. mgp_process_event
  15. pktype_name
  16. chop_name
  17. valid_chaos_host_address
  18. copy_packet9_to_cbridge8
  19. copy_cbridge8_to_packet9
  20. mgp_checksum_raw
  21. mgp_checksum
  22. parse_packet_header
  23. unparse_packet_header
  24. dumppkt
  25. mgp_init_dev_state
  26. mgp_wants_to_read
  27. find_free_conn
  28. find_conn_for
  29. make_cbridge_pkt
  30. make_rfc_pkt
  31. cbridge_open_socket
  32. close_conn
  33. cbridge_send_packet
  34. handle_packet
  35. handle_close
  36. handle_lose
  37. handle_connect
  38. handle_mgp_packet
  39. make_mgp_header
  40. make_mgp_packet
  41. make_status_packet
  42. make_noop_packet
  43. make_open_packet
  44. make_connect_packet
  45. receive_cbridge_opcode
  46. poll_from_cbridge

   1 /*
   2  * vim: filetype=c:tabstop=4:ai:expandtab
   3  * SPDX-License-Identifier: ICU
   4  * scspell-id: 35c9cf5c-ebbf-11ed-8d34-80ee73e9b8e7
   5  *
   6  * ---------------------------------------------------------------------------
   7  *
   8  * Copyright (c) 2007-2013 Michael Mondy
   9  * Copyright (c) 2015-2018 Charles Anthony
  10  * Copyright (c) 2023 Björn Victor
  11  * Copyright (c) 2021-2024 The DPS8M Development Team
  12  *
  13  * This software is made available under the terms of the ICU License.
  14  * See the LICENSE.md file at the top-level directory of this distribution.
  15  *
  16  * ---------------------------------------------------------------------------
  17  */
  18 
  19 // Defining USE_SOCKET_DEV_APPROACH to 1 means taking "the socket_dev
  20 // approach", meaning the Read operation doesn't really do much, but
  21 // instead the event/poll loop (see mgp_process_event) does the actual
  22 // reading. This doesn't seem to work very well, basically nothing
  23 // gets read.
  24 
  25 // Defining USE_SOCKET_DEV_APPROACH to 0 means the Read operation does
  26 // the reading, returning IOM_CMD_DISCONNECT to signal that there is
  27 // something in the buffer. Additionally the event/poll loop
  28 // (mgp_process_event) checks if there is anything to read and in that
  29 // case explicitly does send_terminate_interrupt(). This works a
  30 // little bit better, as some things are actually read, but not
  31 // sufficiently well.
  32 
  33 #define USE_SOCKET_DEV_APPROACH 0
  34 
  35 #include <stdio.h>
  36 #include <ctype.h>
  37 #include <unistd.h>
  38 #include <stdint.h>
  39 #include <time.h>
  40 
  41 #include <sys/types.h>
  42 #include <sys/un.h>
  43 #include <sys/select.h>
  44 #include <sys/time.h>
  45 
  46 #include "dps8.h"
  47 #include "dps8_iom.h"
  48 #include "dps8_mgp.h"
  49 #include "dps8_sys.h"
  50 #include "dps8_cable.h"
  51 #include "dps8_cpu.h"
  52 #include "dps8_faults.h"
  53 #include "dps8_scu.h"
  54 #include "dps8_utils.h"
  55 
  56 #if defined(FREE)
  57 # undef FREE
  58 #endif /* if defined(FREE) */
  59 #define FREE(p) do  \
  60   {                 \
  61     free((p));      \
  62     (p) = NULL;     \
  63   } while(0)
  64 
  65 #if defined(WITH_MGP_DEV)
  66 
  67 # define DBG_CTR  1
  68 
  69 static void mgp_init_dev_state(void);
  70 static void dumppkt(char *hdr, word36 *buf, uint words);
  71 static int  handle_mgp_packet(word36 *buf, uint words);
  72 static int  poll_from_cbridge(word36 *buf, uint words, uint probe_only);
  73 static void mgp_wants_to_read(uint iom_unit_idx, uint chan);
  74 
  75 # define MAX_CONNS  64
  76 
  77 struct conn_table
  78 {
  79   int skt;                    /* socket to cbridge                     */
  80   u_short remote_addr;        /* remote address (from connect/cbridge) */
  81   char *contact_name;         /* contact name (likewise)               */
  82   u_short local_id;           /* local id                              */
  83   u_short multics_proc;
  84   u_char pkt_last_received;   /* from Multics */
  85   u_char pkt_last_sent;       /* to Multics   */
  86 };
  87 
  88 struct mgp_dev_state
  89 {
  90   u_char first_frame_received;
  91   u_char frame_last_received; /* from Multics                             */
  92   u_char frame_last_sent;     /* to Multics                               */
  93   u_char send_noop;           /* set to make sure NOOP is sent to Multics */
  94   short read_index;           /* conn we last read from, for round-robin  */
  95   u_char want_to_read;        /* flag that Multics wants to read          */
  96   uint read_unit_idx;
  97   uint read_unit_chan;
  98   struct conn_table conns[MAX_CONNS];
  99 } mgp_dev_state;
 100 
 101 static struct mgp_state
 102   {
 103     char device_name[MAX_DEV_NAME_LEN];
 104   } mgp_state[N_MGP_UNITS_MAX];
 105 
 106 # define N_MGP_UNITS  2 // default
 107 
 108 # define UNIT_FLAGS \
 109         ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE )
 110 
 111 UNIT mgp_unit[N_MGP_UNITS_MAX] = {
 112   {
 113     UDATA(NULL, UNIT_FLAGS, 0),
 114     0,   0,   0,   0,   0,
 115     NULL,  NULL,  NULL,  NULL
 116   }
 117 };
 118 
 119 static inline uint32_t
 120 hash32s(const void *buf, size_t len, uint32_t h)
     /* [previous][next][first][last][top][bottom][index][help] */
 121 {
 122   const unsigned char *p = buf;
 123 
 124   for (size_t i = 0; i < len; i++)
 125     h = h * 31 + p[i];
 126 
 127   h ^= h >> 17;
 128   h *= UINT32_C(0xed5ad4bb);
 129   h ^= h >> 11;
 130   h *= UINT32_C(0xac4c1b51);
 131   h ^= h >> 15;
 132   h *= UINT32_C(0x31848bab);
 133   h ^= h >> 14;
 134 
 135   return h;
 136 }
 137 
 138 # define MGP_UNIT_IDX(uptr)  (( uptr ) - mgp_unit )
 139 
 140 static DEBTAB mgp_dt[] = {
 141      { "NOTIFY", DBG_NOTIFY, NULL },
 142      { "INFO",   DBG_INFO,   NULL },
 143      { "ERR",    DBG_ERR,    NULL },
 144      { "WARN",   DBG_WARN,   NULL },
 145      { "DEBUG",  DBG_DEBUG,  NULL },
 146      { "ALL",    DBG_ALL,    NULL }, // Don't move as it messes up DBG message
 147      { NULL,     0,          NULL }
 148 };
 149 
 150 static t_stat
 151 mgp_show_nunits(UNUSED FILE *st, UNUSED UNIT *uptr, UNUSED int val,
     /* [previous][next][first][last][top][bottom][index][help] */
 152                 UNUSED const void *desc)
 153 {
 154   sim_printf("Number of MGP units in system is %d\n", mgp_dev.numunits);
 155 
 156   return SCPE_OK;
 157 }
 158 
 159 static t_stat
 160 mgp_set_nunits(UNUSED UNIT *uptr, UNUSED int32 value, const char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 161                UNUSED void *desc)
 162 {
 163   if (!cptr)
 164     {
 165       return SCPE_ARG;
 166     }
 167 
 168   int n = atoi(cptr);
 169   if (n < 1 || n > N_MGP_UNITS_MAX)
 170     {
 171       return SCPE_ARG;
 172     }
 173 
 174   mgp_dev.numunits = (uint32)n;
 175 
 176   return SCPE_OK;
 177 }
 178 
 179 static t_stat
 180 mgp_show_device_name(UNUSED FILE *st, UNIT *uptr, UNUSED int val,
     /* [previous][next][first][last][top][bottom][index][help] */
 181                      UNUSED const void *desc)
 182 {
 183   int n = (int)MGP_UNIT_IDX(uptr);
 184 
 185   if (n < 0 || n >= N_MGP_UNITS_MAX)
 186     {
 187       return SCPE_ARG;
 188     }
 189 
 190   if (mgp_state[n].device_name[1] != 0)
 191     {
 192       sim_printf("name     : %s", mgp_state[n].device_name);
 193     }
 194   else
 195     {
 196       sim_printf("name     : MGP%d", n);
 197     }
 198 
 199   return SCPE_OK;
 200 }
 201 
 202 static t_stat
 203 mgp_set_device_name(UNIT *uptr, UNUSED int32 value, const char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 204                     UNUSED void *desc)
 205 {
 206   int n = (int)MGP_UNIT_IDX(uptr);
 207 
 208   if (n < 0 || n >= N_MGP_UNITS_MAX)
 209     {
 210       return SCPE_ARG;
 211     }
 212 
 213   if (cptr)
 214     {
 215       strncpy(mgp_state[n].device_name, cptr, MAX_DEV_NAME_LEN - 1);
 216       mgp_state[n].device_name[MAX_DEV_NAME_LEN - 1] = 0;
 217     }
 218   else
 219     {
 220       mgp_state[n].device_name[0] = 0;
 221     }
 222 
 223   return SCPE_OK;
 224 }
 225 
 226 # define UNIT_WATCH  UNIT_V_UF
 227 
 228 static MTAB mgp_mod[] = {
 229 # if !defined(SPEED)
 230   { UNIT_WATCH, 1, "WATCH",   "WATCH",   0, 0, NULL, NULL },
 231   { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
 232 # endif /* if !defined(SPEED) */
 233   {
 234     MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_VALR, /* Mask               */
 235     0,                                          /* Match              */
 236     "NUNITS",                                   /* Print string       */
 237     "NUNITS",                                   /* Match string       */
 238     mgp_set_nunits,                             /* Validation routine */
 239     mgp_show_nunits,                            /* Display routine    */
 240     "Number of MGP units in the system",        /* Value descriptor   */
 241     NULL                                        /* Help               */
 242   },
 243   {
 244     MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,  /* Mask               */
 245     0,                                          /* Match              */
 246     "NAME",                                     /* Print string       */
 247     "NAME",                                     /* Match string       */
 248     mgp_set_device_name,                        /* Validation routine */
 249     mgp_show_device_name,                       /* Display routine    */
 250     "Set the device name",                      /* Value descriptor   */
 251     NULL                                        /* Help               */
 252   },
 253   MTAB_eol
 254 };
 255 
 256 static t_stat
 257 mgp_reset(UNUSED DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 258 {
 259   // mgpResetRX (0);
 260   // mgpResetTX (0);
 261 
 262   return SCPE_OK;
 263 }
 264 
 265 static t_stat
 266 mgpAttach(UNIT *uptr, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 267 {
 268   if (!cptr)
 269     {
 270       return SCPE_ARG;
 271     }
 272 
 273   // If we're already attached, then detach ...
 274   if (( uptr->flags & UNIT_ATT ) != 0)
 275     {
 276       detach_unit(uptr);
 277     }
 278 
 279   uptr->flags |= UNIT_ATT;
 280 
 281   return SCPE_OK;
 282 }
 283 
 284 // Detach (connect) ...
 285 static t_stat
 286 mgpDetach(UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 287 {
 288   if (( uptr->flags & UNIT_ATT ) == 0)
 289     {
 290       return SCPE_OK;
 291     }
 292 
 293   uptr->flags &= ~(unsigned int)UNIT_ATT;
 294 
 295   return SCPE_OK;
 296 }
 297 
 298 DEVICE mgp_dev = {
 299   "MGP",       /* Name                */
 300   mgp_unit,    /* Units               */
 301   NULL,        /* Registers           */
 302   mgp_mod,     /* Modifiers           */
 303   N_MGP_UNITS, /* #units              */
 304   10,          /* Address radix       */
 305   24,          /* Address width       */
 306   1,           /* Address increment   */
 307   8,           /* Data radix          */
 308   36,          /* Data width          */
 309   NULL,        /* Examine             */
 310   NULL,        /* Deposit             */
 311   mgp_reset,   /* Reset               */
 312   NULL,        /* Boot                */
 313   mgpAttach,   /* Attach              */
 314   mgpDetach,   /* Detach              */
 315   NULL,        /* Context             */
 316   DEV_DEBUG,   /* Flags               */
 317   0,           /* Debug control flags */
 318   mgp_dt,      /* Debug flag names    */
 319   NULL,        /* Memory size change  */
 320   NULL,        /* Logical name        */
 321   NULL,        /* Help                */
 322   NULL,        /* Attach help         */
 323   NULL,        /* Attach context      */
 324   NULL,        /* Description         */
 325   NULL         /* End                 */
 326 };
 327 
 328 /*
 329  * mgp_init()
 330  */
 331 
 332 // Once-only initialization
 333 
 334 void
 335 mgp_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 336 {
 337   (void)memset(mgp_state, 0, sizeof ( mgp_state ));
 338   // Init the other state too
 339   mgp_init_dev_state();
 340 }
 341 
 342 static iom_cmd_rc_t
 343 get_ddcw(iom_chan_data_t *p, uint iom_unit_idx, uint chan, bool *ptro,
     /* [previous][next][first][last][top][bottom][index][help] */
 344          uint expected_tally, uint *tally)
 345 {
 346 # if defined(TESTING)
 347   cpu_state_t * cpup = _cpup;
 348 # endif
 349   bool  send, uff;
 350   int   rc = iom_list_service(iom_unit_idx, chan, ptro, &send, &uff);
 351 
 352   if (rc < 0)
 353     {
 354       p->stati = 05001; // BUG: arbitrary error code; config switch
 355       sim_warn("%s list service failed\n", __func__);
 356 
 357       return IOM_CMD_ERROR;
 358     }
 359 
 360   if (uff)
 361     {
 362       sim_warn("%s ignoring uff\n", __func__); // XXX
 363     }
 364 
 365   if (!send)
 366     {
 367       sim_warn("%s nothing to send\n", __func__);
 368       p->stati = 05001; // BUG: arbitrary error code; config switch
 369 
 370       return IOM_CMD_ERROR;
 371     }
 372 
 373   if (IS_IDCW(p) || IS_TDCW(p))
 374     {
 375       sim_warn("%s expected DDCW\n", __func__);
 376       p->stati = 05001; // BUG: arbitrary error code; config switch
 377 
 378       return IOM_CMD_ERROR;
 379     }
 380 
 381   *tally = p->DDCW_TALLY;
 382 
 383   if (*tally == 0)
 384     {
 385       sim_debug(DBG_DEBUG, &mgp_dev,
 386                 "%s: Tally of zero interpreted as 010000(4096)\n", __func__);
 387       *tally = 4096;
 388     }
 389 
 390   sim_debug(DBG_DEBUG, &mgp_dev,
 391             "%s: Tally %d (%o)\n", __func__, *tally, *tally);
 392 
 393   if (expected_tally && *tally != expected_tally)
 394     {
 395       sim_warn("mgp_dev call expected tally of %d; got %d\n",
 396                expected_tally, *tally);
 397       p->stati = 05001; // BUG: arbitrary error code; config switch
 398 
 399       return IOM_CMD_ERROR;
 400     }
 401 
 402   return IOM_CMD_PROCEED;
 403 }
 404 
 405 static char *
 406 cmd_name(int code)
     /* [previous][next][first][last][top][bottom][index][help] */
 407 {
 408   // Where can I find documentation for these?
 409   switch (code)
 410     {
 411     case 000:
 412       return "Request status";
 413 
 414     case 001:
 415       return "Read";
 416 
 417     case 011:
 418       return "Write";
 419 
 420     case 020:
 421       return "Host switch down";
 422 
 423     case 040:
 424       return "Reset status";
 425 
 426     case 042:
 427       return "Disable Bus Back";
 428 
 429     case 043:
 430       return "Enable Bus Back";
 431 
 432     case 060:
 433       return "Host switch up";
 434 
 435     default:
 436       return "Unknown";
 437     }
 438 }
 439 
 440 static iom_cmd_rc_t
 441 mgp_cmd(uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 442 {
 443 # if defined(TESTING)
 444   cpu_state_t * cpup = _cpup;
 445 # endif
 446   iom_chan_data_t *p = &iom_chan_data[iom_unit_idx][chan];
 447 
 448   sim_debug(DBG_TRACE, &mgp_dev,
 449             "mgp_cmd CHAN_CMD %o DEV_CODE %o DEV_CMD %o COUNT %o\n",
 450             p->IDCW_CHAN_CMD, p->IDCW_DEV_CODE, p->IDCW_DEV_CMD, p->IDCW_COUNT);
 451 
 452   // Not IDCW?
 453   if (IS_NOT_IDCW(p))
 454     {
 455       sim_warn("%s: Unexpected IOTx\n", __func__);
 456 
 457       return IOM_CMD_ERROR;
 458     }
 459 
 460   bool ptro;
 461 
 462   sim_printf("mgp_cmd %#o (%s)\n",
 463              p->IDCW_DEV_CMD, cmd_name(p->IDCW_DEV_CMD));
 464 
 465   switch (p->IDCW_DEV_CMD)
 466     {
 467     case 000: // CMD 00 Request status
 468     {
 469       p->stati = 04000;
 470       sim_printf("mgp request status\n");
 471     }
 472     break;
 473 
 474     case 001: // CMD 01 Read
 475     {
 476       sim_debug(DBG_DEBUG, &mgp_dev, "%s: mgp_dev_$read\n", __func__);
 477 
 478       const uint    expected_tally = 0;
 479       uint          tally;
 480       iom_cmd_rc_t  rc
 481         = get_ddcw(p, iom_unit_idx, chan, &ptro, expected_tally, &tally);
 482       if (rc)
 483         {
 484           return rc;
 485         }
 486 
 487       word36  buffer[4096];  /* tally size is max 4096 bytes */
 488       uint    words_processed;
 489       iom_indirect_data_service(
 490         iom_unit_idx, chan, buffer, &words_processed, false);
 491 
 492       sim_printf("mgp_cmd: Read unit %#x chan %#x (%d)\n",
 493                  iom_unit_idx, chan, chan);
 494 
 495       /*
 496        * Command pending, don't send terminate interrupt
 497        */
 498 
 499       rc = IOM_CMD_PENDING;
 500 
 501       mgp_wants_to_read(iom_unit_idx, chan);
 502 # if !USE_SOCKET_DEV_APPROACH
 503       int v;
 504       if (( v = poll_from_cbridge(buffer, words_processed, 0)) < 0)
 505         {
 506           // nothing to read
 507           sim_printf("%s: nothing to read\n", __func__);
 508         }
 509       else
 510         {
 511           // something was read
 512           if (v > 0)
 513             {
 514               sim_printf("%s: read something, rc IOM_CMD_DISCONNECT\n",
 515                          __func__);
 516               rc = IOM_CMD_DISCONNECT; /* so send terminate interrupt */
 517             }
 518 
 519           dumppkt("Read", buffer, words_processed);
 520         }
 521 # endif /* if !USE_SOCKET_DEV_APPROACH */
 522 
 523       iom_indirect_data_service(
 524         iom_unit_idx, chan, buffer, &words_processed, true);
 525 
 526 
 527 
 528 
 529 
 530 
 531 
 532 
 533 
 534       p->stati = 04000; /* bogus status, since we're
 535                          * not sending terminate interrupt */
 536       return rc;
 537     }
 538     /*NOTREACHED*/ /* unreachable */
 539     break;
 540 
 541     case 011: // CMD 11 Write
 542     {
 543       sim_debug(DBG_DEBUG, &mgp_dev, "%s: mgp_dev_$write\n", __func__);
 544 
 545       const uint    expected_tally = 0;
 546       uint          tally;
 547       iom_cmd_rc_t  rc
 548         = get_ddcw(p, iom_unit_idx, chan, &ptro, expected_tally, &tally);
 549 
 550       word36  buffer[4096];  /* tally size is max 4096 bytes */
 551       uint    words_processed;
 552       iom_indirect_data_service(
 553         iom_unit_idx, chan, buffer, &words_processed, false);
 554 
 555       sim_printf("mgp_cmd: Write unit %#x chan %#x (%d)\n",
 556                  iom_unit_idx, chan, chan);
 557       dumppkt("Write", buffer, words_processed);
 558 
 559       int v = handle_mgp_packet(buffer, words_processed);
 560       sim_printf("%s: handle_mgp_packet returned %d\n", __func__, v);
 561 
 562 
 563 
 564 
 565 
 566 
 567 
 568 
 569 
 570 
 571       rc        = IOM_CMD_DISCONNECT; /* send terminate interrupt */
 572       p->stati  = 04000;
 573 
 574 
 575 
 576 
 577       iom_indirect_data_service(
 578         iom_unit_idx, chan, buffer, &words_processed, true);
 579 
 580       return rc;
 581     }
 582     /*NOTREACHED*/ /* unreachable */
 583     break;
 584 
 585     case 020: // CMD 20 Host switch down
 586     {
 587       p->stati = 04000;
 588       sim_printf("mgp host switch down\n");
 589     }
 590     break;
 591 
 592     case 040: // CMD 40 Reset status
 593     {
 594       p->stati = 04000;
 595       // is called repeatedly causing system console to be unusable
 596       // sim_printf ("mgp reset status\n");
 597     }
 598     break;
 599 
 600     case 042: // CMD 42 Disable Bus Back
 601     {
 602       p->stati = 04000;
 603       sim_printf("mgp disable bus back\n");
 604     }
 605     break;
 606 
 607     case 043: // CMD 43 Enable Bus Back
 608     {
 609       p->stati = 04000;
 610       sim_printf("mgp enable bus back\n");
 611     }
 612     break;
 613 
 614     case 060: // CMD 60 Host switch up
 615     {
 616       p->stati = 04000;
 617       sim_printf("mgp host switch up\n");
 618     }
 619     break;
 620 
 621     default:
 622     {
 623       if (p->IDCW_DEV_CMD != 051) // ignore bootload console probe
 624         {
 625           sim_warn("%s: MGP unrecognized device command  %02o\n",
 626             __func__, p->IDCW_DEV_CMD);
 627         }
 628 
 629       p->stati       = 04501; // cmd reject, invalid opcode
 630       p->chanStatus  = chanStatIncorrectDCW;
 631     }
 632       return IOM_CMD_ERROR;
 633     }
 634 
 635   if (p->IDCW_CHAN_CMD == 0)
 636     {
 637       return IOM_CMD_DISCONNECT; // don't do DCW list
 638     }
 639 
 640   return IOM_CMD_PROCEED;
 641 }
 642 
 643 //  3 == command pending
 644 //  2 == did command
 645 //  1 == ignored command
 646 //  0 == ok
 647 // -1 == problem
 648 
 649 iom_cmd_rc_t
 650 mgp_iom_cmd(uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 651 {
 652   iom_chan_data_t *p = &iom_chan_data[iom_unit_idx][chan];
 653 
 654   // Is it an IDCW?
 655   if (IS_IDCW(p))
 656     {
 657       return mgp_cmd(iom_unit_idx, chan);
 658     }
 659 
 660   sim_printf("%s expected IDCW\n", __func__);
 661 
 662   return IOM_CMD_ERROR;
 663 }
 664 
 665 void
 666 mgp_process_event(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 667 {
 668 # if USE_SOCKET_DEV_APPROACH
 669   if (mgp_dev_state.want_to_read)
 670     {
 671       uint iom_unit_idx = mgp_dev_state.read_unit_idx;
 672       uint chan         = mgp_dev_state.read_unit_chan;
 673       // This is normally 128 or 129, needs 4 for header + 488/4 data = 128
 674       word36 buffer[128];
 675       uint words_processed = 128;
 676       (void)memset(buffer, 0, sizeof(buffer));
 677 
 678       int v = poll_from_cbridge(buffer, words_processed, 0);
 679       // mgp_dev_state.want_to_read = 0;
 680       if (v <= 0)
 681         {
 682           // nothing to read
 683           // sim_printf("%s: nothing to read\n", __func__);
 684         }
 685       else if (v > 0)
 686         {
 687           sim_printf("%s: read something (%d) for unit %d chan %d\n", __func__,
 688                      v, iom_unit_idx, chan);
 689           dumppkt("Read", buffer, words_processed);
 690           iom_indirect_data_service(
 691               iom_unit_idx, chan, buffer, &words_processed, true);
 692           send_terminate_interrupt(iom_unit_idx, chan);
 693         }
 694     }
 695 # else
 696   int v = poll_from_cbridge(NULL, 0, 1);
 697   if (v > 0)
 698     {
 699       uint iom_unit_idx = mgp_dev_state.read_unit_idx;
 700       uint chan         = mgp_dev_state.read_unit_chan;
 701       if (iom_chan_data[iom_unit_idx][chan].in_use != false )
 702         {
 703           // And avoid complaints
 704           sim_printf("%s: poll %d, terminate interrupt unit \"%s\": iom "
 705                      "unit %#x, chan %#x\n", __func__, v,
 706                      mgp_state[iom_unit_idx].device_name,
 707                      iom_unit_idx, chan);
 708           send_terminate_interrupt(iom_unit_idx, chan);
 709         }
 710     }
 711 # endif /* if USE_SOCKET_DEV_APPROACH */
 712 }
 713 
 714 # define CBRIDGE_PACKET_SOCKET        "/tmp/chaos_packet"
 715 # define CBRIDGE_PACKET_HEADER_SIZE   4
 716 # define CH_PK_MAX_DATALEN            488
 717 
 718 // Chaosnet opcodes
 719 enum
 720 {
 721   CHOP_RFC = 1,
 722   CHOP_OPN,
 723   CHOP_CLS,
 724   CHOP_FWD,
 725   CHOP_ANS,
 726   CHOP_SNS,
 727   CHOP_STS,
 728   CHOP_RUT,
 729   CHOP_LOS,
 730   CHOP_LSN,
 731   CHOP_MNT,
 732   CHOP_EOF,
 733   CHOP_UNC,
 734   CHOP_BRD,
 735   CHOP_ACK  = 0177, // Note: extension for the NCP Packet socket
 736   CHOP_DAT  = 0200,
 737   CHOP_DWD  = 0300
 738 };
 739 
 740 enum mgp_pktypes
 741 {
 742   pktype_NOOP = 1,
 743   pktype_CONNECT,
 744   pktype_OPEN,
 745   pktype_CLOSE,
 746   pktype_LOSE,
 747   pktype_STATUS,
 748   pktype_SEND_STATUS,
 749   pktype_ORDER,
 750   pktype_DATA = 255
 751 };
 752 
 753 static char *pktype_names[] = {
 754   "NULL", "NOOP",   "CONNECT",     "OPEN",  "CLOSE",
 755   "LOSE", "STATUS", "SEND_STATUS", "ORDER", NULL
 756   };
 757 
 758 static char *chop_names[] = {
 759   "NIL", "RFC", "OPN", "CLS", "FWD", "ANS", "SNS", "STS",
 760   "RUT", "LOS", "LSN", "MNT", "EOF", "UNC", "BRD"
 761   };
 762 
 763 static char *
 764 pktype_name(uint t)
     /* [previous][next][first][last][top][bottom][index][help] */
 765 {
 766   if (( t > 0 ) && ( t <= pktype_ORDER ))
 767     {
 768       return pktype_names[t];
 769     }
 770   else if (t == pktype_DATA)
 771     {
 772       return "DATA";
 773     }
 774   else
 775     {
 776       return NULL;
 777     }
 778 }
 779 
 780 static char *
 781 chop_name(uint c)
     /* [previous][next][first][last][top][bottom][index][help] */
 782 {
 783   if (( c > 0 ) && ( c <= CHOP_BRD ))
 784     {
 785       return chop_names[c];
 786     }
 787   else if (c == CHOP_ACK)
 788     {
 789       return "ACK";
 790     }
 791   else if (c >= 0200)  //-V536  /* Decimal: 128; Octal: 0200 */
 792     {
 793       return "DAT";
 794     }
 795   else
 796     {
 797       return NULL;
 798     }
 799 }
 800 
 801 // Number of words in an MGP packet header
 802 # define MGP_PACKET_HEADER_SIZE  4
 803 
 804 struct mgp_packet_header
 805 {
 806   // The u_char fields are "technically" 9-bit,
 807   // but they are always 8-bit in reality
 808   u_char checksum;             /* Checksum low byte in first word          */
 809   u_char identification;       /* A character that always appears here (#) */
 810   u_char packet_type;          /* Similar to Chaos operation code          */
 811   struct
 812   {                            /* bits about packet                        */
 813     u_int unusable  : 1;       /* can't transfer this bit to/from PDP-11   */
 814     u_int nak       : 1;       /* This packet is NAKing some packet        */
 815     u_int reply_now : 1;       /* This packet requires an immediate reply  */
 816     u_int padding   : 5;       /* Unused, reserved                         */
 817     u_int loopback  : 1;       /* Used for detecting errors                */
 818   } flags;
 819   u_char frame_number;         /* Per-link flow control                    */
 820   u_char receipt_number;       /* ditto                                    */
 821   u_char packet_number;        /* Per-connection flow control              */
 822   u_char ack_number;           /* ditto                                    */
 823   // These three are 2 x 9-bit in Multics, but implemented as 2 x 8-bit
 824   u_short byte_count;          /* Number of bytes in data                  */
 825   u_short source_process;      /* Who it came from                         */
 826   u_short destination_process; /* Who it's going to                        */
 827   u_char chaos_opcode;         /* The opcode in the original packet        */
 828   u_char reserved;             /* Not yet used.   MBZ                      */
 829 };
 830 
 831 int
 832 valid_chaos_host_address(u_short addr)
     /* [previous][next][first][last][top][bottom][index][help] */
 833 {
 834   // both subnet and host part must be non-zero
 835   return ( addr > 0xff ) && (( addr & 0xff ) != 0 );
 836 }
 837 
 838 // Copy Multics packet data (9-bit) to cbridge packet data (8-bit).
 839 // words is max #words in buf, dlen is max #bytes in dest.
 840 static void
 841 copy_packet9_to_cbridge8(word36 *buf, uint words, u_char *dest, int dlen)
     /* [previous][next][first][last][top][bottom][index][help] */
 842 {
 843 # if !defined(__clang_analyzer__)
 844   int j;
 845   /* Convert from 9-bit to 8-bit */
 846   for (j = 0; j < words * 4 && j < dlen; j++)
 847     {
 848       // Clang Analyzer warning: 1st function call argument is an uninitialized value
 849       dest[j] = getbits36_9(buf[MGP_PACKET_HEADER_SIZE + j / 4], ( j % 4 ) * 9);
 850     }
 851 # endif /* if !defined(__clang_analyzer__) */
 852 }
 853 
 854 // and the other way around
 855 static void
 856 copy_cbridge8_to_packet9(u_char *src, int slen, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
 857 {
 858   int j;
 859   /* Convert from 8-bit to 9-bit */
 860   for (j = 0; j < words * 4 && j < slen; j++)
 861     {
 862       putbits36_9(&buf[MGP_PACKET_HEADER_SIZE + j / 4], ( j % 4 ) * 9, src[j]);
 863     }
 864 }
 865 
 866 // cf mgp_checksum_.pl1
 867 // Compute checksum on a raw Multics packet
 868 u_char
 869 mgp_checksum_raw(word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
 870 {
 871   int j, cks = 0;
 872   // Skip checksum and ident bytes
 873   for (j = 2; j < words * 4; j++)
 874     {
 875       cks += getbits36_9(buf[j / 4], ( j % 4 ) * 9);
 876     }
 877 
 878   return cks % 256;
 879 }
 880 
 881 // Compute checksum on a header struct and 8-bit byte body
 882 u_char
 883 mgp_checksum(struct mgp_packet_header *p, u_char *pkt, uint pklen)
     /* [previous][next][first][last][top][bottom][index][help] */
 884 {
 885   uint i, cks = 0;
 886 
 887   // Flags are actually 9 bits!
 888   cks  = ( p->flags.unusable  << 8 )
 889        | ( p->flags.nak       << 7 )
 890        | ( p->flags.reply_now << 6 )
 891        | ( p->flags.padding   << 1 )
 892        |   p->flags.loopback;
 893 
 894   cks  +=  p->packet_type
 895        +   p->frame_number
 896        +   p->receipt_number
 897        +   p->packet_number
 898        +   p->ack_number
 899        + ( p->byte_count           & 0xff )
 900        + ( p->byte_count          >> 8    )
 901        + ( p->source_process       & 0xff )
 902        + ( p->source_process      >> 8    )
 903        + ( p->destination_process  & 0xff )
 904        + ( p->destination_process >> 8    )
 905        +   p->chaos_opcode;
 906   for (i = 0; i < pklen; i++)
 907     {
 908       cks += pkt[i];
 909     }
 910 
 911   return cks % 256;
 912 }
 913 
 914 static struct mgp_packet_header *
 915 parse_packet_header(word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
 916 {
 917   if (words * 4 < sizeof ( struct mgp_packet_header ))
 918     {
 919       sim_printf("%s: buffer too small (%d words) for mgp packet header\n",
 920                  __func__, words);
 921 
 922       return NULL;
 923     }
 924 
 925   struct mgp_packet_header *p = malloc(sizeof ( struct mgp_packet_header ));
 926   if (p == NULL)
 927     {
 928       (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
 929                      __func__, __FILE__, __LINE__);
 930 # if defined(USE_BACKTRACE)
 931 #  if defined(SIGUSR2)
 932       (void)raise(SIGUSR2);
 933       /*NOTREACHED*/ /* unreachable */
 934 #  endif /* if defined(SIGUSR2) */
 935 # endif /* if defined(USE_BACKTRACE) */
 936       abort();
 937     }
 938 
 939   int checksum        = getbits36_9(buf[0],  0);
 940   int id              = getbits36_9(buf[0],  9);
 941   int pktype          = getbits36_9(buf[0], 18);
 942   // int flags        = getbits36_9(buf[0], 27);
 943   int f_unus          = getbits36_1(buf[0], 27);
 944   int f_nak           = getbits36_1(buf[0], 28);
 945   int f_rnow          = getbits36_1(buf[0], 29);
 946   int f_pad           = getbits36_5(buf[0], 30);
 947   int f_loop          = getbits36_1(buf[0], 35);
 948 
 949   p->checksum         = checksum;
 950   p->identification   = id;
 951   p->packet_type      = pktype;
 952   p->flags.unusable   = f_unus;
 953   p->flags.nak        = f_nak;
 954   p->flags.reply_now  = f_rnow;
 955   p->flags.padding    = f_pad;
 956   p->flags.loopback   = f_loop;
 957 
 958   int framenr         = getbits36_9(buf[1],  0);
 959   int rcpt            = getbits36_9(buf[1],  9);
 960   int pknr            = getbits36_9(buf[1], 18);
 961   int acknr           = getbits36_9(buf[1], 27);
 962 
 963   p->frame_number     = framenr;
 964   p->receipt_number   = rcpt;
 965   p->packet_number    = pknr;
 966   p->ack_number       = acknr;
 967 
 968   // Note: 8-bit byte values combine to 16-bit values.
 969   int bytecount  =     ( getbits36_9(buf[2],  0) & 0xff )
 970                     | (( getbits36_9(buf[2],  9) & 0xff ) << 8 );
 971   int srcprc     =     ( getbits36_9(buf[2], 18) & 0xff )
 972                     | (( getbits36_9(buf[2], 27) & 0xff ) << 8 );
 973 
 974   p->byte_count      = bytecount;
 975   p->source_process  = srcprc;
 976 
 977   int dstprc     =     ( getbits36_9(buf[3],  0) & 0xff )
 978                     | (( getbits36_9(buf[3],  9) & 0xff ) << 8 );
 979   int chopcode   =       getbits36_9(buf[3], 18);
 980   int mbz        =       getbits36_9(buf[3], 27);
 981 
 982   p->destination_process  = dstprc;
 983   p->chaos_opcode         = chopcode;
 984   p->reserved             = mbz;
 985 
 986   return p;
 987 }
 988 
 989 static void
 990 unparse_packet_header(struct mgp_packet_header *p, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
 991 {
 992   if (words * 4 < sizeof ( struct mgp_packet_header ))
 993     {
 994       sim_printf("%s: buffer too small (%d words) for mgp packet header\n",
 995                  __func__, words);
 996 
 997       return;
 998     }
 999 
1000   putbits36_9(&buf[0],  0, p->checksum);
1001   putbits36_9(&buf[0],  9, p->identification);
1002   putbits36_9(&buf[0], 18, p->packet_type);
1003   putbits36_1(&buf[0], 27, p->flags.unusable);
1004   putbits36_1(&buf[0], 28, p->flags.nak);
1005   putbits36_1(&buf[0], 29, p->flags.reply_now);
1006   putbits36_5(&buf[0], 30, p->flags.padding);
1007   putbits36_1(&buf[0], 35, p->flags.loopback);
1008 
1009   putbits36_9(&buf[1],  0, p->frame_number);
1010   putbits36_9(&buf[1],  9, p->receipt_number);
1011   putbits36_9(&buf[1], 18, p->packet_number);
1012   putbits36_9(&buf[1], 27, p->ack_number);
1013 
1014   // Note: these mgp_packet_header values
1015   // are 16 bits, and put in 9-bit fields
1016 
1017   putbits36_9(&buf[2],  0, p->byte_count      & 0xff);
1018   putbits36_9(&buf[2],  9, p->byte_count     >> 8   );
1019   putbits36_9(&buf[2], 18, p->source_process  & 0xff);
1020   putbits36_9(&buf[2], 27, p->source_process >> 8   );
1021 
1022   putbits36_9(&buf[3],  0, p->destination_process  & 0xff);
1023   putbits36_9(&buf[3],  9, p->destination_process >> 8   );
1024 
1025   putbits36_9(&buf[3], 18, p->chaos_opcode);
1026   putbits36_9(&buf[3], 27, p->reserved);
1027 }
1028 
1029 static void
1030 dumppkt(char *hdr, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1031 {
1032   int i;
1033   struct mgp_packet_header *p = parse_packet_header(buf, words);
1034   if (p == NULL)
1035     {
1036       sim_printf("%s: failed to parse packet!\n", __func__);
1037 
1038       return;
1039     }
1040 
1041   sim_printf("%s packet (%d words)\n", hdr, words);
1042   sim_printf("cks %#x, id %#x, type %#x (%s), flags %#x (%s%s%s%s)\n"
1043              "frame %#x, rcpt %#x, pknr %#x, acknr %#x\n"
1044              "bytecount %d, src %#x, dst %#x, chopcode %#o (%s)\n",
1045              p->checksum, p->identification, p->packet_type,
1046              pktype_name(p->packet_type),
1047              ( p->flags.unusable << 8 ) | ( p->flags.nak << 7 )
1048              | ( p->flags.reply_now << 6 ) | ( p->flags.padding << 1 )
1049              | p->flags.loopback, p->flags.unusable ? "unusable " : "",
1050              p->flags.nak ? "NAK " : "", p->flags.reply_now ? "rNOW " : "",
1051              p->flags.loopback ? "loop" : "", p->frame_number,
1052              p->receipt_number, p->packet_number, p->ack_number,
1053              p->byte_count, p->source_process, p->destination_process,
1054              p->chaos_opcode, chop_name(p->chaos_opcode));
1055 
1056   if (p->identification != '#')
1057     {
1058       sim_printf("[Warning: identification byte is %d instead of %d]\n",
1059                  p->identification, '#');
1060     }
1061 
1062   if (p->reserved != 0)
1063     {
1064       sim_printf("[Warning: MBZ byte is %d]\n", p->reserved);
1065     }
1066 
1067   int pklen = 4 + ( p->byte_count / 4 ) \
1068                 + ( p->byte_count % 4 ? 1 : 0 );
1069   FREE(p);
1070   for (i = 0; i < pklen; i++)
1071     {
1072       int lh  = getbits36_18 (buf[i],  0);
1073       int rh  = getbits36_18 (buf[i], 18);
1074       int b0  = getbits36_9  (buf[i],  0);
1075       int b1  = getbits36_9  (buf[i],  9);
1076       int b2  = getbits36_9  (buf[i], 18);
1077       int b3  = getbits36_9  (buf[i], 27);
1078       if (i < MGP_PACKET_HEADER_SIZE)
1079         {
1080           sim_printf(" %d: %06o,,%06o = 0x%02x %02x %02x %02x\n",
1081                      i, lh, rh, b0, b1, b2, b3);
1082         }
1083       else
1084         {
1085           /* avoid printing NULs for the console output to work */
1086           char chars[128], *cp = chars;
1087           (void)memset(chars, 0, sizeof ( chars ));
1088           if (b0 && b0 < 0177 && b0 >= 040)
1089             {
1090               cp += sprintf(cp, "'%c' ",
1091                       b0);
1092             }
1093           else
1094             {
1095               cp += sprintf(cp, "'^%c' ",
1096                       b0 < 0100 ? b0 + 0100 : b0 - 0100);
1097             }
1098 
1099           if (b1 && b1 < 0177 && b1 >= 040)
1100             {
1101               cp += sprintf(cp, "'%c' ",
1102                       b1);
1103             }
1104           else
1105             {
1106               cp += sprintf(cp, "'^%c' ",
1107                       b1 < 0100 ? b1 + 0100 : b1 - 0100);
1108             }
1109 
1110           if (b2 && b2 < 0177 && b2 >= 040)
1111             {
1112               cp += sprintf(cp, "'%c' ",
1113                       b2);
1114             }
1115           else
1116             {
1117               cp += sprintf(cp, "'^%c' ",
1118                       b2 < 0100 ? b2 + 0100 : b2 - 0100);
1119             }
1120 
1121           if (b3 && b3 < 0177 && b3 >= 040)
1122             {
1123               cp += sprintf(cp, "'%c'",
1124                       b3);
1125             }
1126           else
1127             {
1128               cp += sprintf(cp, "'^%c'",
1129                       b3 < 0100 ? b3 + 0100 : b3 - 0100);
1130             }
1131 
1132           sim_printf(" %d: %06o,,%06o = 0x%02x %02x %02x %02x = %s\n",
1133                      i, lh, rh, b0, b1, b2, b3, chars);
1134         }
1135     }
1136 
1137   sim_printf("EOP\n"); /* although this helps */
1138 }
1139 
1140 // Pipe for sending conn index which needs to have a STATUS packet sent for
1141 static int status_conns[2];
1142 
1143 static void
1144 mgp_init_dev_state(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1145 {
1146   (void)memset(&mgp_dev_state, 0, sizeof ( mgp_dev_state ));
1147   // Start reading at the lowest index
1148   mgp_dev_state.read_index  = -1;
1149 
1150   status_conns[0] = status_conns[1] = 0;
1151   if (pipe(status_conns) < 0)
1152     {
1153       sim_printf("%s: error from pipe(): %s (%d)\n",
1154                  __func__, xstrerror_l(errno), errno);
1155     }
1156 
1157   // Init randomness
1158   uint32_t h = 0;  /* initial hash value */
1159 # if __STDC_VERSION__ < 201112L
1160   /* LINTED E_OLD_STYLE_FUNC_DECL */
1161   void *(*mallocptr)() = malloc;
1162   h = hash32s(&mallocptr, sizeof(mallocptr), h);
1163 # endif /* if __STDC_VERSION__ < 201112L */
1164   void *small = malloc(1);
1165   h = hash32s(&small, sizeof(small), h);
1166   FREE(small);
1167   void *big = malloc(1UL << 20);
1168   h = hash32s(&big, sizeof(big), h);
1169   FREE(big);
1170   void *ptr = &ptr;
1171   h = hash32s(&ptr, sizeof(ptr), h);
1172   time_t t = time(0);
1173   h = hash32s(&t, sizeof(t), h);
1174 # if !defined(_AIX)
1175   for (int i = 0; i < 1000; i++)
1176     {
1177       unsigned long counter = 0;
1178       clock_t start = clock();
1179       while (clock() == start)
1180         {
1181           counter++;
1182         }
1183       h = hash32s(&start, sizeof(start), h);
1184       h = hash32s(&counter, sizeof(counter), h);
1185     }
1186 # endif /* if !defined(_AIX) */
1187   int mypid = (int)getpid();
1188   h = hash32s(&mypid, sizeof(mypid), h);
1189   char rnd[4];
1190   FILE *f = fopen("/dev/urandom", "rb");
1191   if (f)
1192     {
1193       if (fread(rnd, sizeof(rnd), 1, f))
1194         {
1195           h = hash32s(rnd, sizeof(rnd), h);
1196         }
1197       fclose(f);
1198     }
1199   srandom(h);
1200 }
1201 
1202 static void
1203 mgp_wants_to_read(uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
1204 {
1205   mgp_dev_state.read_unit_idx  = iom_unit_idx;
1206   mgp_dev_state.read_unit_chan = chan;
1207   mgp_dev_state.want_to_read   = 1;
1208 }
1209 
1210 // Find the first conn which has a zero skt
1211 static int
1212 find_free_conn(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1213 {
1214   int i;
1215   for (i = 0; i < MAX_CONNS; i++)
1216     {
1217       if (mgp_dev_state.conns[i].skt == 0)
1218         {
1219           return i;
1220         }
1221     }
1222 
1223   return -1;
1224 }
1225 
1226 // Find the conn for <remote,local> id.
1227 // local may be 0 which matches all local ids.
1228 static int
1229 find_conn_for(int remote, int local)
     /* [previous][next][first][last][top][bottom][index][help] */
1230 {
1231   int i;
1232   for (i = 0; i < MAX_CONNS; i++)
1233     {
1234       if ( ( mgp_dev_state.conns[i].multics_proc != 0 )
1235         && ( mgp_dev_state.conns[i].multics_proc == remote )
1236         && (( local == 0 ) || ( mgp_dev_state.conns[i].local_id == local )) )
1237         {
1238           return i;
1239         }
1240     }
1241 
1242   return -1;
1243 }
1244 
1245 // Return a malloc'd pkt with cbridge header filled in.
1246 static u_char *
1247 make_cbridge_pkt(int len, int opcode)
     /* [previous][next][first][last][top][bottom][index][help] */
1248 {
1249   u_char *pkt = malloc(len + CBRIDGE_PACKET_HEADER_SIZE); /* space for cbridge header */
1250   if (pkt == NULL)
1251     {
1252       (void)fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1253                      __func__, __FILE__, __LINE__);
1254 # if defined(USE_BACKTRACE)
1255 #  if defined(SIGUSR2)
1256       (void)raise(SIGUSR2);
1257       /*NOTREACHED*/ /* unreachable */
1258 #  endif /* if defined(SIGUSR2) */
1259 # endif /* if defined(USE_BACKTRACE) */
1260       abort();
1261     }
1262   (void)memset(pkt, 0, len + CBRIDGE_PACKET_HEADER_SIZE);
1263 
1264   pkt[0]  = opcode;
1265   pkt[2]  = len & 0xff;
1266   pkt[3]  = len >> 8;
1267 
1268   return pkt;
1269 }
1270 
1271 static u_char *
1272 make_rfc_pkt(int *len, char *host, char *contact, char *args)
     /* [previous][next][first][last][top][bottom][index][help] */
1273 {
1274   /* cbridge header + strings with spaces + NUL */
1275   *len = strlen(host) + 1 + strlen(contact) + \
1276          ( args == NULL ? 0 : 1 + strlen(args) ) + 1;
1277 
1278   u_char *pkt = make_cbridge_pkt(*len, CHOP_RFC);
1279   (void)sprintf((char *)&pkt[CBRIDGE_PACKET_HEADER_SIZE],
1280                 "%s %s%s%s", host, contact,
1281                 args == NULL || *args == '\0' ? "" : " ",
1282                 args == NULL || *args == '\0' ? "" : args);
1283 
1284   return pkt;
1285 }
1286 
1287 // Open a packet socket to cbridge (done for each conn)
1288 int
1289 cbridge_open_socket(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1290 {
1291   int slen, sock;
1292   struct sockaddr_un server;
1293 
1294   if (( sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
1295     {
1296       // Check for "out of sockets" or similar?
1297       sim_printf("%s: socket(AF_UNIX) error: %s (%d)",
1298                  __func__, xstrerror_l(errno), errno); // @@@@ handle error better?
1299 
1300       return sock;
1301     }
1302 
1303   server.sun_family  = AF_UNIX;
1304   (void)sprintf(server.sun_path, "%s", CBRIDGE_PACKET_SOCKET);
1305   slen = strlen(server.sun_path) + 1 + sizeof ( server.sun_family );
1306 
1307   if (connect(sock, (struct sockaddr *)&server, slen) < 0)
1308     {
1309       sim_printf("%s: connect(%s) error: %s (%d)", __func__,
1310                  server.sun_path, xstrerror_l(errno), errno);
1311       // @@@@ let the device go down, instead
1312       close(sock);
1313       sock = 0;
1314     }
1315 
1316   return sock;
1317 }
1318 
1319 static void
1320 close_conn(int i)
     /* [previous][next][first][last][top][bottom][index][help] */
1321 {
1322   if (i < 0)
1323     {
1324       sim_printf("%s: closing conn %d which is invalid!\n", __func__, i);
1325       return;
1326     }
1327   sim_printf("%s: closing conn %d <%#x,%#x>, remote %#o, contact \"%s\"\n",
1328              __func__, i,
1329              mgp_dev_state.conns[i].multics_proc,
1330              mgp_dev_state.conns[i].local_id,
1331              mgp_dev_state.conns[i].remote_addr,
1332              mgp_dev_state.conns[i].contact_name);
1333 
1334   if (mgp_dev_state.conns[i].skt > 0)
1335     {
1336       close(mgp_dev_state.conns[i].skt);
1337     }
1338 
1339   mgp_dev_state.conns[i].multics_proc  = 0;
1340   mgp_dev_state.conns[i].local_id      = 0;
1341   if (mgp_dev_state.conns[i].contact_name != NULL)
1342     {
1343       FREE(mgp_dev_state.conns[i].contact_name);
1344     }
1345 
1346   mgp_dev_state.conns[i].contact_name  = NULL;
1347   mgp_dev_state.conns[i].remote_addr   = 0;
1348 }
1349 
1350 static int
1351 cbridge_send_packet(int i, u_char *pkt, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1352 {
1353   int skt  = mgp_dev_state.conns[i].skt;
1354   int x    = write(skt, pkt, len);
1355   if (x < 0)
1356     {
1357       // @@@@ handle error, pass it on to Multics
1358       if (( errno == EBADF      )  \
1359        || ( errno == ECONNRESET )  \
1360        || ( errno == EPIPE      ))
1361         {
1362           sim_printf("%s: socket seems to have closed: %s\n",
1363                      __func__, xstrerror_l(errno));
1364           close_conn(i);
1365         }
1366       else
1367         {
1368           sim_warn("%s: socket write error: %s (%d)\n",
1369                    __func__, xstrerror_l(errno), errno);
1370         }
1371     }
1372   else if (x != len)
1373     {
1374       sim_printf("%s: wrote %d bytes (expected %d)\n", __func__, x, len);
1375     }
1376 
1377   FREE(pkt);
1378   return x;
1379 }
1380 
1381 // Handle packets from Multics, send them to cbridge
1382 static int
1383 handle_packet(int opcode, struct mgp_packet_header *p, word36 *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
1384               uint words)
1385 {
1386   int i = find_conn_for(p->source_process, p->destination_process);
1387   if (i < 0)
1388     {
1389       sim_warn("%s: can't find conn for %#x,%#x\n",
1390                __func__, p->source_process, p->destination_process);
1391       return -1;
1392     }
1393 
1394   u_char *pkt = make_cbridge_pkt(p->byte_count, opcode);
1395   if (p->byte_count > 0)
1396     {
1397       copy_packet9_to_cbridge8(
1398         buf, words, pkt + CBRIDGE_PACKET_HEADER_SIZE, p->byte_count);
1399     }
1400 
1401   return cbridge_send_packet(
1402                  i, pkt, CBRIDGE_PACKET_HEADER_SIZE + p->byte_count);
1403 }
1404 
1405 static int
1406 handle_close(struct mgp_packet_header *p, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1407 {
1408   // Close the connection in a controlled way:
1409   // first send and EOF with payload "wait",
1410   // which makes cbridge send the EOF and wait (some time) for its
1411   // acknowledgement, and then send an ACK packet here. When the ACK arrives,
1412   // send the CLS. (No need to save a close message somewhere, since Multics
1413   // doesn't include any data.)
1414   word36 eof[1];
1415   copy_cbridge8_to_packet9((u_char *)"wait", 4, buf, 1);
1416 
1417   return handle_packet(CHOP_EOF, p, eof, 1);
1418 }
1419 
1420 static int
1421 handle_lose(int conni, struct mgp_packet_header *p, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1422 {
1423   // send LOS, close socket, clear out our conn
1424   int v = handle_packet(CHOP_LOS, p, buf, words);
1425   // after sending a LOS, the connection is gone
1426   close_conn(conni);
1427 
1428   return v;
1429 }
1430 
1431 static int
1432 handle_connect(struct mgp_packet_header *p, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1433 {
1434   char connect_string[256], *net, *host, *contact, *args;
1435   char *i;
1436   copy_packet9_to_cbridge8(buf,
1437     words, (u_char *)connect_string, sizeof ( connect_string ));
1438   sim_printf("%s: connect string is \"%s\"\n", __func__, connect_string);
1439   // Parse the connect string, something like "CHAOS 12234 NAME /W BV"
1440   net  = connect_string;
1441   i    = index(net, ' ');
1442   if (i == NULL)
1443     {
1444       sim_printf("%s: bad connect string: first space not found\n", __func__);
1445 
1446       return -1;
1447     }
1448 
1449   *i    = '\0';
1450   host  = i + 1;
1451   i     = index(host, ' ');
1452   if (i == NULL)
1453     {
1454       sim_printf("%s: bad connect string: second space not found\n", __func__);
1455 
1456       return -1;
1457     }
1458 
1459   *i       = '\0';
1460   contact  = i + 1;
1461   i        = index(contact, ' ');
1462   if (i == NULL)
1463     {
1464       sim_printf("%s: third space not found, no contact args\n", __func__);
1465       args = NULL;
1466     }
1467   else
1468     {
1469       *i    = '\0';
1470       args  = i + 1;
1471     }
1472 
1473   sim_printf("%s: parsed connect string: net \"%s\", host \"%s\", contact "
1474              "\"%s\", args \"%s\"\n", __func__, net, host, contact, args);
1475   if (strcasecmp(net, "CHAOS") != 0)
1476     {
1477       sim_printf("%s: not CHAOS net, ignoring\n", __func__);
1478 
1479       return -1;
1480     }
1481 
1482   // Now find a free slot in mgp_dev_state.conns,
1483   int cindex               = find_free_conn();
1484   if (cindex < 0)
1485     {
1486       sim_printf("%s: no free conns available!\n", __func__);
1487       return -1;
1488     }
1489   struct conn_table *conn  = &mgp_dev_state.conns[cindex];
1490   // save the contact name
1491   if (conn->contact_name) /* Free any old string */
1492     {
1493       FREE(conn->contact_name);
1494     }
1495 
1496   conn->contact_name = strdup(contact);
1497   // parse the host address and save it
1498   u_short raddr;
1499   if (( sscanf(host, "%ho", &raddr) != 1 ) || !valid_chaos_host_address(raddr))
1500     {
1501       sim_printf("%s: bad remote address %s\n", __func__, host);
1502 
1503       return -1;
1504     }
1505   else
1506     {
1507       conn->remote_addr = raddr;
1508     }
1509 
1510   // make a local id, fill in multics id,
1511   conn->local_id      = random() % ( 1 << 16 ); /* srandom() called in mgp_init_dev_state */
1512   conn->multics_proc  = p->source_process;
1513   // open a socket,
1514   int cbskt = cbridge_open_socket();
1515   if (cbskt < 0)
1516     {
1517       sim_printf("%s: unable to get a socket\n", __func__);
1518 
1519       return cbskt;
1520     }
1521 
1522   conn->skt = cbskt;
1523   // construct a cbridge packet,
1524   int cblen;
1525   u_char *cbpkt = make_rfc_pkt(&cblen, host, contact, args);
1526 
1527   // send the packet on it
1528   int v = cbridge_send_packet(cindex, cbpkt,
1529               CBRIDGE_PACKET_HEADER_SIZE + cblen);  /* incl header pls */
1530 
1531   if (v < 0)
1532     {
1533       // failed sending, close it again
1534       // @@@@ and pass on error to Multics
1535       close_conn(cindex);
1536 
1537       return -1;
1538     }
1539   else
1540     {
1541       int i = cindex;
1542       sim_printf(
1543            "%s: opened conn %d <%#x,%#x>, remote %#o, contact \"%s\"\n",
1544            __func__, i, mgp_dev_state.conns[i].multics_proc,
1545            mgp_dev_state.conns[i].local_id, mgp_dev_state.conns[i].remote_addr,
1546            mgp_dev_state.conns[i].contact_name);
1547 
1548       return cindex;
1549     }
1550 }
1551 
1552 // Given pkt read from Multics, act on it
1553 static int
1554 handle_mgp_packet(word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1555 {
1556   struct mgp_packet_header *p  = parse_packet_header(buf, words);
1557   int rval                     = 0;
1558 
1559   if (   ( p->checksum       == 0 ) \
1560       && ( p->packet_type    == 0 ) \
1561       && ( p->frame_number   == 0 ) \
1562       && ( p->receipt_number == 0 ) )
1563     {
1564       FREE(p);
1565       // Not a real packet, ignore
1566       return 0;
1567     }
1568 
1569   if (mgp_dev_state.first_frame_received
1570       && ( p->frame_number != ( mgp_dev_state.frame_last_received + 1 )))
1571     {
1572       sim_printf("%s: unordered frame %#x read, expected %#x\n", __func__,
1573                  p->frame_number, mgp_dev_state.frame_last_received + 1);
1574       // send NAK?
1575     }
1576   else
1577     {
1578       mgp_dev_state.first_frame_received = 1;
1579     }
1580 
1581   int i = find_conn_for(p->source_process, p->destination_process);
1582   sim_printf(
1583           "%s: packet %#x (ack %#x) for conn %d <%#x,%#x>, pktype %d (%s)\n",
1584           __func__, p->packet_number, p->ack_number, i,
1585           i < 0 ? 0 : mgp_dev_state.conns[i].multics_proc,
1586           i < 0 ? 0 : mgp_dev_state.conns[i].local_id,
1587           p->packet_type, pktype_name(p->packet_type));
1588 
1589   int pktype = p->packet_type;
1590   switch (pktype)
1591     {
1592     case pktype_NOOP:
1593       // NOOP seems to be nonspecific to conn, just conveying frame/receipt
1594       // (handled above/below)
1595       break;
1596 
1597     case pktype_CONNECT:
1598       rval = handle_connect(p, buf, words);
1599       break;
1600 
1601     case pktype_OPEN:
1602       // make it ANS or OPN, depending on opcode
1603       rval = handle_packet(
1604         p->chaos_opcode ? p->chaos_opcode : CHOP_OPN, p, buf, words);
1605       break;
1606 
1607     case pktype_CLOSE:
1608       rval = handle_close(p, buf, words);
1609       break;
1610 
1611     case pktype_LOSE:
1612       rval = handle_lose(i, p, buf, words);
1613       break;
1614 
1615     case pktype_DATA:
1616       // just convert to DAT and send (but watch out for EOF, check opcode)
1617       rval = handle_packet(
1618         p->chaos_opcode ? p->chaos_opcode : CHOP_DAT, p, buf, words);
1619       break;
1620 
1621     case pktype_SEND_STATUS:
1622       if (status_conns[1] > 0)
1623         {
1624           char b[2] = { i, 0 };
1625           sim_printf(
1626               "%s: asking for STATUS to be sent for conn %d on status_conns\n",
1627               __func__, i);
1628           if (write(status_conns[1], b, 1) < 0)
1629             {
1630               sim_printf(
1631                   "%s: write() on status_conns failed: %s (%d)\n",
1632                   __func__, xstrerror_l(errno), errno);
1633               status_conns[1] = status_conns[0] = 0;
1634             }
1635         }
1636 
1637       break;
1638 
1639     case pktype_STATUS:
1640       sim_printf("%s: STATUS for conn %d: frame,rcpt = <%#x,%#x>, pkt,ack = "
1641             "<%#x,%#x>\n", __func__, i, p->frame_number, p->receipt_number,
1642             p->packet_number, p->ack_number);
1643       break;
1644 
1645     default:
1646       sim_printf("%s: can't handle pkt type %#o (%s) yet\n",
1647                  __func__, pktype, pktype_name(pktype));
1648       rval = -1;
1649     }
1650 
1651   // Set a mark to make a NOOP being available for reading next.
1652     if (p->flags.reply_now)
1653       {
1654         sim_printf("%s: reply_NOW set, setting flag for sending NOOP\n",
1655                    __func__);
1656         mgp_dev_state.send_noop = 1;
1657 
1658 
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   // Count the frame
1686   mgp_dev_state.frame_last_received = p->frame_number;
1687   sim_printf("%s: afterwards, frame last sent %#x, last received %#x\n",
1688              __func__, mgp_dev_state.frame_last_sent,
1689              mgp_dev_state.frame_last_received);
1690   FREE(p);
1691 
1692   return rval;
1693 }
1694 
1695 // Handle packets from cbridge, give them to Multics.
1696 
1697 // Mapping from Chaos opcode to MGP packet type
1698 u_char opcode_to_pktype[] = {
1699   0,              /* None                    */
1700   pktype_CONNECT, /* RFC                     */
1701   pktype_OPEN,    /* OPN                     */
1702   pktype_CLOSE,   /* CLS                     */
1703   0,              /* FWD (not handled)       */
1704   pktype_OPEN,    /* ANS                     */
1705   0,              /* SNS (never appears)     */
1706   pktype_STATUS,  /* STS (internal use only) */
1707   0,              /* RUT (never appears)     */
1708   pktype_LOSE,    /* LOS                     */
1709   0,              /* LSN (never appears)     */
1710   0,              /* MNT (never appears)     */
1711   pktype_DATA,    /* EOF                     */
1712   0,              /* UNC (not handled)       */
1713   pktype_CONNECT  /* BRD                     */
1714 };
1715 
1716 static void
1717 make_mgp_header(struct mgp_packet_header *p, u_char opcode, u_char *pkt,
     /* [previous][next][first][last][top][bottom][index][help] */
1718                 uint pklen, int i)
1719 {
1720   (void)memset(p, 0, sizeof ( struct mgp_packet_header ));
1721   p->identification = '#';
1722   if (( opcode > 0 ) && ( opcode <= CHOP_BRD ))
1723     {
1724       p->packet_type = opcode_to_pktype[opcode];
1725     }
1726   else if (opcode >= CHOP_DAT)
1727     {
1728       p->packet_type = pktype_DATA;
1729     }
1730   else if (i == -1) /* special case */
1731     {
1732       p->packet_type = pktype_NOOP;
1733     }
1734 
1735   /* no flags? */
1736   p->flags.reply_now  = 1;
1737   p->frame_number     = ++mgp_dev_state.frame_last_sent;
1738   p->receipt_number   = mgp_dev_state.frame_last_received;
1739   if (i >= 0)
1740     {
1741       // Never mind about these if it is a NOOP we're making
1742       p->packet_number        = ++mgp_dev_state.conns[i].pkt_last_sent;
1743       p->ack_number           =   mgp_dev_state.conns[i].pkt_last_received;
1744       p->source_process       =   mgp_dev_state.conns[i].local_id;
1745       p->destination_process  =   mgp_dev_state.conns[i].multics_proc;
1746     }
1747 
1748   p->chaos_opcode  = opcode;
1749   p->byte_count    = pklen;
1750   sim_printf(
1751         "%s: made %s (%d) f,r=<%#x,%#x> p,a=<%#x,%#x> opc %s (%d) bc %d\n",
1752         __func__, pktype_name(p->packet_type), p->packet_type, p->frame_number,
1753         p->receipt_number, p->packet_number, p->ack_number,
1754         chop_name(p->chaos_opcode), p->chaos_opcode, p->byte_count);
1755 }
1756 
1757 static int
1758 make_mgp_packet(u_char opcode, u_char *pkt, uint pklen, word36 *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
1759                 uint words, uint conni)
1760 {
1761   struct mgp_packet_header hdr;
1762 
1763   // Make an mgp header
1764   make_mgp_header(&hdr, opcode, pkt, pklen, conni);
1765 
1766   // fill in the checksum (which is computed on the 8-bit bytes!)
1767   hdr.checksum = mgp_checksum(&hdr, pkt, pklen);
1768 
1769   // fill in the header in the buffer
1770   unparse_packet_header(&hdr, buf, words);
1771 
1772   // copy the data part, converting from 8-bit to 9-bit
1773   copy_cbridge8_to_packet9(pkt, pklen, buf, words);
1774   sim_printf("%s: conn %d <%#x,%#x> made %s pkt %#x (ack %#x), frame %#x "
1775       "(rcpt %#x)\n", __func__, conni, mgp_dev_state.conns[conni].local_id,
1776       mgp_dev_state.conns[conni].multics_proc, pktype_name(hdr.packet_type),
1777       hdr.packet_number, hdr.ack_number, hdr.frame_number, hdr.receipt_number);
1778 
1779   return 0;
1780 }
1781 
1782 static int
1783 make_status_packet(int conni, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1784 {
1785   struct mgp_packet_header hdr;
1786 
1787   // Make an mgp header - reuse CHOP_STS which doesn't appear otherwise
1788   make_mgp_header(&hdr, CHOP_STS, NULL, 0, conni);
1789 
1790   // fill in the checksum (which is computed on the 8-bit bytes!)
1791   hdr.checksum = mgp_checksum(&hdr, NULL, 0);
1792 
1793   // fill in the header in the buffer
1794   unparse_packet_header(&hdr, buf, words);
1795 
1796   // (no data to copy)
1797   sim_printf("%s: conn %d <%#x,%#x> made %s pkt %#x (ack %#x), frame %#x "
1798       "(rcpt %#x)\n", __func__, conni, mgp_dev_state.conns[conni].local_id,
1799       mgp_dev_state.conns[conni].multics_proc, pktype_name(hdr.packet_type),
1800       hdr.packet_number, hdr.ack_number, hdr.frame_number, hdr.receipt_number);
1801 
1802   return 0;
1803 }
1804 
1805 static int
1806 make_noop_packet(word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1807 {
1808   struct mgp_packet_header hdr;
1809 
1810   // Make an mgp header
1811   make_mgp_header(&hdr, 0, NULL, 0, -1);
1812   hdr.packet_number  = 1;
1813 
1814   // fill in the checksum
1815   hdr.checksum       = mgp_checksum(&hdr, NULL, 0);
1816 
1817   // fill in the header in the buffer
1818   unparse_packet_header(&hdr, buf, words);
1819 
1820   // (no data to copy)
1821   sim_printf("%s: made NOOP pkt %#x (ack %#x), frame %#x (rcpt %#x)\n",
1822              __func__, hdr.packet_number, hdr.ack_number, hdr.frame_number,
1823              hdr.receipt_number);
1824 
1825   return 0;
1826 }
1827 
1828 static int
1829 make_open_packet(u_char opcode, u_char *pkt, uint pklen, word36 *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
1830                  uint words, uint conni)
1831 {
1832   if (opcode == CHOP_OPN)
1833     {
1834       // Skip content of OPN packets, which is
1835       // the ascii host name (or octal address)
1836       return make_mgp_packet(opcode, pkt, 0, buf, words, conni);
1837     }
1838   else if (opcode == CHOP_ANS)
1839     {
1840       // First two bytes is the source (useful e.g. if we sent a broadcast)
1841       u_short src = pkt[0] | ( pkt[1] << 8 );
1842       if (src != mgp_dev_state.conns[conni].remote_addr)
1843         {
1844           sim_printf("%s: got ANS from %#o but had remote addr %#o\n",
1845                      __func__, src, mgp_dev_state.conns[conni].remote_addr);
1846                      mgp_dev_state.conns[conni].remote_addr = src;
1847         }
1848 
1849       // Skip the two source bytes in the mgp packet
1850       return make_mgp_packet(opcode, pkt + 2, pklen - 2, buf, words, conni);
1851     }
1852   else
1853     {
1854       sim_warn("%s: BUG: opcode is not ANS or OPN: %s (%#o)\n",
1855                __func__, chop_name(opcode), opcode);
1856 
1857       return -1;
1858     }
1859 }
1860 
1861 static int
1862 make_connect_packet(u_char *pkt, uint pklen, word36 *buf, uint words,
     /* [previous][next][first][last][top][bottom][index][help] */
1863                     uint conni)
1864 {
1865   // An RFC cbridge pkt is almost like a mgp connect pkt
1866   char *i, *rhost, *args = NULL, connect[128];
1867   rhost = (char *)pkt;
1868   // Zap any line ending
1869   if (( i = index(rhost, '\r')) != NULL)
1870     {
1871       *i = '\0';
1872     }
1873   else if (( i = index(rhost, '\n')) != NULL)
1874     {
1875       *i = '\0';
1876     }
1877 
1878   // Find any contact args
1879   if (( i = index(rhost, ' ')) != NULL)
1880     {
1881       args  = i + 1;
1882       *i    = '\0';
1883     }
1884 
1885   // @@@@ beware: I think Multics wants the name of the remote host,
1886   // @@@@ not the address.
1887   // @@@@ But it should handle the address, I think/hope?
1888   // @@@@ Make sure contact_name is set up also when listening
1889   // @@@@ - this is future work.
1890 
1891   // Prefix with the "net", add contact name, and args
1892   if ( ( mgp_dev_state.conns[conni].contact_name == NULL )
1893    || ( *mgp_dev_state.conns[conni].contact_name == '\0' ))
1894     {
1895       sim_printf("%s: no contact name known for conn %d\n", __func__, conni);
1896 
1897       return -1;
1898     }
1899 
1900   (void)sprintf(connect, "CHAOS %s %s%s%s",
1901                 rhost, mgp_dev_state.conns[conni].contact_name,
1902                 args == NULL ? "" : " ", args == NULL ? "" : args);
1903 
1904   return make_mgp_packet(CHOP_RFC,
1905     (u_char *)connect, strlen(connect), buf, words, conni);
1906 }
1907 
1908 static int
1909 receive_cbridge_opcode(u_char copcode, u_char *cbuf, uint clen, word36 *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
1910                        uint words, int conni)
1911 {
1912   sim_printf("%s: got opcode %#o (%s)\n",
1913              __func__, copcode, chop_name(copcode));
1914   switch (copcode)
1915     {
1916     case CHOP_FWD:
1917     // These should never be seen:
1918     case CHOP_RUT:
1919     case CHOP_MNT:
1920     case CHOP_UNC:
1921     case CHOP_STS:
1922     case CHOP_SNS:
1923     // Do nothing.
1924       return -1;
1925 
1926     case CHOP_RFC: /* this can originally be a BRD, too */
1927       // format is similar, but not same
1928       return make_connect_packet(cbuf, clen, buf, words, conni);
1929 
1930     case CHOP_OPN:
1931     case CHOP_ANS:
1932       return make_open_packet(copcode, cbuf, clen, buf, words, conni);
1933 
1934     case CHOP_ACK:
1935     {
1936       // This is the ACK of an EOF[wait] (see handle_close),
1937       // so now it is time to send a CLS
1938       u_char *clspkt = make_cbridge_pkt(0, CHOP_CLS);
1939       cbridge_send_packet(conni, clspkt, 0);
1940       // After sending a CLS, the connection can be discarded (cf MIT AIM 628)
1941       close_conn(conni);
1942     }
1943     break;
1944 
1945     case CHOP_CLS:
1946     case CHOP_LOS:
1947     {
1948       // Pass it on to Multics
1949       int v = make_mgp_packet(copcode, cbuf, clen, buf, words, conni);
1950       // and then discard the connection
1951       close_conn(conni);
1952 
1953       return v;
1954     }
1955 
1956     default:
1957       // Most pkts have the same content
1958       return make_mgp_packet(copcode, cbuf, clen, buf, words, conni);
1959     }
1960 
1961   return 1;
1962 }
1963 
1964 // Read result into buf, return the number of bytes/words put there or -1.
1965 static int
1966 poll_from_cbridge(word36 *buf, uint words, uint probe_only)
     /* [previous][next][first][last][top][bottom][index][help] */
1967 {
1968   fd_set rfd;
1969   int maxfd, numfds, i, sval, cnt, rval = -1;
1970   int foundone = 0, tryagain = 0;
1971   u_char cbuf[CH_PK_MAX_DATALEN + CBRIDGE_PACKET_HEADER_SIZE]; /* Fit data + cbridge header */
1972 
1973   maxfd   = 0;
1974   numfds  = 0;
1975   // Add the status pipe to the fd set
1976   FD_ZERO(&rfd);
1977   if (status_conns[0] != 0)
1978     {
1979       FD_SET(status_conns[0], &rfd);
1980       maxfd = status_conns[0];
1981       numfds++;
1982     }
1983 
1984   // Add all existing conns
1985   for (i = 0; i < MAX_CONNS; i++)
1986     {
1987       if (mgp_dev_state.conns[i].skt != 0)
1988         {
1989           FD_SET(mgp_dev_state.conns[i].skt, &rfd);
1990           numfds++;
1991           if (mgp_dev_state.conns[i].skt > maxfd)
1992             {
1993               maxfd = mgp_dev_state.conns[i].skt;
1994             }
1995         }
1996     }
1997 
1998   if (maxfd > 0)
1999     {
2000       struct timeval timeout;
2001       do
2002         {
2003           tryagain         = 0;
2004           // set a very short timeout (e.g. 0.01ms)
2005           timeout.tv_sec   = 0;
2006           timeout.tv_usec  = 10;
2007           sval             = select(maxfd + 1, &rfd, NULL, NULL, &timeout);
2008           if (probe_only)
2009             {
2010               if ((sval < 0) && (errno == EINTR))
2011                 {
2012                   return 0; /* Timeout, nothing to read */
2013                 }
2014               else
2015                 {
2016                   return sval;
2017                 }
2018             }
2019 
2020           if (sval < 0)
2021             {
2022               if (errno == EINTR)
2023                 {
2024                   // timed out
2025                 }
2026               else
2027                 {
2028                   sim_printf(
2029                        "%s: select() error, maxfd %d, numfds %d: %s (%d)\n",
2030                        __func__, maxfd, numfds, xstrerror_l(errno), errno);
2031                 }
2032 
2033               return -1;
2034             }
2035           else if (sval > 0)
2036             {
2037               int statusconn = -1;
2038 
2039               // First see if a STATUS should be sent
2040               if (( status_conns[0] != 0 ) && FD_ISSET(status_conns[0], &rfd))
2041                 {
2042                   char b[2];
2043                   sim_printf(
2044                        "%s: about to read a byte from status_conns[0] = %d\n",
2045                        __func__, status_conns[0]);
2046                   int s = read(status_conns[0], b, 1);
2047                   if (s < 0)
2048                     {
2049                       sim_warn("%s: read on status_conns failed: %s (%d)\n",
2050                                __func__, xstrerror_l(errno), errno);
2051                       status_conns[0] = status_conns[1] = 0;
2052                     }
2053                   else if (s == 0)
2054                     {
2055                       sim_printf("%s: read on status_conns returned 0\n",
2056                                  __func__);
2057                       status_conns[0] = status_conns[1] = 0;
2058                     }
2059                   else
2060                     {
2061                       sim_printf(
2062                          "%s: read %d from status_conns, make STATUS packet\n",
2063                          __func__, b[0]);
2064                       // make a STATUS packet
2065                       statusconn = b[0];
2066                     }
2067                 }
2068 
2069               // Start at the one after the previously read index, to make it
2070               // round-robin-like
2071               for (i = mgp_dev_state.read_index + 1; i < MAX_CONNS; i++)
2072                 {
2073                   if (FD_ISSET(mgp_dev_state.conns[i].skt, &rfd))
2074                     {
2075                       mgp_dev_state.read_index = i;
2076                       // read the header first, then that many bytes
2077                       if (( cnt = read(mgp_dev_state.conns[i].skt,
2078                               cbuf, CBRIDGE_PACKET_HEADER_SIZE)) < 0)
2079                         {
2080                           // @@@@ handle error, socket closed, pass on to Multics
2081                           sim_printf(
2082                               "%s: read() header error for conn %d: %s (%d)\n",
2083                               __func__, i, xstrerror_l(errno), errno);
2084                           FD_CLR(mgp_dev_state.conns[i].skt, &rfd);
2085                           numfds--;
2086                           close_conn(i);
2087                           foundone = 0;
2088                           continue;
2089                         }
2090                       else if (cnt == 0)
2091                         {
2092                           sim_printf(
2093                               "%s: read() header zero length conn %d, assuming closed\n",
2094                               __func__, i);
2095                           FD_CLR(mgp_dev_state.conns[i].skt, &rfd);
2096                           numfds--;
2097                           close_conn(i);
2098                           foundone = 0;
2099                           continue;
2100                         }
2101                       else if (cnt != CBRIDGE_PACKET_HEADER_SIZE)
2102                         {
2103                           sim_printf(
2104                                 "%s: read() header length %d for conn %d\n",
2105                                 __func__, cnt, i);
2106                           foundone = 0;
2107                           continue;
2108                         }
2109 
2110                       // Parse the cbridge packet header
2111                       int copcode  = cbuf[0];
2112                       int mbz      = cbuf[1];
2113                       int clen     = cbuf[2] | ( cbuf[3] << 8 );
2114                       sim_printf(
2115                         "%s: read cbridge pkt: opcode %#o (%s), mbz %d, len %d\n",
2116                         __func__, copcode, chop_name(copcode), mbz, clen);
2117                       if (( mbz != 0 ) || (( copcode > CHOP_BRD )  \
2118                                   && ( copcode < CHOP_ACK ))       \
2119                                   || ( clen > CH_PK_MAX_DATALEN ))
2120                         {
2121                           sim_printf(
2122                             "%s: cbridge header bad: opcode %#o (%s), mbz %d, len %d\n",
2123                             __func__, copcode, chop_name(copcode), mbz, clen);
2124                           FD_CLR(mgp_dev_state.conns[i].skt, &rfd);
2125                           numfds--;
2126                           close_conn(i);
2127                           foundone  = 0;
2128                           rval      = -1;
2129                           break;
2130                         }
2131                       else if (( cnt = read(mgp_dev_state.conns[i].skt, cbuf, clen)) < 0)
2132                         {
2133                           // @@@@ handle error, socket closed, pass on to Multics
2134                           sim_printf(
2135                                "%s: read() body error for conn %d: %s (%d)\n",
2136                                __func__, i, xstrerror_l(errno), errno);
2137                           FD_CLR(mgp_dev_state.conns[i].skt, &rfd);
2138                           numfds--;
2139                           close_conn(i);
2140                           foundone = 0;
2141                           continue;
2142                         }
2143                       else if (cnt != clen)
2144                         {
2145                           sim_printf(
2146                             "%s: read() body read %d (expected %d) for conn %d\n",
2147                             __func__, cnt, clen, i);
2148                           foundone = 0;
2149                           continue;
2150                         }
2151                       else
2152                         {
2153                           foundone = 1;
2154                           if (i == statusconn) /* No need for STATUS if we're
2155                                                 * making some other pkt */
2156                             {
2157                               statusconn = -1;
2158                             }
2159 
2160                           // Handle based on chaos opcode, and return
2161                           rval = receive_cbridge_opcode(
2162                             copcode, cbuf, clen, buf, words, i);
2163                           break;
2164                         }
2165                     }
2166                 }
2167 
2168               if (statusconn >= 0)
2169                 {
2170                   sim_printf("%s: making STATUS packet for conn %d\n",
2171                              __func__, statusconn);
2172                   make_status_packet(statusconn, buf, words);
2173                   foundone  = 1;
2174                   rval      = 1;
2175                 }
2176             }
2177           else
2178             {
2179               // sim_printf("%s: select() returned 0 (maxfd %d)\n",
2180               //   __func__, maxfd);
2181               rval = -1;
2182             }
2183 
2184           // If none found, start again at the lowest index
2185           if (!foundone && ( mgp_dev_state.read_index > -1 ))
2186             {
2187               sim_printf(
2188                   "%s: nothing to read at indices over %d, retrying select\n",
2189                   __func__, mgp_dev_state.read_index);
2190               mgp_dev_state.read_index  = -1;
2191               tryagain                  =  1;
2192             }
2193         }
2194       while (tryagain);
2195     }
2196 
2197   // If we didn't already send something, make a NOOP
2198   if (mgp_dev_state.send_noop)
2199     {
2200       sim_printf("%s: asked to send a NOOP - current frame %#x receipt %#x\n",
2201                  __func__, mgp_dev_state.frame_last_sent,
2202                  mgp_dev_state.frame_last_received);
2203       mgp_dev_state.send_noop = 0;
2204       if (!foundone)
2205         { // Only do it if we didn't already send something
2206           make_noop_packet(buf, words);
2207           rval = 1;
2208         }
2209       else
2210         {
2211           sim_printf("%s: already made a packet, skipping NOOP\n", __func__);
2212         }
2213     }
2214 
2215   return rval;
2216 }
2217 
2218 #endif /* if defined(WITH_MGP_DEV) */

/* [previous][next][first][last][top][bottom][index][help] */