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 <bjorn@victor.se>
  11  * Copyright (c) 2021-2023 The DPS8M Development Team
  12  *
  13  * All rights reserved.
  14  *
  15  * This software is made available under the terms of the ICU
  16  * License, version 1.8.1 or later.  For more details, see the
  17  * LICENSE.md file at the top-level directory of this distribution.
  18  *
  19  * ---------------------------------------------------------------------------
  20  */
  21 
  22 // Defining USE_SOCKET_DEV_APPROACH to 1 means taking "the socket_dev
  23 // approach", meaning the Read operation doesn't really do much, but
  24 // instead the event/poll loop (see mgp_process_event) does the actual
  25 // reading. This doesn't seem to work very well, basically nothing
  26 // gets read.
  27 
  28 // Defining USE_SOCKET_DEV_APPROACH to 0 means the Read operation does
  29 // the reading, returning IOM_CMD_DISCONNECT to signal that there is
  30 // something in the buffer. Additionally the event/poll loop
  31 // (mgp_process_event) checks if there is anything to read and in that
  32 // case explicitly does send_terminate_interrupt(). This works a
  33 // little bit better, as some things are actually read, but not
  34 // sufficiently well.
  35 
  36 #define USE_SOCKET_DEV_APPROACH 0
  37 
  38 #include <stdio.h>
  39 #include <ctype.h>
  40 #include <unistd.h>
  41 #include <stdint.h>
  42 #include <time.h>
  43 
  44 #include <sys/types.h>
  45 #include <sys/un.h>
  46 #include <sys/select.h>
  47 #include <sys/time.h>
  48 
  49 #include "dps8.h"
  50 #include "dps8_iom.h"
  51 #include "dps8_mgp.h"
  52 #include "dps8_sys.h"
  53 #include "dps8_faults.h"
  54 #include "dps8_scu.h"
  55 #include "dps8_cable.h"
  56 #include "dps8_cpu.h"
  57 #include "dps8_utils.h"
  58 
  59 #undef FREE
  60 #define FREE(p) do  \
  61   {                 \
  62     free((p));      \
  63     (p) = NULL;     \
  64   } while(0)
  65 
  66 #ifdef TESTING
  67 # undef FREE
  68 # define FREE(p) free(p)
  69 #endif /* ifdef TESTING */
  70 
  71 #ifdef WITH_MGP_DEV
  72 
  73 # define DBG_CTR  1
  74 
  75 static void mgp_init_dev_state(void);
  76 static void dumppkt(char *hdr, word36 *buf, uint words);
  77 static int  handle_mgp_packet(word36 *buf, uint words);
  78 static int  poll_from_cbridge(word36 *buf, uint words, uint probe_only);
  79 static void mgp_wants_to_read(uint iom_unit_idx, uint chan);
  80 
  81 # define MAX_CONNS  64
  82 
  83 struct conn_table
  84 {
  85   int skt;                    /* socket to cbridge                     */
  86   u_short remote_addr;        /* remote address (from connect/cbridge) */
  87   char *contact_name;         /* contact name (likewise)               */
  88   u_short local_id;           /* local id                              */
  89   u_short multics_proc;
  90   u_char pkt_last_received;   /* from Multics */
  91   u_char pkt_last_sent;       /* to Multics   */
  92 };
  93 
  94 struct mgp_dev_state
  95 {
  96   u_char first_frame_received;
  97   u_char frame_last_received; /* from Multics                             */
  98   u_char frame_last_sent;     /* to Multics                               */
  99   u_char send_noop;           /* set to make sure NOOP is sent to Multics */
 100   short read_index;           /* conn we last read from, for round-robin  */
 101   u_char want_to_read;        /* flag that Multics wants to read          */
 102   uint read_unit_idx;
 103   uint read_unit_chan;
 104   struct conn_table conns[MAX_CONNS];
 105 } mgp_dev_state;
 106 
 107 static struct mgp_state
 108   {
 109     char device_name[MAX_DEV_NAME_LEN];
 110   } mgp_state[N_MGP_UNITS_MAX];
 111 
 112 # define N_MGP_UNITS  2 // default
 113 
 114 # define UNIT_FLAGS \
 115         ( UNIT_FIX | UNIT_ATTABLE | UNIT_ROABLE | UNIT_DISABLE | UNIT_IDLE )
 116 
 117 UNIT mgp_unit[N_MGP_UNITS_MAX] = {
 118   {
 119     UDATA(NULL, UNIT_FLAGS, 0),
 120     0,   0,   0,   0,   0,
 121     NULL,  NULL,  NULL,  NULL
 122   }
 123 };
 124 
 125 static inline uint32_t
 126 hash32s(const void *buf, size_t len, uint32_t h)
     /* [previous][next][first][last][top][bottom][index][help] */
 127 {
 128   const unsigned char *p = buf;
 129 
 130   for (size_t i = 0; i < len; i++)
 131     h = h * 31 + p[i];
 132 
 133   h ^= h >> 17;
 134   h *= UINT32_C(0xed5ad4bb);
 135   h ^= h >> 11;
 136   h *= UINT32_C(0xac4c1b51);
 137   h ^= h >> 15;
 138   h *= UINT32_C(0x31848bab);
 139   h ^= h >> 14;
 140 
 141   return h;
 142 }
 143 
 144 # define MGP_UNIT_IDX(uptr)  (( uptr ) - mgp_unit )
 145 
 146 static DEBTAB mgp_dt[] = {
 147      { "NOTIFY", DBG_NOTIFY, NULL },
 148      { "INFO",   DBG_INFO,   NULL },
 149      { "ERR",    DBG_ERR,    NULL },
 150      { "WARN",   DBG_WARN,   NULL },
 151      { "DEBUG",  DBG_DEBUG,  NULL },
 152      { "ALL",    DBG_ALL,    NULL }, // Don't move as it messes up DBG message
 153      { NULL,     0,          NULL }
 154 };
 155 
 156 static t_stat
 157 mgp_show_nunits(UNUSED FILE *st, UNUSED UNIT *uptr, UNUSED int val,
     /* [previous][next][first][last][top][bottom][index][help] */
 158                 UNUSED const void *desc)
 159 {
 160   sim_printf("Number of MGP units in system is %d\n", mgp_dev.numunits);
 161 
 162   return SCPE_OK;
 163 }
 164 
 165 static t_stat
 166 mgp_set_nunits(UNUSED UNIT *uptr, UNUSED int32 value, const char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 167                UNUSED void *desc)
 168 {
 169   if (!cptr)
 170     {
 171       return SCPE_ARG;
 172     }
 173 
 174   int n = atoi(cptr);
 175   if (n < 1 || n > N_MGP_UNITS_MAX)
 176     {
 177       return SCPE_ARG;
 178     }
 179 
 180   mgp_dev.numunits = (uint32)n;
 181 
 182   return SCPE_OK;
 183 }
 184 
 185 static t_stat
 186 mgp_show_device_name(UNUSED FILE *st, UNIT *uptr, UNUSED int val,
     /* [previous][next][first][last][top][bottom][index][help] */
 187                      UNUSED const void *desc)
 188 {
 189   int n = (int)MGP_UNIT_IDX(uptr);
 190 
 191   if (n < 0 || n >= N_MGP_UNITS_MAX)
 192     {
 193       return SCPE_ARG;
 194     }
 195 
 196   if (mgp_state[n].device_name[1] != 0)
 197     {
 198       sim_printf("name     : %s", mgp_state[n].device_name);
 199     }
 200   else
 201     {
 202       sim_printf("name     : MGP%d", n);
 203     }
 204 
 205   return SCPE_OK;
 206 }
 207 
 208 static t_stat
 209 mgp_set_device_name(UNIT *uptr, UNUSED int32 value, const char *cptr,
     /* [previous][next][first][last][top][bottom][index][help] */
 210                     UNUSED void *desc)
 211 {
 212   int n = (int)MGP_UNIT_IDX(uptr);
 213 
 214   if (n < 0 || n >= N_MGP_UNITS_MAX)
 215     {
 216       return SCPE_ARG;
 217     }
 218 
 219   if (cptr)
 220     {
 221       strncpy(mgp_state[n].device_name, cptr, MAX_DEV_NAME_LEN - 1);
 222       mgp_state[n].device_name[MAX_DEV_NAME_LEN - 1] = 0;
 223     }
 224   else
 225     {
 226       mgp_state[n].device_name[0] = 0;
 227     }
 228 
 229   return SCPE_OK;
 230 }
 231 
 232 # define UNIT_WATCH  UNIT_V_UF
 233 
 234 static MTAB mgp_mod[] = {
 235 # ifndef SPEED
 236   { UNIT_WATCH, 1, "WATCH",   "WATCH",   0, 0, NULL, NULL },
 237   { UNIT_WATCH, 0, "NOWATCH", "NOWATCH", 0, 0, NULL, NULL },
 238 # endif /* ifndef SPEED */
 239   {
 240     MTAB_XTD | MTAB_VDV | MTAB_NMO | MTAB_VALR, /* Mask               */
 241     0,                                          /* Match              */
 242     "NUNITS",                                   /* Print string       */
 243     "NUNITS",                                   /* Match string       */
 244     mgp_set_nunits,                             /* Validation routine */
 245     mgp_show_nunits,                            /* Display routine    */
 246     "Number of MGP units in the system",        /* Value descriptor   */
 247     NULL                                        /* Help               */
 248   },
 249   {
 250     MTAB_XTD | MTAB_VUN | MTAB_VALR | MTAB_NC,  /* Mask               */
 251     0,                                          /* Match              */
 252     "NAME",                                     /* Print string       */
 253     "NAME",                                     /* Match string       */
 254     mgp_set_device_name,                        /* Validation routine */
 255     mgp_show_device_name,                       /* Display routine    */
 256     "Set the device name",                      /* Value descriptor   */
 257     NULL                                        /* Help               */
 258   },
 259   MTAB_eol
 260 };
 261 
 262 static t_stat
 263 mgp_reset(UNUSED DEVICE *dptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 264 {
 265   // mgpResetRX (0);
 266   // mgpResetTX (0);
 267 
 268   return SCPE_OK;
 269 }
 270 
 271 static t_stat
 272 mgpAttach(UNIT *uptr, const char *cptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 273 {
 274   if (!cptr)
 275     {
 276       return SCPE_ARG;
 277     }
 278 
 279   // If we're already attached, then detach ...
 280   if (( uptr->flags & UNIT_ATT ) != 0)
 281     {
 282       detach_unit(uptr);
 283     }
 284 
 285   uptr->flags |= UNIT_ATT;
 286 
 287   return SCPE_OK;
 288 }
 289 
 290 // Detach (connect) ...
 291 static t_stat
 292 mgpDetach(UNIT *uptr)
     /* [previous][next][first][last][top][bottom][index][help] */
 293 {
 294   if (( uptr->flags & UNIT_ATT ) == 0)
 295     {
 296       return SCPE_OK;
 297     }
 298 
 299   uptr->flags &= ~(unsigned int)UNIT_ATT;
 300 
 301   return SCPE_OK;
 302 }
 303 
 304 DEVICE mgp_dev = {
 305   "MGP",       /* Name                */
 306   mgp_unit,    /* Units               */
 307   NULL,        /* Registers           */
 308   mgp_mod,     /* Modifiers           */
 309   N_MGP_UNITS, /* #units              */
 310   10,          /* Address radix       */
 311   24,          /* Address width       */
 312   1,           /* Address increment   */
 313   8,           /* Data radix          */
 314   36,          /* Data width          */
 315   NULL,        /* Examine             */
 316   NULL,        /* Deposit             */
 317   mgp_reset,   /* Reset               */
 318   NULL,        /* Boot                */
 319   mgpAttach,   /* Attach              */
 320   mgpDetach,   /* Detach              */
 321   NULL,        /* Context             */
 322   DEV_DEBUG,   /* Flags               */
 323   0,           /* Debug control flags */
 324   mgp_dt,      /* Debug flag names    */
 325   NULL,        /* Memory size change  */
 326   NULL,        /* Logical name        */
 327   NULL,        /* Help                */
 328   NULL,        /* Attach help         */
 329   NULL,        /* Attach context      */
 330   NULL,        /* Description         */
 331   NULL         /* End                 */
 332 };
 333 
 334 /*
 335  * mgp_init()
 336  */
 337 
 338 // Once-only initialization
 339 
 340 void
 341 mgp_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 342 {
 343   memset(mgp_state, 0, sizeof ( mgp_state ));
 344   // Init the other state too
 345   mgp_init_dev_state();
 346 }
 347 
 348 static iom_cmd_rc_t
 349 get_ddcw(iom_chan_data_t *p, uint iom_unit_idx, uint chan, bool *ptro,
     /* [previous][next][first][last][top][bottom][index][help] */
 350          uint expected_tally, uint *tally)
 351 {
 352   bool  send, uff;
 353   int   rc = iom_list_service(iom_unit_idx, chan, ptro, &send, &uff);
 354 
 355   if (rc < 0)
 356     {
 357       p->stati = 05001; // BUG: arbitrary error code; config switch
 358       sim_warn("%s list service failed\n", __func__);
 359 
 360       return IOM_CMD_ERROR;
 361     }
 362 
 363   if (uff)
 364     {
 365       sim_warn("%s ignoring uff\n", __func__); // XXX
 366     }
 367 
 368   if (!send)
 369     {
 370       sim_warn("%s nothing to send\n", __func__);
 371       p->stati = 05001; // BUG: arbitrary error code; config switch
 372 
 373       return IOM_CMD_ERROR;
 374     }
 375 
 376   if (IS_IDCW(p) || IS_TDCW(p))
 377     {
 378       sim_warn("%s expected DDCW\n", __func__);
 379       p->stati = 05001; // BUG: arbitrary error code; config switch
 380 
 381       return IOM_CMD_ERROR;
 382     }
 383 
 384   *tally = p->DDCW_TALLY;
 385 
 386   if (*tally == 0)
 387     {
 388       sim_debug(DBG_DEBUG, &mgp_dev,
 389                 "%s: Tally of zero interpreted as 010000(4096)\n", __func__);
 390       *tally = 4096;
 391     }
 392 
 393   sim_debug(DBG_DEBUG, &mgp_dev,
 394             "%s: Tally %d (%o)\n", __func__, *tally, *tally);
 395 
 396   if (expected_tally && *tally != expected_tally)
 397     {
 398       sim_warn("mgp_dev call expected tally of %d; got %d\n",
 399                expected_tally, *tally);
 400       p->stati = 05001; // BUG: arbitrary error code; config switch
 401 
 402       return IOM_CMD_ERROR;
 403     }
 404 
 405   return IOM_CMD_PROCEED;
 406 }
 407 
 408 static char *
 409 cmd_name(int code)
     /* [previous][next][first][last][top][bottom][index][help] */
 410 {
 411   // Where can I find documentation for these?
 412   switch (code)
 413     {
 414     case 000:
 415       return "Request status";
 416 
 417     case 001:
 418       return "Read";
 419 
 420     case 011:
 421       return "Write";
 422 
 423     case 020:
 424       return "Host switch down";
 425 
 426     case 040:
 427       return "Reset status";
 428 
 429     case 042:
 430       return "Disable Bus Back";
 431 
 432     case 043:
 433       return "Enable Bus Back";
 434 
 435     case 060:
 436       return "Host switch up";
 437 
 438     default:
 439       return "Unknown";
 440     }
 441 }
 442 
 443 static iom_cmd_rc_t
 444 mgp_cmd(uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
 445 {
 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       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 # ifndef __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 /* ifndef __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       fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
 929                __func__, __FILE__, __LINE__);
 930 # if defined(USE_BACKTRACE)
 931 #  ifdef SIGUSR2
 932       (void)raise(SIGUSR2);
 933       /*NOTREACHED*/ /* unreachable */
 934 #  endif /* ifdef 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           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   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__, strerror(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   for (int i = 0; i < 1000; i++)
1175     {
1176       unsigned long counter = 0;
1177       clock_t start = clock();
1178       while (clock() == start)
1179         {
1180           counter++;
1181         }
1182       h = hash32s(&start, sizeof(start), h);
1183       h = hash32s(&counter, sizeof(counter), h);
1184     }
1185   int mypid = (int)getpid();
1186   h = hash32s(&mypid, sizeof(mypid), h);
1187   char rnd[4];
1188   FILE *f = fopen("/dev/urandom", "rb");
1189   if (f)
1190     {
1191       if (fread(rnd, sizeof(rnd), 1, f))
1192         {
1193           h = hash32s(rnd, sizeof(rnd), h);
1194         }
1195       fclose(f);
1196     }
1197   srandom(h);
1198 }
1199 
1200 static void
1201 mgp_wants_to_read(uint iom_unit_idx, uint chan)
     /* [previous][next][first][last][top][bottom][index][help] */
1202 {
1203   mgp_dev_state.read_unit_idx  = iom_unit_idx;
1204   mgp_dev_state.read_unit_chan = chan;
1205   mgp_dev_state.want_to_read   = 1;
1206 }
1207 
1208 // Find the first conn which has a zero skt
1209 static int
1210 find_free_conn(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1211 {
1212   int i;
1213   for (i = 0; i < MAX_CONNS; i++)
1214     {
1215       if (mgp_dev_state.conns[i].skt == 0)
1216         {
1217           return i;
1218         }
1219     }
1220 
1221   return -1;
1222 }
1223 
1224 // Find the conn for <remote,local> id.
1225 // local may be 0 which matches all local ids.
1226 static int
1227 find_conn_for(int remote, int local)
     /* [previous][next][first][last][top][bottom][index][help] */
1228 {
1229   int i;
1230   for (i = 0; i < MAX_CONNS; i++)
1231     {
1232       if ( ( mgp_dev_state.conns[i].multics_proc != 0 )
1233         && ( mgp_dev_state.conns[i].multics_proc == remote )
1234         && (( local == 0 ) || ( mgp_dev_state.conns[i].local_id == local )) )
1235         {
1236           return i;
1237         }
1238     }
1239 
1240   return -1;
1241 }
1242 
1243 // Return a malloc'd pkt with cbridge header filled in.
1244 static u_char *
1245 make_cbridge_pkt(int len, int opcode)
     /* [previous][next][first][last][top][bottom][index][help] */
1246 {
1247   u_char *pkt = malloc(len + CBRIDGE_PACKET_HEADER_SIZE); /* space for cbridge header */
1248   if (pkt == NULL)
1249     {
1250       fprintf (stderr, "\rFATAL: Out of memory! Aborting at %s[%s:%d]\r\n",
1251                __func__, __FILE__, __LINE__);
1252 # if defined(USE_BACKTRACE)
1253 #  ifdef SIGUSR2
1254       (void)raise(SIGUSR2);
1255       /*NOTREACHED*/ /* unreachable */
1256 #  endif /* ifdef SIGUSR2 */
1257 # endif /* if defined(USE_BACKTRACE) */
1258       abort();
1259     }
1260   memset(pkt, 0, len + CBRIDGE_PACKET_HEADER_SIZE);
1261 
1262   pkt[0]  = opcode;
1263   pkt[2]  = len & 0xff;
1264   pkt[3]  = len >> 8;
1265 
1266   return pkt;
1267 }
1268 
1269 static u_char *
1270 make_rfc_pkt(int *len, char *host, char *contact, char *args)
     /* [previous][next][first][last][top][bottom][index][help] */
1271 {
1272   /* cbridge header + strings with spaces + NUL */
1273   *len = strlen(host) + 1 + strlen(contact) + \
1274          ( args == NULL ? 0 : 1 + strlen(args) ) + 1;
1275 
1276   u_char *pkt = make_cbridge_pkt(*len, CHOP_RFC);
1277   sprintf((char *)&pkt[CBRIDGE_PACKET_HEADER_SIZE],
1278           "%s %s%s%s", host, contact,
1279           args == NULL || *args == '\0' ? "" : " ",
1280           args == NULL || *args == '\0' ? "" : args);
1281 
1282   return pkt;
1283 }
1284 
1285 // Open a packet socket to cbridge (done for each conn)
1286 int
1287 cbridge_open_socket(void)
     /* [previous][next][first][last][top][bottom][index][help] */
1288 {
1289   int slen, sock;
1290   struct sockaddr_un server;
1291 
1292   if (( sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
1293     {
1294       // Check for "out of sockets" or similar?
1295       sim_printf("%s: socket(AF_UNIX) error: %s (%d)",
1296                  __func__, strerror(errno), errno); // @@@@ handle error better?
1297 
1298       return sock;
1299     }
1300 
1301   server.sun_family  = AF_UNIX;
1302   sprintf(server.sun_path, "%s", CBRIDGE_PACKET_SOCKET);
1303   slen               = strlen(server.sun_path) + 1 + sizeof ( server.sun_family );
1304 
1305   if (connect(sock, (struct sockaddr *)&server, slen) < 0)
1306     {
1307       sim_printf("%s: connect(%s) error: %s (%d)", __func__,
1308                  server.sun_path, strerror(errno), errno);
1309       // @@@@ let the device go down, instead
1310       close(sock);
1311       sock = 0;
1312     }
1313 
1314   return sock;
1315 }
1316 
1317 static void
1318 close_conn(int i)
     /* [previous][next][first][last][top][bottom][index][help] */
1319 {
1320   if (i < 0)
1321     {
1322       sim_printf("%s: closing conn %d which is invalid!\n", __func__, i);
1323       return;
1324     }
1325   sim_printf("%s: closing conn %d <%#x,%#x>, remote %#o, contact \"%s\"\n",
1326              __func__, i,
1327              mgp_dev_state.conns[i].multics_proc,
1328              mgp_dev_state.conns[i].local_id,
1329              mgp_dev_state.conns[i].remote_addr,
1330              mgp_dev_state.conns[i].contact_name);
1331 
1332   if (mgp_dev_state.conns[i].skt > 0)
1333     {
1334       close(mgp_dev_state.conns[i].skt);
1335     }
1336 
1337   mgp_dev_state.conns[i].multics_proc  = 0;
1338   mgp_dev_state.conns[i].local_id      = 0;
1339   if (mgp_dev_state.conns[i].contact_name != NULL)
1340     {
1341       FREE(mgp_dev_state.conns[i].contact_name);
1342     }
1343 
1344   mgp_dev_state.conns[i].contact_name  = NULL;
1345   mgp_dev_state.conns[i].remote_addr   = 0;
1346 }
1347 
1348 static int
1349 cbridge_send_packet(int i, u_char *pkt, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1350 {
1351   int skt  = mgp_dev_state.conns[i].skt;
1352   int x    = write(skt, pkt, len);
1353   if (x < 0)
1354     {
1355       // @@@@ handle error, pass it on to Multics
1356       if (( errno == EBADF      )  \
1357        || ( errno == ECONNRESET )  \
1358        || ( errno == EPIPE      ))
1359         {
1360           sim_printf("%s: socket seems to have closed: %s\n",
1361                      __func__, strerror(errno));
1362           close_conn(i);
1363         }
1364       else
1365         {
1366           sim_warn("%s: socket write error: %s (%d)\n",
1367                    __func__, strerror(errno), errno);
1368         }
1369     }
1370   else if (x != len)
1371     {
1372       sim_printf("%s: wrote %d bytes (expected %d)\n", __func__, x, len);
1373     }
1374 
1375   FREE(pkt);
1376   return x;
1377 }
1378 
1379 // Handle packets from Multics, send them to cbridge
1380 static int
1381 handle_packet(int opcode, struct mgp_packet_header *p, word36 *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
1382               uint words)
1383 {
1384   int i = find_conn_for(p->source_process, p->destination_process);
1385   if (i < 0)
1386     {
1387       sim_warn("%s: can't find conn for %#x,%#x\n",
1388                __func__, p->source_process, p->destination_process);
1389       return -1;
1390     }
1391 
1392   u_char *pkt = make_cbridge_pkt(p->byte_count, opcode);
1393   if (p->byte_count > 0)
1394     {
1395       copy_packet9_to_cbridge8(
1396         buf, words, pkt + CBRIDGE_PACKET_HEADER_SIZE, p->byte_count);
1397     }
1398 
1399   return cbridge_send_packet(
1400                  i, pkt, CBRIDGE_PACKET_HEADER_SIZE + p->byte_count);
1401 }
1402 
1403 static int
1404 handle_close(struct mgp_packet_header *p, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1405 {
1406   // Close the connection in a controlled way:
1407   // first send and EOF with payload "wait",
1408   // which makes cbridge send the EOF and wait (some time) for its
1409   // acknowledgement, and then send an ACK packet here. When the ACK arrives,
1410   // send the CLS. (No need to save a close message somewhere, since Multics
1411   // doesn't include any data.)
1412   word36 eof[1];
1413   copy_cbridge8_to_packet9((u_char *)"wait", 4, buf, 1);
1414 
1415   return handle_packet(CHOP_EOF, p, eof, 1);
1416 }
1417 
1418 static int
1419 handle_lose(int conni, struct mgp_packet_header *p, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1420 {
1421   // send LOS, close socket, clear out our conn
1422   int v = handle_packet(CHOP_LOS, p, buf, words);
1423   // after sending a LOS, the connection is gone
1424   close_conn(conni);
1425 
1426   return v;
1427 }
1428 
1429 static int
1430 handle_connect(struct mgp_packet_header *p, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1431 {
1432   char connect_string[256], *net, *host, *contact, *args;
1433   char *i;
1434   copy_packet9_to_cbridge8(buf,
1435     words, (u_char *)connect_string, sizeof ( connect_string ));
1436   sim_printf("%s: connect string is \"%s\"\n", __func__, connect_string);
1437   // Parse the connect string, something like "CHAOS 12234 NAME /W BV"
1438   net  = connect_string;
1439   i    = index(net, ' ');
1440   if (i == NULL)
1441     {
1442       sim_printf("%s: bad connect string: first space not found\n", __func__);
1443 
1444       return -1;
1445     }
1446 
1447   *i    = '\0';
1448   host  = i + 1;
1449   i     = index(host, ' ');
1450   if (i == NULL)
1451     {
1452       sim_printf("%s: bad connect string: second space not found\n", __func__);
1453 
1454       return -1;
1455     }
1456 
1457   *i       = '\0';
1458   contact  = i + 1;
1459   i        = index(contact, ' ');
1460   if (i == NULL)
1461     {
1462       sim_printf("%s: third space not found, no contact args\n", __func__);
1463       args = NULL;
1464     }
1465   else
1466     {
1467       *i    = '\0';
1468       args  = i + 1;
1469     }
1470 
1471   sim_printf("%s: parsed connect string: net \"%s\", host \"%s\", contact "
1472              "\"%s\", args \"%s\"\n", __func__, net, host, contact, args);
1473   if (strcasecmp(net, "CHAOS") != 0)
1474     {
1475       sim_printf("%s: not CHAOS net, ignoring\n", __func__);
1476 
1477       return -1;
1478     }
1479 
1480   // Now find a free slot in mgp_dev_state.conns,
1481   int cindex               = find_free_conn();
1482   if (cindex < 0)
1483     {
1484       sim_printf("%s: no free conns available!\n", __func__);
1485       return -1;
1486     }
1487   struct conn_table *conn  = &mgp_dev_state.conns[cindex];
1488   // save the contact name
1489   if (conn->contact_name) /* Free any old string */
1490     {
1491       FREE(conn->contact_name);
1492     }
1493 
1494   conn->contact_name = strdup(contact);
1495   // parse the host address and save it
1496   u_short raddr;
1497   if (( sscanf(host, "%ho", &raddr) != 1 ) || !valid_chaos_host_address(raddr))
1498     {
1499       sim_printf("%s: bad remote address %s\n", __func__, host);
1500 
1501       return -1;
1502     }
1503   else
1504     {
1505       conn->remote_addr = raddr;
1506     }
1507 
1508   // make a local id, fill in multics id,
1509   conn->local_id      = random() % ( 1 << 16 ); /* srandom() called in mgp_init_dev_state */
1510   conn->multics_proc  = p->source_process;
1511   // open a socket,
1512   int cbskt = cbridge_open_socket();
1513   if (cbskt < 0)
1514     {
1515       sim_printf("%s: unable to get a socket\n", __func__);
1516 
1517       return cbskt;
1518     }
1519 
1520   conn->skt = cbskt;
1521   // construct a cbridge packet,
1522   int cblen;
1523   u_char *cbpkt = make_rfc_pkt(&cblen, host, contact, args);
1524 
1525   // send the packet on it
1526   int v = cbridge_send_packet(cindex, cbpkt,
1527               CBRIDGE_PACKET_HEADER_SIZE + cblen);  /* incl header pls */
1528 
1529   if (v < 0)
1530     {
1531       // failed sending, close it again
1532       // @@@@ and pass on error to Multics
1533       close_conn(cindex);
1534 
1535       return -1;
1536     }
1537   else
1538     {
1539       int i = cindex;
1540       sim_printf(
1541            "%s: opened conn %d <%#x,%#x>, remote %#o, contact \"%s\"\n",
1542            __func__, i, mgp_dev_state.conns[i].multics_proc,
1543            mgp_dev_state.conns[i].local_id, mgp_dev_state.conns[i].remote_addr,
1544            mgp_dev_state.conns[i].contact_name);
1545 
1546       return cindex;
1547     }
1548 }
1549 
1550 // Given pkt read from Multics, act on it
1551 static int
1552 handle_mgp_packet(word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1553 {
1554   struct mgp_packet_header *p  = parse_packet_header(buf, words);
1555   int rval                     = 0;
1556 
1557   if (   ( p->checksum       == 0 ) \
1558       && ( p->packet_type    == 0 ) \
1559       && ( p->frame_number   == 0 ) \
1560       && ( p->receipt_number == 0 ) )
1561     {
1562       FREE(p);
1563       // Not a real packet, ignore
1564       return 0;
1565     }
1566 
1567   if (mgp_dev_state.first_frame_received
1568       && ( p->frame_number != ( mgp_dev_state.frame_last_received + 1 )))
1569     {
1570       sim_printf("%s: unordered frame %#x read, expected %#x\n", __func__,
1571                  p->frame_number, mgp_dev_state.frame_last_received + 1);
1572       // send NAK?
1573     }
1574   else
1575     {
1576       mgp_dev_state.first_frame_received = 1;
1577     }
1578 
1579   int i = find_conn_for(p->source_process, p->destination_process);
1580   sim_printf(
1581           "%s: packet %#x (ack %#x) for conn %d <%#x,%#x>, pktype %d (%s)\n",
1582           __func__, p->packet_number, p->ack_number, i,
1583           i < 0 ? 0 : mgp_dev_state.conns[i].multics_proc,
1584           i < 0 ? 0 : mgp_dev_state.conns[i].local_id,
1585           p->packet_type, pktype_name(p->packet_type));
1586 
1587   int pktype = p->packet_type;
1588   switch (pktype)
1589     {
1590     case pktype_NOOP:
1591       // NOOP seems to be nonspecific to conn, just conveying frame/receipt
1592       // (handled above/below)
1593       break;
1594 
1595     case pktype_CONNECT:
1596       rval = handle_connect(p, buf, words);
1597       break;
1598 
1599     case pktype_OPEN:
1600       // make it ANS or OPN, depending on opcode
1601       rval = handle_packet(
1602         p->chaos_opcode ? p->chaos_opcode : CHOP_OPN, p, buf, words);
1603       break;
1604 
1605     case pktype_CLOSE:
1606       rval = handle_close(p, buf, words);
1607       break;
1608 
1609     case pktype_LOSE:
1610       rval = handle_lose(i, p, buf, words);
1611       break;
1612 
1613     case pktype_DATA:
1614       // just convert to DAT and send (but watch out for EOF, check opcode)
1615       rval = handle_packet(
1616         p->chaos_opcode ? p->chaos_opcode : CHOP_DAT, p, buf, words);
1617       break;
1618 
1619     case pktype_SEND_STATUS:
1620       if (status_conns[1] > 0)
1621         {
1622           char b[2] = { i, 0 };
1623           sim_printf(
1624               "%s: asking for STATUS to be sent for conn %d on status_conns\n",
1625               __func__, i);
1626           if (write(status_conns[1], b, 1) < 0)
1627             {
1628               sim_printf(
1629                   "%s: write() on status_conns failed: %s (%d)\n",
1630                   __func__, strerror(errno), errno);
1631               status_conns[1] = status_conns[0] = 0;
1632             }
1633         }
1634 
1635       break;
1636 
1637     case pktype_STATUS:
1638       sim_printf("%s: STATUS for conn %d: frame,rcpt = <%#x,%#x>, pkt,ack = "
1639             "<%#x,%#x>\n", __func__, i, p->frame_number, p->receipt_number,
1640             p->packet_number, p->ack_number);
1641       break;
1642 
1643     default:
1644       sim_printf("%s: can't handle pkt type %#o (%s) yet\n",
1645                  __func__, pktype, pktype_name(pktype));
1646       rval = -1;
1647     }
1648 
1649   // Set a mark to make a NOOP being available for reading next.
1650     if (p->flags.reply_now)
1651       {
1652         sim_printf("%s: reply_NOW set, setting flag for sending NOOP\n",
1653                    __func__);
1654         mgp_dev_state.send_noop = 1;
1655 
1656 
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   // Count the frame
1684   mgp_dev_state.frame_last_received = p->frame_number;
1685   sim_printf("%s: afterwards, frame last sent %#x, last received %#x\n",
1686              __func__, mgp_dev_state.frame_last_sent,
1687              mgp_dev_state.frame_last_received);
1688   FREE(p);
1689 
1690   return rval;
1691 }
1692 
1693 // Handle packets from cbridge, give them to Multics.
1694 
1695 // Mapping from Chaos opcode to MGP packet type
1696 u_char opcode_to_pktype[] = {
1697   0,              /* None                    */
1698   pktype_CONNECT, /* RFC                     */
1699   pktype_OPEN,    /* OPN                     */
1700   pktype_CLOSE,   /* CLS                     */
1701   0,              /* FWD (not handled)       */
1702   pktype_OPEN,    /* ANS                     */
1703   0,              /* SNS (never appears)     */
1704   pktype_STATUS,  /* STS (internal use only) */
1705   0,              /* RUT (never appears)     */
1706   pktype_LOSE,    /* LOS                     */
1707   0,              /* LSN (never appears)     */
1708   0,              /* MNT (never appears)     */
1709   pktype_DATA,    /* EOF                     */
1710   0,              /* UNC (not handled)       */
1711   pktype_CONNECT  /* BRD                     */
1712 };
1713 
1714 static void
1715 make_mgp_header(struct mgp_packet_header *p, u_char opcode, u_char *pkt,
     /* [previous][next][first][last][top][bottom][index][help] */
1716                 uint pklen, int i)
1717 {
1718   memset(p, 0, sizeof ( struct mgp_packet_header ));
1719   p->identification = '#';
1720   if (( opcode > 0 ) && ( opcode <= CHOP_BRD ))
1721     {
1722       p->packet_type = opcode_to_pktype[opcode];
1723     }
1724   else if (opcode >= CHOP_DAT)
1725     {
1726       p->packet_type = pktype_DATA;
1727     }
1728   else if (i == -1) /* special case */
1729     {
1730       p->packet_type = pktype_NOOP;
1731     }
1732 
1733   /* no flags? */
1734   p->flags.reply_now  = 1;
1735   p->frame_number     = ++mgp_dev_state.frame_last_sent;
1736   p->receipt_number   = mgp_dev_state.frame_last_received;
1737   if (i >= 0)
1738     {
1739       // Never mind about these if it is a NOOP we're making
1740       p->packet_number        = ++mgp_dev_state.conns[i].pkt_last_sent;
1741       p->ack_number           =   mgp_dev_state.conns[i].pkt_last_received;
1742       p->source_process       =   mgp_dev_state.conns[i].local_id;
1743       p->destination_process  =   mgp_dev_state.conns[i].multics_proc;
1744     }
1745 
1746   p->chaos_opcode  = opcode;
1747   p->byte_count    = pklen;
1748   sim_printf(
1749         "%s: made %s (%d) f,r=<%#x,%#x> p,a=<%#x,%#x> opc %s (%d) bc %d\n",
1750         __func__, pktype_name(p->packet_type), p->packet_type, p->frame_number,
1751         p->receipt_number, p->packet_number, p->ack_number,
1752         chop_name(p->chaos_opcode), p->chaos_opcode, p->byte_count);
1753 }
1754 
1755 static int
1756 make_mgp_packet(u_char opcode, u_char *pkt, uint pklen, word36 *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
1757                 uint words, uint conni)
1758 {
1759   struct mgp_packet_header hdr;
1760 
1761   // Make an mgp header
1762   make_mgp_header(&hdr, opcode, pkt, pklen, conni);
1763 
1764   // fill in the checksum (which is computed on the 8-bit bytes!)
1765   hdr.checksum = mgp_checksum(&hdr, pkt, pklen);
1766 
1767   // fill in the header in the buffer
1768   unparse_packet_header(&hdr, buf, words);
1769 
1770   // copy the data part, converting from 8-bit to 9-bit
1771   copy_cbridge8_to_packet9(pkt, pklen, buf, words);
1772   sim_printf("%s: conn %d <%#x,%#x> made %s pkt %#x (ack %#x), frame %#x "
1773       "(rcpt %#x)\n", __func__, conni, mgp_dev_state.conns[conni].local_id,
1774       mgp_dev_state.conns[conni].multics_proc, pktype_name(hdr.packet_type),
1775       hdr.packet_number, hdr.ack_number, hdr.frame_number, hdr.receipt_number);
1776 
1777   return 0;
1778 }
1779 
1780 static int
1781 make_status_packet(int conni, word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1782 {
1783   struct mgp_packet_header hdr;
1784 
1785   // Make an mgp header - reuse CHOP_STS which doesn't appear otherwise
1786   make_mgp_header(&hdr, CHOP_STS, NULL, 0, conni);
1787 
1788   // fill in the checksum (which is computed on the 8-bit bytes!)
1789   hdr.checksum = mgp_checksum(&hdr, NULL, 0);
1790 
1791   // fill in the header in the buffer
1792   unparse_packet_header(&hdr, buf, words);
1793 
1794   // (no data to copy)
1795   sim_printf("%s: conn %d <%#x,%#x> made %s pkt %#x (ack %#x), frame %#x "
1796       "(rcpt %#x)\n", __func__, conni, mgp_dev_state.conns[conni].local_id,
1797       mgp_dev_state.conns[conni].multics_proc, pktype_name(hdr.packet_type),
1798       hdr.packet_number, hdr.ack_number, hdr.frame_number, hdr.receipt_number);
1799 
1800   return 0;
1801 }
1802 
1803 static int
1804 make_noop_packet(word36 *buf, uint words)
     /* [previous][next][first][last][top][bottom][index][help] */
1805 {
1806   struct mgp_packet_header hdr;
1807 
1808   // Make an mgp header
1809   make_mgp_header(&hdr, 0, NULL, 0, -1);
1810   hdr.packet_number  = 1;
1811 
1812   // fill in the checksum
1813   hdr.checksum       = mgp_checksum(&hdr, NULL, 0);
1814 
1815   // fill in the header in the buffer
1816   unparse_packet_header(&hdr, buf, words);
1817 
1818   // (no data to copy)
1819   sim_printf("%s: made NOOP pkt %#x (ack %#x), frame %#x (rcpt %#x)\n",
1820              __func__, hdr.packet_number, hdr.ack_number, hdr.frame_number,
1821              hdr.receipt_number);
1822 
1823   return 0;
1824 }
1825 
1826 static int
1827 make_open_packet(u_char opcode, u_char *pkt, uint pklen, word36 *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
1828                  uint words, uint conni)
1829 {
1830   if (opcode == CHOP_OPN)
1831     {
1832       // Skip content of OPN packets, which is
1833       // the ascii host name (or octal address)
1834       return make_mgp_packet(opcode, pkt, 0, buf, words, conni);
1835     }
1836   else if (opcode == CHOP_ANS)
1837     {
1838       // First two bytes is the source (useful e.g. if we sent a broadcast)
1839       u_short src = pkt[0] | ( pkt[1] << 8 );
1840       if (src != mgp_dev_state.conns[conni].remote_addr)
1841         {
1842           sim_printf("%s: got ANS from %#o but had remote addr %#o\n",
1843                      __func__, src, mgp_dev_state.conns[conni].remote_addr);
1844                      mgp_dev_state.conns[conni].remote_addr = src;
1845         }
1846 
1847       // Skip the two source bytes in the mgp packet
1848       return make_mgp_packet(opcode, pkt + 2, pklen - 2, buf, words, conni);
1849     }
1850   else
1851     {
1852       sim_warn("%s: BUG: opcode is not ANS or OPN: %s (%#o)\n",
1853                __func__, chop_name(opcode), opcode);
1854 
1855       return -1;
1856     }
1857 }
1858 
1859 static int
1860 make_connect_packet(u_char *pkt, uint pklen, word36 *buf, uint words,
     /* [previous][next][first][last][top][bottom][index][help] */
1861                     uint conni)
1862 {
1863   // An RFC cbridge pkt is almost like a mgp connect pkt
1864   char *i, *rhost, *args = NULL, connect[128];
1865   rhost = (char *)pkt;
1866   // Zap any line ending
1867   if (( i = index(rhost, '\r')) != NULL)
1868     {
1869       *i = '\0';
1870     }
1871   else if (( i = index(rhost, '\n')) != NULL)
1872     {
1873       *i = '\0';
1874     }
1875 
1876   // Find any contact args
1877   if (( i = index(rhost, ' ')) != NULL)
1878     {
1879       args  = i + 1;
1880       *i    = '\0';
1881     }
1882 
1883   // @@@@ beware: I think Multics wants the name of the remote host,
1884   // @@@@ not the address.
1885   // @@@@ But it should handle the address, I think/hope?
1886   // @@@@ Make sure contact_name is set up also when listening
1887   // @@@@ - this is future work.
1888 
1889   // Prefix with the "net", add contact name, and args
1890   if ( ( mgp_dev_state.conns[conni].contact_name == NULL )
1891    || ( *mgp_dev_state.conns[conni].contact_name == '\0' ))
1892     {
1893       sim_printf("%s: no contact name known for conn %d\n", __func__, conni);
1894 
1895       return -1;
1896     }
1897 
1898   sprintf(connect, "CHAOS %s %s%s%s",
1899           rhost, mgp_dev_state.conns[conni].contact_name,
1900           args == NULL ? "" : " ", args == NULL ? "" : args);
1901 
1902   return make_mgp_packet(CHOP_RFC,
1903     (u_char *)connect, strlen(connect), buf, words, conni);
1904 }
1905 
1906 static int
1907 receive_cbridge_opcode(u_char copcode, u_char *cbuf, uint clen, word36 *buf,
     /* [previous][next][first][last][top][bottom][index][help] */
1908                        uint words, int conni)
1909 {
1910   sim_printf("%s: got opcode %#o (%s)\n",
1911              __func__, copcode, chop_name(copcode));
1912   switch (copcode)
1913     {
1914     case CHOP_FWD:
1915     // These should never be seen:
1916     case CHOP_RUT:
1917     case CHOP_MNT:
1918     case CHOP_UNC:
1919     case CHOP_STS:
1920     case CHOP_SNS:
1921     // Do nothing.
1922       return -1;
1923 
1924     case CHOP_RFC: /* this can originally be a BRD, too */
1925       // format is similar, but not same
1926       return make_connect_packet(cbuf, clen, buf, words, conni);
1927 
1928     case CHOP_OPN:
1929     case CHOP_ANS:
1930       return make_open_packet(copcode, cbuf, clen, buf, words, conni);
1931 
1932     case CHOP_ACK:
1933     {
1934       // This is the ACK of an EOF[wait] (see handle_close),
1935       // so now it is time to send a CLS
1936       u_char *clspkt = make_cbridge_pkt(0, CHOP_CLS);
1937       cbridge_send_packet(conni, clspkt, 0);
1938       // After sending a CLS, the connection can be discarded (cf MIT AIM 628)
1939       close_conn(conni);
1940     }
1941     break;
1942 
1943     case CHOP_CLS:
1944     case CHOP_LOS:
1945     {
1946       // Pass it on to Multics
1947       int v = make_mgp_packet(copcode, cbuf, clen, buf, words, conni);
1948       // and then discard the connection
1949       close_conn(conni);
1950 
1951       return v;
1952     }
1953 
1954     default:
1955       // Most pkts have the same content
1956       return make_mgp_packet(copcode, cbuf, clen, buf, words, conni);
1957     }
1958 
1959   return 1;
1960 }
1961 
1962 // Read result into buf, return the number of bytes/words put there or -1.
1963 static int
1964 poll_from_cbridge(word36 *buf, uint words, uint probe_only)
     /* [previous][next][first][last][top][bottom][index][help] */
1965 {
1966   fd_set rfd;
1967   int maxfd, numfds, i, sval, cnt, rval = -1;
1968   int foundone = 0, tryagain = 0;
1969   u_char cbuf[CH_PK_MAX_DATALEN + CBRIDGE_PACKET_HEADER_SIZE]; /* Fit data + cbridge header */
1970 
1971   maxfd   = 0;
1972   numfds  = 0;
1973   // Add the status pipe to the fd set
1974   FD_ZERO(&rfd);
1975   if (status_conns[0] != 0)
1976     {
1977       FD_SET(status_conns[0], &rfd);
1978       maxfd = status_conns[0];
1979       numfds++;
1980     }
1981 
1982   // Add all existing conns
1983   for (i = 0; i < MAX_CONNS; i++)
1984     {
1985       if (mgp_dev_state.conns[i].skt != 0)
1986         {
1987           FD_SET(mgp_dev_state.conns[i].skt, &rfd);
1988           numfds++;
1989           if (mgp_dev_state.conns[i].skt > maxfd)
1990             {
1991               maxfd = mgp_dev_state.conns[i].skt;
1992             }
1993         }
1994     }
1995 
1996   if (maxfd > 0)
1997     {
1998       struct timeval timeout;
1999       do
2000         {
2001           tryagain         = 0;
2002           // set a very short timeout (e.g. 0.01ms)
2003           timeout.tv_sec   = 0;
2004           timeout.tv_usec  = 10;
2005           sval             = select(maxfd + 1, &rfd, NULL, NULL, &timeout);
2006           if (probe_only)
2007             {
2008               if ((sval < 0) && (errno == EINTR))
2009                 {
2010                   return 0; /* Timeout, nothing to read */
2011                 }
2012               else
2013                 {
2014                   return sval;
2015                 }
2016             }
2017 
2018           if (sval < 0)
2019             {
2020               if (errno == EINTR)
2021                 {
2022                   // timed out
2023                 }
2024               else
2025                 {
2026                   sim_printf(
2027                        "%s: select() error, maxfd %d, numfds %d: %s (%d)\n",
2028                        __func__, maxfd, numfds, strerror(errno), errno);
2029                 }
2030 
2031               return -1;
2032             }
2033           else if (sval > 0)
2034             {
2035               int statusconn = -1;
2036 
2037               // First see if a STATUS should be sent
2038               if (( status_conns[0] != 0 ) && FD_ISSET(status_conns[0], &rfd))
2039                 {
2040                   char b[2];
2041                   sim_printf(
2042                        "%s: about to read a byte from status_conns[0] = %d\n",
2043                        __func__, status_conns[0]);
2044                   int s = read(status_conns[0], b, 1);
2045                   if (s < 0)
2046                     {
2047                       sim_warn("%s: read on status_conns failed: %s (%d)\n",
2048                                __func__, strerror(errno), errno);
2049                       status_conns[0] = status_conns[1] = 0;
2050                     }
2051                   else if (s == 0)
2052                     {
2053                       sim_printf("%s: read on status_conns returned 0\n",
2054                                  __func__);
2055                       status_conns[0] = status_conns[1] = 0;
2056                     }
2057                   else
2058                     {
2059                       sim_printf(
2060                          "%s: read %d from status_conns, make STATUS packet\n",
2061                          __func__, b[0]);
2062                       // make a STATUS packet
2063                       statusconn = b[0];
2064                     }
2065                 }
2066 
2067               // Start at the one after the previously read index, to make it
2068               // round-robin-like
2069               for (i = mgp_dev_state.read_index + 1; i < MAX_CONNS; i++)
2070                 {
2071                   if (FD_ISSET(mgp_dev_state.conns[i].skt, &rfd))
2072                     {
2073                       mgp_dev_state.read_index = i;
2074                       // read the header first, then that many bytes
2075                       if (( cnt = read(mgp_dev_state.conns[i].skt,
2076                               cbuf, CBRIDGE_PACKET_HEADER_SIZE)) < 0)
2077                         {
2078                           // @@@@ handle error, socket closed, pass on to Multics
2079                           sim_printf(
2080                               "%s: read() header error for conn %d: %s (%d)\n",
2081                               __func__, i, strerror(errno), errno);
2082                           FD_CLR(mgp_dev_state.conns[i].skt, &rfd);
2083                           numfds--;
2084                           close_conn(i);
2085                           foundone = 0;
2086                           continue;
2087                         }
2088                       else if (cnt == 0)
2089                         {
2090                           sim_printf(
2091                               "%s: read() header zero length conn %d, assuming closed\n",
2092                               __func__, i);
2093                           FD_CLR(mgp_dev_state.conns[i].skt, &rfd);
2094                           numfds--;
2095                           close_conn(i);
2096                           foundone = 0;
2097                           continue;
2098                         }
2099                       else if (cnt != CBRIDGE_PACKET_HEADER_SIZE)
2100                         {
2101                           sim_printf(
2102                                 "%s: read() header length %d for conn %d\n",
2103                                 __func__, cnt, i);
2104                           foundone = 0;
2105                           continue;
2106                         }
2107 
2108                       // Parse the cbridge packet header
2109                       int copcode  = cbuf[0];
2110                       int mbz      = cbuf[1];
2111                       int clen     = cbuf[2] | ( cbuf[3] << 8 );
2112                       sim_printf(
2113                         "%s: read cbridge pkt: opcode %#o (%s), mbz %d, len %d\n",
2114                         __func__, copcode, chop_name(copcode), mbz, clen);
2115                       if (( mbz != 0 ) || (( copcode > CHOP_BRD )  \
2116                                   && ( copcode < CHOP_ACK ))       \
2117                                   || ( clen > CH_PK_MAX_DATALEN ))
2118                         {
2119                           sim_printf(
2120                             "%s: cbridge header bad: opcode %#o (%s), mbz %d, len %d\n",
2121                             __func__, copcode, chop_name(copcode), mbz, clen);
2122                           FD_CLR(mgp_dev_state.conns[i].skt, &rfd);
2123                           numfds--;
2124                           close_conn(i);
2125                           foundone  = 0;
2126                           rval      = -1;
2127                           break;
2128                         }
2129                       else if (( cnt = read(mgp_dev_state.conns[i].skt, cbuf, clen)) < 0)
2130                         {
2131                           // @@@@ handle error, socket closed, pass on to Multics
2132                           sim_printf(
2133                                "%s: read() body error for conn %d: %s (%d)\n",
2134                                __func__, i, strerror(errno), errno);
2135                           FD_CLR(mgp_dev_state.conns[i].skt, &rfd);
2136                           numfds--;
2137                           close_conn(i);
2138                           foundone = 0;
2139                           continue;
2140                         }
2141                       else if (cnt != clen)
2142                         {
2143                           sim_printf(
2144                             "%s: read() body read %d (expected %d) for conn %d\n",
2145                             __func__, cnt, clen, i);
2146                           foundone = 0;
2147                           continue;
2148                         }
2149                       else
2150                         {
2151                           foundone = 1;
2152                           if (i == statusconn) /* No need for STATUS if we're
2153                                                 * making some other pkt */
2154                             {
2155                               statusconn = -1;
2156                             }
2157 
2158                           // Handle based on chaos opcode, and return
2159                           rval = receive_cbridge_opcode(
2160                             copcode, cbuf, clen, buf, words, i);
2161                           break;
2162                         }
2163                     }
2164                 }
2165 
2166               if (statusconn >= 0)
2167                 {
2168                   sim_printf("%s: making STATUS packet for conn %d\n",
2169                              __func__, statusconn);
2170                   make_status_packet(statusconn, buf, words);
2171                   foundone  = 1;
2172                   rval      = 1;
2173                 }
2174             }
2175           else
2176             {
2177               // sim_printf("%s: select() returned 0 (maxfd %d)\n",
2178               //   __func__, maxfd);
2179               rval = -1;
2180             }
2181 
2182           // If none found, start again at the lowest index
2183           if (!foundone && ( mgp_dev_state.read_index > -1 ))
2184             {
2185               sim_printf(
2186                   "%s: nothing to read at indices over %d, retrying select\n",
2187                   __func__, mgp_dev_state.read_index);
2188               mgp_dev_state.read_index  = -1;
2189               tryagain                  =  1;
2190             }
2191         }
2192       while (tryagain);
2193     }
2194 
2195   // If we didn't already send something, make a NOOP
2196   if (mgp_dev_state.send_noop)
2197     {
2198       sim_printf("%s: asked to send a NOOP - current frame %#x receipt %#x\n",
2199                  __func__, mgp_dev_state.frame_last_sent,
2200                  mgp_dev_state.frame_last_received);
2201       mgp_dev_state.send_noop = 0;
2202       if (!foundone)
2203         { // Only do it if we didn't already send something
2204           make_noop_packet(buf, words);
2205           rval = 1;
2206         }
2207       else
2208         {
2209           sim_printf("%s: already made a packet, skipping NOOP\n", __func__);
2210         }
2211     }
2212 
2213   return rval;
2214 }
2215 
2216 #endif /* ifdef WITH_MGP_DEV */

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