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

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