40
40
#define UNIT_M_DTYPE 3
41
41
#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE)
42
42
#define GET_DTYPE (x ) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE)
43
+ #define UNIT_V_NCP (UNIT_V_UF + 3) /* NCP flag */
44
+ #define UNIT_NCP (1 << UNIT_V_NCP)
43
45
44
46
#define TYPE_MIT 0 /* MIT Style KAIMP ITS */
45
47
#define TYPE_BBN 1 /* BBN style interface TENEX */
@@ -475,13 +477,15 @@ struct imp_device {
475
477
struct imp_stats stats ;
476
478
uint8 sbuffer [ETH_FRAME_SIZE ]; /* Temp send buffer */
477
479
uint8 rbuffer [ETH_FRAME_SIZE ]; /* Temp receive buffer */
480
+ int rpos ;
478
481
ETH_DEV etherface ;
479
482
ETH_QUE ReadQ ;
480
483
int imp_error ;
481
484
int host_error ;
482
485
int rfnm_count ; /* Number of pending RFNM packets */
483
486
int pia ; /* PIA channels */
484
487
struct arp_entry arp_table [IMP_ARPTAB_SIZE ];
488
+ int32 link ; /* Link for UDP. */
485
489
} imp_data ;
486
490
487
491
extern int32 tmxr_poll ;
@@ -541,6 +545,16 @@ const char *imp_description (DEVICE *dptr);
541
545
static char * ipv4_inet_ntoa (struct in_addr ip );
542
546
static int ipv4_inet_aton (const char * str , struct in_addr * inp );
543
547
548
+ #define MAXDATA 16348
549
+ extern t_stat udp_create (DEVICE * dptr , const char * premote , int32 * pln );
550
+ extern t_stat udp_release (DEVICE * dptr , int32 link );
551
+ extern t_stat udp_send (DEVICE * dptr , int32 link , uint16 * pdata , uint16 count );
552
+ extern int32 udp_receive (DEVICE * dptr , int32 link , uint16 * pdata , uint16 maxbuf );
553
+ // Last-IMP-Bit is implemented as an out-of-band flag in UDP_PACKET
554
+ #define PFLG_FINAL 00001
555
+ // Host or IMP Ready bit.
556
+ #define PFLG_READY 00002
557
+
544
558
#if KS
545
559
uint16 imp_icsr ;
546
560
uint16 imp_idb ;
@@ -595,6 +609,10 @@ MTAB imp_mod[] = {
595
609
"Use DHCP to set IP address" },
596
610
{ MTAB_XTD |MTAB_VDV , 0 , "DHCPIP" , NULL ,
597
611
NULL , & imp_show_dhcpip , NULL , "DHCP info" },
612
+ { UNIT_NCP , 0 , "TCP" , "TCP" , NULL , NULL , NULL ,
613
+ "Use TCP/IP protocol" },
614
+ { UNIT_NCP , UNIT_NCP , "NCP" , "NCP" , NULL , NULL , NULL ,
615
+ "Use NCP protocol" },
598
616
#if KS
599
617
{ UNIT_DTYPE , (TYPE_UNI << UNIT_V_DTYPE ), "UNI" , "UNI" , NULL , NULL , NULL ,
600
618
"Standard Unibus transfers" },
@@ -860,6 +878,13 @@ static void check_interrupts (UNIT *uptr)
860
878
set_interrupt_mpx (DEVNUM , imp_data .pia >> 3 , imp_mpx_lvl + 1 );
861
879
}
862
880
881
+ static void imp_send_host_ready (DEVICE * dptr , struct imp_device * imp )
882
+ {
883
+ t_stat r ;
884
+ uint16 data = PFLG_READY ;
885
+ r = udp_send (dptr , imp -> link , & data , 1 );
886
+ }
887
+
863
888
t_stat imp_devio (uint32 dev , uint64 * data )
864
889
{
865
890
DEVICE * dptr = & imp_dev ;
@@ -893,8 +918,12 @@ t_stat imp_devio(uint32 dev, uint64 *data)
893
918
}
894
919
if (* data & IMPHEC ) { /* Clear host error. */
895
920
/* Only if there has been a CONI lately. */
896
- if (last_coni - sim_gtime () < CONI_TIMEOUT )
921
+ if (last_coni - sim_gtime () < CONI_TIMEOUT ) {
897
922
uptr -> STATUS &= ~IMPHER ;
923
+ uptr -> STATUS |= IMPHR ;
924
+ if (uptr -> flags & UNIT_NCP )
925
+ imp_send_host_ready (dptr , & imp_data );
926
+ }
898
927
}
899
928
if (* data & IMIIHE ) /* Inhibit interrupt on host error. */
900
929
uptr -> STATUS |= IMPIHE ;
@@ -1380,6 +1409,35 @@ t_stat imp_tim_srv(UNIT * uptr)
1380
1409
return SCPE_OK ;
1381
1410
}
1382
1411
1412
+ void
1413
+ imp_receive_udp (DEVICE * dev , struct imp_device * imp )
1414
+ {
1415
+ static uint16 data [MAXDATA ];
1416
+ int i ;
1417
+ int32 count ;
1418
+
1419
+ count = udp_receive (dev , imp -> link , data , MAXDATA );
1420
+ if (count == 0 )
1421
+ return ;
1422
+ if (data [0 ] & PFLG_READY )
1423
+ imp_unit [0 ].STATUS |= IMPR ;
1424
+ else
1425
+ imp_unit [0 ].STATUS &= IMPR ;
1426
+ for (i = 1 ; i < count ; i ++ ) {
1427
+ imp -> rbuffer [imp -> rpos ++ ] = data [i ] >> 8 ;
1428
+ imp -> rbuffer [imp -> rpos ++ ] = data [i ] & 0xFF ;
1429
+ }
1430
+ if ((data [0 ] & PFLG_FINAL ) == 0 || imp -> rpos == 0 )
1431
+ return ;
1432
+ imp_unit [0 ].STATUS |= IMPIB ;
1433
+ imp_unit [0 ].IPOS = 0 ;
1434
+ imp_unit [0 ].ILEN = 8 * imp -> rpos ;
1435
+ imp -> rpos = 0 ;
1436
+ if (!sim_is_active (& imp_unit [0 ]))
1437
+ sim_activate (& imp_unit [0 ], 100 );
1438
+ return ;
1439
+ }
1440
+
1383
1441
void
1384
1442
imp_packet_in (struct imp_device * imp )
1385
1443
{
@@ -1389,6 +1447,11 @@ imp_packet_in(struct imp_device *imp)
1389
1447
int n ;
1390
1448
int pad ;
1391
1449
1450
+ if (imp_unit [0 ].flags & UNIT_NCP ) {
1451
+ imp_receive_udp (& imp_dev , imp );
1452
+ return ;
1453
+ }
1454
+
1392
1455
if (eth_read (& imp_data .etherface , & read_buffer , NULL ) <= 0 ) {
1393
1456
/* Any pending packet notifications? */
1394
1457
if (imp -> rfnm_count != 0 ) {
@@ -1608,6 +1671,24 @@ imp_packet_in(struct imp_device *imp)
1608
1671
}
1609
1672
}
1610
1673
1674
+ void
1675
+ imp_send_udp (struct imp_device * imp , int len )
1676
+ {
1677
+ static uint16 data [MAXDATA ];
1678
+ t_stat r ;
1679
+ int i , j ;
1680
+
1681
+ data [0 ] = PFLG_FINAL ;
1682
+ if ((imp_unit [0 ].STATUS & IMPHER ) == 0 )
1683
+ data [0 ] |= PFLG_READY ;
1684
+
1685
+ for (i = 0 , j = 0 ; i < len /2 ; i ++ , j += 2 )
1686
+ data [i + 1 ] = (imp -> sbuffer [j ] << 8 ) + imp -> sbuffer [j + 1 ];
1687
+ if (len & 1 )
1688
+ data [i + 1 ] = imp -> sbuffer [j ] << 8 ;
1689
+ r = udp_send (& imp_dev , imp -> link , data , ((uint16 )len + 3 )/2 );
1690
+ }
1691
+
1611
1692
void
1612
1693
imp_send_packet (struct imp_device * imp , int len )
1613
1694
{
@@ -1619,6 +1700,12 @@ imp_send_packet (struct imp_device *imp, int len)
1619
1700
int lk ;
1620
1701
int mt ;
1621
1702
1703
+ if (imp_unit [0 ].flags & UNIT_NCP ) {
1704
+ imp_send_udp (imp , len );
1705
+ sim_activate (uptr , tmxr_poll );
1706
+ return ;
1707
+ }
1708
+
1622
1709
lk = 0 ;
1623
1710
n = len ;
1624
1711
switch (imp -> sbuffer [0 ] & 0xF ) {
@@ -3132,6 +3219,16 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr)
3132
3219
char * tptr ;
3133
3220
char buf [32 ];
3134
3221
3222
+ if (cptr == NULL || * cptr == 0 )
3223
+ return SCPE_ARG ;
3224
+
3225
+ if (uptr -> flags & UNIT_NCP ) {
3226
+ status = udp_create (& imp_dev , cptr , & imp_data .link );
3227
+ if (status != SCPE_OK )
3228
+ return status ;
3229
+ imp_data .rpos = 0 ;
3230
+ }
3231
+
3135
3232
#if !KS
3136
3233
/* Set to correct device number */
3137
3234
switch (GET_DTYPE (imp_unit [0 ].flags )) {
@@ -3146,6 +3243,16 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr)
3146
3243
break ;
3147
3244
}
3148
3245
#endif
3246
+
3247
+ /* Start out in a "host not ready" state. */
3248
+ uptr -> STATUS &= ~IMPHR ;
3249
+
3250
+ if (uptr -> flags & UNIT_NCP ) {
3251
+ /* Don't do the Ethernet stuff below. */
3252
+ uptr -> flags |= UNIT_ATT ;
3253
+ return SCPE_OK ;
3254
+ }
3255
+
3149
3256
if (!(uptr -> flags & UNIT_DHCP ) && imp_data .ip == 0 )
3150
3257
return sim_messagef (SCPE_NOATT , "%s: An IP Address must be specified when DHCP is disabled\n" ,
3151
3258
imp_dev .name );
@@ -3227,17 +3334,20 @@ t_stat imp_attach(UNIT* uptr, CONST char* cptr)
3227
3334
3228
3335
t_stat imp_detach (UNIT * uptr )
3229
3336
{
3230
-
3231
3337
if (uptr -> flags & UNIT_ATT ) {
3338
+ if (uptr -> flags & UNIT_NCP )
3339
+ udp_release (& imp_dev , imp_data .link );
3232
3340
/* If DHCP, release our IP address */
3233
- if (uptr -> flags & UNIT_DHCP ) {
3341
+ else if (uptr -> flags & UNIT_DHCP ) {
3234
3342
imp_dhcp_release (& imp_data );
3235
3343
}
3236
3344
sim_cancel (uptr + 1 ); /* stop the packet timing services */
3237
3345
sim_cancel (uptr + 2 ); /* stop the clock timer services */
3238
- eth_close (& imp_data .etherface );
3239
- free (uptr -> filename );
3240
- uptr -> filename = NULL ;
3346
+ if (!(uptr -> flags & UNIT_NCP )) {
3347
+ eth_close (& imp_data .etherface );
3348
+ free (uptr -> filename );
3349
+ uptr -> filename = NULL ;
3350
+ }
3241
3351
uptr -> flags &= ~UNIT_ATT ;
3242
3352
}
3243
3353
return SCPE_OK ;
@@ -3260,6 +3370,13 @@ fprintf (st, "GW points to the default\nrouter. If DHCP is enabled these ");
3260
3370
fprintf (st , "will be set from DHCP when the IMP is attached.\nIf IP is set " );
3261
3371
fprintf (st , "and DHCP is enabled, when the IMP is attached it will inform\n" );
3262
3372
fprintf (st , "the local DHCP server of it's address.\n\n" );
3373
+ fprintf (st , "There is a second way to interact with a network.\n" );
3374
+ fprintf (st , "If the NCP modifier is enabled, you must ATTACH\n" );
3375
+ fprintf (st , "the IMP device to <local port>:<host>:<remote port>\n" );
3376
+ fprintf (st , "It is expected that there is an IMP emulator at <host>\n" );
3377
+ fprintf (st , "listening to <remote port> and talking to the PDP-10\n" );
3378
+ fprintf (st , "at <local port>. This network will only accept the NCP\n" );
3379
+ fprintf (st , "protocol that existed before TCP/IP.\n" );
3263
3380
fprint_set_help (st , dptr );
3264
3381
fprint_show_help (st , dptr );
3265
3382
eth_attach_help (st , dptr , uptr , flag , cptr );
0 commit comments