Google
 

Trailing-Edge - PDP-10 Archives - SRI_NIC_PERM_SRC_1_19910112 - 6-1-monitor/ipnidv.mac
There are 5 other files named ipnidv.mac in the archive. Click here to see a list.
; *** Edit 7450 to IPNIDV.MAC by PRATT on 16-Apr-87, for SPR #21374
; Fix up ARP table problems and also create a lock for GHT updating. 
;------------------------- Autopatch Tape # 13 -------------------------
; *** Edit 7227 to IPNIDV.MAC by MELOHN on 23-Jan-86 (TCO 6.1.1568)
; Increase ARP portal size so that we can receive ARP msgs from Ultrix QNA
; systems
;------------------------- Autopatch Tape # 12 -------------------------
; UPD ID= 2089, SNARK:<6.1.MONITOR>IPNIDV.MAC.13,   3-Jun-85 14:47:00 by MCCOLLUM
;TCO 6.1.1406  - Update copyright notice.
; UPD ID= 1706, SNARK:<6.1.MONITOR>IPNIDV.MAC.12,  31-Mar-85 13:30:42 by PAETZOLD
;TCO 6.1.1302 - Fix ARPCDS to return the buffer on a send failure.
; UPD ID= 1598, SNARK:<6.1.MONITOR>IPNIDV.MAC.11,   7-Mar-85 15:40:43 by PAETZOLD
;Document BUGxxx's, also turn off IPNDSW.
; UPD ID= 1579, SNARK:<6.1.MONITOR>IPNIDV.MAC.10,   1-Mar-85 15:49:14 by PAETZOLD
;Fix up some comments and typeos found when reading through this module.
;More TCO 6.1.1126 - Do not destroy PI state in IPNDSW stuff and fix section
;problem in NIPSTO.
; UPD ID= 1576, SNARK:<6.1.MONITOR>IPNIDV.MAC.9,  27-Feb-85 16:09:27 by PAETZOLD
;TCO 6.1.1225  -  Add IPNDSW stuff and rewrite NIPSTO. Make sure NBQUE
;zero in NIPQUE. Document BUGxxx's
; UPD ID= 1418, SNARK:<6.1.MONITOR>IPNIDV.MAC.8,  29-Jan-85 11:37:27 by PAETZOLD
;TCO 6.1.1158 - Decrease scheduler latency when requesting INTFRK from interrupt context.
; UPD ID= 1415, SNARK:<6.1.MONITOR>IPNIDV.MAC.7,  28-Jan-85 15:12:52 by PAETZOLD
;Remove IPNISC.  It was a bad idea.
; UPD ID= 1395, SNARK:<6.1.MONITOR>IPNIDV.MAC.6,  22-Jan-85 22:34:06 by PAETZOLD
;Make IPNISC conditional on NIBUGX
; UPD ID= 1292, SNARK:<6.1.MONITOR>IPNIDV.MAC.5,   9-Jan-85 11:22:14 by PAETZOLD
;Add IPNISC BUGINF in CKSTAT for NISRV reported KLNI state change.
; UPD ID= 1037, SNARK:<6.1.MONITOR>IPNIDV.MAC.4,  12-Nov-84 15:25:17 by PAETZOLD
;TCO 6.1041 - Move ARPANET to XCDSEC
; UPD ID= 306, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.80,  16-Oct-84 16:37:11 by PRATT
;Use INTXPB + CRC bytes for setting input packet size
; UPD ID= 293, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.79,  24-Sep-84 13:56:47 by PURRETTA
;Update copyright notice.
; UPD ID= 280, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.78,   8-Sep-84 14:55:32 by PAETZOLD
;Ping all known Ethernet Internet hosts on network up state change.
; UPD ID= 269, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.77,   5-Sep-84 10:10:42 by PRATT
;Don't lose ARP buffers when port has been closed
; UPD ID= 260, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.76,  28-Aug-84 16:37:51 by PRATT
;Also remove comments about physically contigous buffers 
; UPD ID= 259, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.75,  27-Aug-84 11:48:57 by PRATT
;Now that we do BSD style xmits, GETNIB/RETNIB don't use 1822 buffers 
; UPD ID= 240, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.74,  22-Aug-84 11:07:46 by PRATT
;Use NISRV's UN block on re-posting an ARP buffer that got an error
; UPD ID= 239, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.73,  21-Aug-84 21:36:16 by PRATT
;Zero UNBNFI/UNBFRI after the UN block free space is released
; UPD ID= 236, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.72,  16-Aug-84 11:26:42 by PAETZOLD
;Fix a typo in the previous edit.
; UPD ID= 234, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.71,  15-Aug-84 16:17:51 by PAETZOLD
;Fix up CBDRCK to work around NISRV deficiency.
; UPD ID= 219, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.70,  18-Jul-84 09:43:41 by PRATT
;Fix typo if datagram too long error (currently we do nothing anyway)
;Don't run NIPSRV if NIPON is off
; UPD ID= 215, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.69,  17-Jul-84 10:12:57 by PRATT
;If IPNI hasn't initialized, don't issue IPUNBP buginfs.
; UPD ID= 212, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.68,  16-Jul-84 17:28:32 by PRATT
;Fix IPDWNS problem with very short packets at the end of a page
;  If we have a packet less than the ethernet minimum packet size,
;  use a 2 MSD style transmit
;Try to prevent KNIFQE/IPIBLP semi-deadly embrace
;Don't type so many IPIBLP's, buginf only every 4th occurance
;Some systems are sending oversize ARP packets, expand AR.MAX and AR.WRD 
;Make sure GHTCT1 is legit when we have bad or non-exsistent ght files 
; UPD ID= 211, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.67,  11-Jul-84 14:04:27 by PRATT
;Detect trailer encapsulated datagrams and BUGINF
; UPD ID= 207, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.66,  29-Jun-84 13:41:28 by PRATT
;Fix lost UNPID word caused by multiple UN blocks
;Remove extraneous code in arpupd
; UPD ID= 206, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.65,  28-Jun-84 08:49:24 by PRATT
;Use NIPSHT on line state change when klni went down
;Do a CALL to callback routines and put callback function code on the stack
;Make callback routines skip return or not. If no skip, save error code
;Fix up ARPUPD to use reverse XBLTs to update the GHT  
;If error posting an input buffer or when channel is shutting down,
;  we can't call RETNIB because it's not resident.  Instead place 
;  the buffer back on queue of free input buffers
;Handle address change callbacks differently:
;  . If no arp, shut down ipni by setting NIPSHT
;  . If arp, invalidate all ght entries
;Trim excess fat and make code more efficient:
;  . Reduce # of ght entries by not putting our hosts info in the ght
;  . Handle errors in NISEND slightly different
;  . Be more efficient in picking up and checking the ethernet address
;  . Found sequences of instructions which could be optimized
;  . Do away with arp enabled/disabled messages
;  . Do away with IPFERR, it's a thing of the past.
;  . Get rid of nifcnt and nipadr
; UPD ID= 200, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.64,  17-Jun-84 20:08:49 by PAETZOLD
;Change NIRELB CALL to a CALLRET in NILCAL.
; UPD ID= 195, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.63,  17-Jun-84 14:28:27 by PAETZOLD
;Fix a typo in the "Tested" code from edit 184.
; UPD ID= 189, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.62,  16-Jun-84 18:29:12 by PAETZOLD
;Do not call NIPRST at datagram callback level since context will be unknown.
;Solution is to set a flag and call NIPRST from INTFRK context in NIPSRV.
; UPD ID= 184, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.61,  15-Jun-84 13:00:40 by PRATT
;Maintain a queue of free UN blocks, remove now unecessary nosked's
;Don't jump to nipkld from nioff
; UPD ID= 183, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.59,  12-Jun-84 13:14:14 by PRATT
;Send all queued output packets at once
;Remove debugging macros
;Put edit 160 back plus some changes to the sequential search code
;Start fixing the cases where the error code gets lost
;Change some PIOFF/PION's to just go NOSKED/OKSKED
;Don't lose ght flags when updating our hosts ethernet address
; UPD ID= 162, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.58,   3-Jun-84 17:26:24 by PAETZOLD
;remove previous edit.
; UPD ID= 160, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.57,   1-Jun-84 21:53:27 by PRATT
;Make some symbols global for IPOPR
;Give additional info on IPIBLP buginfs
;Fix problem with lots of IPRANF buginfs
;Better line state change code
;If # of ght entries is small, do sequential search, not binary
;Fix Intsrc to not loop if ghtcnt is zero
; UPD ID= 154, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.56,  31-May-84 10:58:44 by PAETZOLD
;Do not change NETON.  Reflect state changes in NTRDY.
; UPD ID= 146, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.55,  30-May-84 14:24:09 by PAETZOLD
;NIPLKB and NIPULK in IPFREE now.  Fix the SUBTTLs.
; UPD ID= 135, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.54,  15-May-84 13:53:45 by PRATT
;Make sure ARP request opcode is set on requests
;It would be nice if I bump ghtcnt after adding a new entry
;Go NOSKED when updating the ght
; UPD ID= 133, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.53,  15-May-84 00:55:19 by PRATT
;Fix NISEND to get the -lclpkt(rid) to pick up the packet length
; UPD ID= 132, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.52,  14-May-84 23:16:59 by PRATT
;Fix ILULK2 bug. Keep other forks from modifying the UN block during transmits.
; UPD ID= 128, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.51,  14-May-84 15:23:11 by PRATT
;Don't return GHT sequence error on number of entries is zero
; UPD ID= 127, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.50,  14-May-84 13:06:08 by PRATT
;Change some rescd's to swapcd's since no longer called during interrupts
;Don't let NIPNFI buffer count go negative if no input buffers
;Same thing goes for ARPNFI if no arp buffers
; UPD ID= 116, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.47,  14-May-84 10:47:48 by PRATT
;No need to preserve T1 in NIPUNB.  Define and use GH2MDL. More cleanup.
; UPD ID= 115, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.46,  14-May-84 10:18:40 by PRATT
;Preserve error code over call to nipkil if ght error in restart code
; UPD ID= 114, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.45,  14-May-84 09:07:08 by PRATT
;If no entry for IPNI in Internet.Address file, don't bring net up
; UPD ID= 110, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.44,  12-May-84 18:26:02 by PRATT
;Use different entry point for killing ARP from NIPKIL than from IPOPR
; UPD ID= 109, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.43,  12-May-84 18:13:21 by PRATT
;CLRBLK smashes the acs, call it later in the code in NIHSPC
; UPD ID= 107, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.42,  12-May-84 18:09:34 by PRATT
;If ARPON is on, make ARPINI always succeed (for IPOPR)
;Make ARPKIL global for IPOPR
; UPD ID= 104, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.41,  12-May-84 17:34:09 by PRATT
;Fix ARPUPD to point at insertion point in ght area 2 + entry size
; UPD ID= 93, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.40,  12-May-84 09:50:32 by PRATT
;Leave in hook to send ICMP msg on datagram too long error
;Add ENDxx. macros to close off trvars and stkvars
;Make restart code be more forgiving on ght errors
; UPD ID= 92, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.39,  11-May-84 18:12:13 by PRATT
;Use CLRBLK after calls to GETBLK in various places
; UPD ID= 91, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.38,  11-May-84 16:58:20 by PRATT
;Fix routines which skip return when the callers didn't expect it
; UPD ID= 90, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.37,  11-May-84 16:39:43 by PRATT
;Correct error status does not come from UNSST on callback, use T3 directly
; UPD ID= 89, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.36,  11-May-84 14:14:09 by PRATT
;Fix some typos
; UPD ID= 88, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.35,  11-May-84 14:07:56 by PRATT
;Don't process ARP during interrupt level, let the Internet fork do it
;Make NIPSTO more efficient with it's ac's
; UPD ID= 87, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.34,  10-May-84 16:08:05 by PRATT
;Fix ARP problem that put our ARP buffers in NISRV's portal list
;Use a send buffer during ARP replies, don't re-use the rcv buffer
; UPD ID= 85, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.33,  10-May-84 09:36:18 by PRATT
;Fix "small ght" problem, and general cleanup
; UPD ID= 83, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.32,   9-May-84 13:46:16 by PRATT
;Point at -lclpkt(rid) when calling RETNIB on errors
; UPD ID= 82, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.31,   9-May-84 13:03:45 by PRATT
;Use UNPID not UNPRO in read portal counters
; UPD ID= 81, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.30,   8-May-84 16:03:38 by PRATT
;Fix ARPOST/ARPCDR if post errors
;INTSRC must be resident since it's called during ARP receives
;GETRPC, ARPKIL and ARPBUF can be in swapcd
; UPD ID= 80, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.29,   8-May-84 15:38:27 by PRATT
;Don't call IPFERR if sends fail, datagram not sent buginf will suffice
; UPD ID= 77, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.28,   8-May-84 15:22:49 by PRATT
;Release input buffer if error during post. Count # of buffers posted
; UPD ID= 76, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.27,   7-May-84 16:07:16 by PRATT
;Buffer threshold for 1822 buffers. Don't init NIPNIB from NIPINI
; UPD ID= 73, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.26,   7-May-84 09:35:02 by PRATT
;Better error handling for ght's. If no ght entry for this host, build one
; UPD ID= 72, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.25,   5-May-84 11:48:16 by PRATT
;Remove the debugging code
; UPD ID= 71, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.24,   5-May-84 11:29:11 by PRATT
;Call NIOFF only from NIPKIL, Move NIPHNG to IPFERR
; UPD ID= 70, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.23,   4-May-84 15:48:54 by PRATT
;Set ARPENA from setting in STG 
; UPD ID= 69, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.22,   4-May-84 15:45:27 by PRATT
;Even more debugging code for ILULK2's
; UPD ID= 68, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.21,   4-May-84 15:40:53 by PRATT
;Allow GH%DMB, host does not have ARP, use ght address
; UPD ID= 63, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.20,   3-May-84 13:54:13 by PAETZOLD
;IPLTRK calls need IPLDSW control
; UPD ID= 62, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.19,   2-May-84 21:36:18 by PRATT
;Fix gh.gcf, intsrc, nisend, and nipcka for various problems
;Add more debugging code, add prblem macro
; UPD ID= 58, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.18,   2-May-84 13:51:06 by PRATT
;If using ARP, make sure Ethernet address in GHT is valid
; UPD ID= 57, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.17,   2-May-84 12:57:10 by PRATT
;Fix ipferr startup and niplkb/nipulk smashed ac problems
; UPD ID= 48, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.16,   1-May-84 16:05:17 by PRATT
;Fix getblk/retblk problems in NIHINI
; UPD ID= 47, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.15,   1-May-84 15:29:26 by PRATT
;In UNSET, clear 1 location less than UN.LEN
; UPD ID= 46, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.14,   1-May-84 14:59:37 by PRATT
;Use ARPENA, not ARPON in the check ethernet address code
; UPD ID= 44, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.13,   1-May-84 13:26:07 by PRATT
;Add debugging code to NIPSTO, NISEND, and IPCBDS
; UPD ID= 41, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.12,  30-Apr-84 10:34:34 by PRATT
;Fix ILULK2 bughalts if NISRV returns an error in NISEND. More cleanup.
; UPD ID= 40, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.11,  24-Apr-84 14:34:41 by PRATT
;Add read portal counters for ARP
; UPD ID= 39, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.10,  24-Apr-84 13:08:42 by PRATT
;Add Address Resolution Protocol... ARP
; UPD ID= 36, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.9,  10-Apr-84 15:33:10 by PRATT
;Change NIPON from being "off and on" to "off and degrees of on"
; UPD ID= 35, SNARK:<TCPIP.5.4.MONITOR>IPNIDV.MAC.8,  10-Apr-84 13:17:58 by PRATT
;Remove local loopback code. Fix problem with sending to ourself.
;Clean up code. Begin source code control using ALU.
;TCPNI demo'd to management Apr 9, 1984.

;THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY  BE  USED
;OR COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE.
;
;COPYRIGHT  (C)  DIGITAL  EQUIPMENT  CORPORATION  1976, 1985.
;ALL RIGHTS RESERVED.

	SEARCH ANAUNV,PROLOG,NIPAR

	TTITLE (IPNIDV,IPNIDV,< - Internet Ethernet Interface>)

	IFNDEF REL6,<REL6==1>		; default is release 6
	IFNDEF IPNDSW,<IPNDSW==:0>	; default is no nisrv debuging stuff
	IF1 <IFN IPNDSW,<PRINTX Assembling Debuging NI queuing routines>>
	SALL
	.DIRECTIVE FLBLST
	SUBTTL Definitions


;Special AC definitions

	SRV==Q1			;TYPE OF SERVICE
	ARP==Q2			;ADDRESS OF ARP PACKET
	NCT==P1			;ADDRESS OF OUR NCT
	UNB==P2			;UN BLOCK ADDRESS
	RID==P3			;REQUEST ID (BUFFER ADDRESS)
	CPKT==P3		;ICMP PACKET POINTER

;Internal error codes for debugging

	NI.ER1==610001		;NIPBFR COULDN'T GET A BUFFER
	NI.ER2==610002		;ETHERNET ADDRESS CHANGED
	NI.ER3==610003		;ILLEGAL NISRV CALLBACK VECTOR
	NI.ER5==610005		;COULDN'T GET A UN BLOCK
	NI.ER6==610006		;COULDN'T GET FREE SPACE FOR PORTAL COUNTERS
	NI.ER7==610007		;GHT FULL, ARP PACKET NOT INSERTED
	NI.ER8==610010		;IPNIDV NOT INITIALIZED YET
	NI.ER9==610011		;KLNI STOPPED FOR SOME REASON


;NI "ON" flags, each successive value implies all of the previous

	NI.ON==1		;Portal open (but not necessarily ready)
	NI.RDY==3		;Interface is ready for use


;Type of service. Used in selecting the UN block, callback dispatches, etc

	NI.INT==1		;INTERNET
	NI.ARP==2		;ARP
	NI.TRL==3		;TRAILER ENCAPSULATED PACKETS

;Ethernet protocol types (UNPRO in UN block)

	IPROTO==^D2048		;INTERNET
	APROTO==^D2054		;ARP
	TPROTO==^D4096		;TRAILER ENCAPSULATED PACKET 

	TRMAXP==3		;OPEN PORTALS FOR (0,512,1024) BYTE PACKETS
	SUBTTL Miscellaneous Definitions

	EMINPL==^D46		;MINIMUM ETHERNET PACKET LENGTH
	MINPKT==EMINPL+4	;MINIMUM ETHERNET PACKET LENGTH PLUS CRC BYTES
	GH.EN1==.NIEN1-1	;GHTAR2 ETHERNET ADR HIGH ORDER BYTES
	GH.EN2==.NIEN2-1	;GHTAR2 ETHERNET ADR LOW ORDER BYTES
	GH.GCF==.NIGCF-1	;GHTAR2 GATEWAY CONTROL FLAGS
	GH2MDL==NIHMDL-1	;LENGTH OF AN AREA 2 ENTRY
	NI.HOP==.NBLD1		;ROUTING ADRESS IS KEPT IN THE LEADER
	SRCMAX==^D10		;MAX ENTRIES IN GHT BEFORE USING BINARY SEARCH
	AR.TNB==^D10		;GET TOTAL OF 10 ARP BUFFERS
	UN.TNB==7		;GET TOTAL OF 7 UN BLOCKS
	MSD1==UN.LEN+1		;1ST MSD IS AT END OF UN BLOCK
	MSD2==MSD1+MD.LEN+1	;2ND MSD IS AT THE END OF THE 1ST MSD
	MS.LEN==<MD.LEN+1>*2	;SIZE OF BOTH MSD'S TOGETHER
	SUBTTL ARP Packet Definitions

	ARPQUE==0		;TYPE AND POINTER OFFSET
	ARPPKT==1		;BEGINNING OF THE ARP PACKET
	ARPCRC==7		;ETHERNET CRC BYTES

DEFSTR ARTYP,ARPQUE,4,1		;0=SEND BFR, 1=RECEIVE BFR
DEFSTR ARPNT,ARPQUE,35,30 	;POINTER TO NEXT BUFFER 
DEFSTR AR$HD,ARPPKT,15,16 	;HARDWARE ADDRESS TYPE
  AR.ETH==1			;  ETHERNET IS TYPE 1
DEFSTR AR$PR,ARPPKT,31,16 	;INTERNET PROTOCOL TYPE
DEFSTR AR$HL,ARPPKT+1,7,8	;BYTE LENGTH OF HARDWARE ADDRESS
  AR.HLN==6			;  ETHERNET ADDRESSES ARE 6 BYTES 
DEFSTR AR$PL,ARPPKT+1,15,8	;BYTE LENGTH OF PROTOCOL ADDRESS
  AR.PLN==4			;  INTERNET ADDRESSES ARE 4 BYTES 
DEFSTR AR$OP,ARPPKT+1,31,16	;OPCODE
  AR.REQ==1			;  REQUEST
  AR.REP==2			;  REPLY
DEFSTR AR$S1,ARPPKT+2,31,32	;SENDER HARDWARE ADDRESS (WORD 1)
DEFSTR AR$S2,ARPPKT+3,15,16	;SENDER PROTOCOL ADDRESS (WORD 2)
DEFSTR AR$P1,ARPPKT+3,31,16	;SENDER PROTOCOL ADDRESS (WORD 1)
DEFSTR AR$P2,ARPPKT+4,15,16	;SENDER PROTOCOL ADDRESS (WORD 2)
DEFSTR AR$R1,ARPPKT+4,31,16	;TARGET HARDWARE ADDRESS (WORD 1)
DEFSTR AR$R2,ARPPKT+5,31,32	;TARGET HARDWARE ADDRESS (WORD 2)
DEFSTR AR$TA,ARPPKT+6,31,32	;TARGET PROTOCOL ADDRESS 
DEFSTR ACRC,ARPCRC,31,32	;CRC (NOT PART OF THE ARP PACKET)

	AR.WRD==ARPCRC+2	;NUMBER OF WORDS IN AN ARP PACKET + 1
	AR.LEN==<AR.WRD-2>*4	;LENGTH IN BYTES OF AN ARP PACKET
	AR.MAX==AR.LEN+4	;MAX BUFFER SIZE MUST INCLUDE CRC

; If  AR.LEN  is  less than MINPKT (Ethernet minimum packet size
; plus 4 bytes for the CRC) we must make the ARP packets atleast
; that size.

  IFL AR.LEN-EMINPL,<

	AR.WRD==<MINPKT/4>+4	;WORD SIZE OF ARP PACKET (PLUS A COUPLE)
	AR.LEN==EMINPL  	;BYTES IN ARP PACKET ARE ETHERNET MINIMUM
;**;[7227] Change 1 line at ARP definitions	WCM	14-Jan-86
	AR.MAX==MINPKT+20	;[7227]MAX BFR SIZE WITH ETHERNET CRC (PLUS 20)

  >
	SUBTTL NI Debuging Stuff

IFN IPNDSW,<

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

RS IPNQUE,1			;HEAD OF QUEUE OF BUFFERS GIVEN TO NISRV

IPNENQ:				;BUFFER ADDRESS IN T1
	SAVET			;SAVE ACS
	CONI PI,T4		;GET PI STATE
	PIOFF			;AND STOP THE MACHINE
	HRRZS T1		;ZERO THE LEFT HALF
	MOVEI T2,IPNQUE		;GET ADDRESS OF THE HEAD OF THE QUEUE
IPNENL:				;QUEUE CHECKING LOOP
	LOAD T2,NBQUE,(T2)	;GET THE NEXT ITEM
	JUMPE T2,IPNENN		;NOT FOUND...GOOD
	CAMN T1,T2		;IS THIS OUR ITEM?
	BUG.(HLT,IPNHIT,IPNIDV,SOFT,<Already queued buffer being queued to NISRV>,,<

Cause:	The monitor has detected an inconsistency in the handling of NISRV
	related internet buffers.  This is conditional code which is only
	enabled during debugging.

>)
	SETSEC T2,INTSEC	;SETUP THE CORRECT SECTION
	JRST IPNENL		;KEEP LOOKING
IPNENN:				;HERE WHEN THE BUFFER WAS NOT FOUND
	LOAD T2,NBQUE,+IPNQUE	;GET THE OLD HEAD
	STOR T1,NBQUE,+IPNQUE	;THIS IS THE NEW HEAD
	SETSEC T1,INTSEC	;SETUP THE SECTION NUMBER
	STOR T2,NBQUE,(T1)	;MAKE THE REST OF THE LIST COME OFF US
	TXNE T4,<PIPION>	;WAS PI SYSTEM ON?
	 PION			;YES SO TURN IT BACK ON
	RET			;AND RETURN

IPNDEQ:				;BUFFER ADDRESS IN T1
	SAVET			;SAVE ACS
	CONI PI,T4		;GET PI STATE
	PIOFF			;AND STOP THE MACHINE
	HRRZS T1		;ZERO THE LEFT HALF
	MOVEI T2,IPNQUE		;GET THE HEAD OF THE QUEUE
IPNDEL:				;QUEUE CHECKING LOOP
	MOVE T3,T2		;SAVE THE OLD ITEM
	LOAD T2,NBQUE,(T2)	;GET THE NEXT ITEM
	SKIPN T2		;NOT FOUND...BAD
	BUG.(HLT,IPNMIS,IPNIDV,SOFT,<Buffer not queued to NISRV being dequeued>,,<

Cause:	The monitor has detected an inconsistency in the handling of NISRV
	related internet buffers.  This is conditional code which is only
	enabled during debugging.

>)
	CAMN T1,T2		;IS THIS OUR ITEM?
	 JRST IPNDEF		;FOUND....GOOD
	SETSEC T2,INTSEC	;SETUP THE CORRECT SECTION
	JRST IPNDEL		;KEEP LOOKING
IPNDEF:				;HERE WHEN THE ITEM WAS FOUND
	SETSEC T2,INTSEC	;SETUP THE SECTION NUMBER
	LOAD T2,NBQUE,(T2)	;GET THIS ITEMS QUEUE POINTER
	STOR T2,NBQUE,(T3)	;OLD ITEM POINTS TO THIS ITEM
	TXNE T4,<PIPION>	;WAS PI SYSTEM ON?
	 PION			;YES SO TURN IT BACK ON
	RET			;AND RETURN

>				;END OF IFN IPNDSW
	SUBTTL NISRV Callback Dispatch Tables 

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

CBTAB:	NCTDSP IPNDSP			;INTERNET
	NCTDSP ARPDSP			;ARP
	NCTDSP TRLDSP			;TRAILER ENCAPSULATED PACKETS

IFE REL6,<XXXSEC==<MSEC1,,0>>
IFN REL6,<XXXSEC==<XCDSEC,,0>>

;Internet service
IPNDSP:	TABBEG NU.OPN,NU.MAX,<XXXSEC!ICBVCT>	;UNKNOWN CALLBACKS BUGCHK
	  TABENT NU.CLO,<XXXSEC!RSKP>	;CLOSE COMPLETED
	  TABENT NU.RCV,<XXXSEC!IPCBDR>	;RECEIVED A DATAGRAM
	  TABENT NU.XMT,<XXXSEC!IPCBDS>	;DATAGRAM SENT
	  TABENT NU.RPC,<XXXSEC!IPCBRC>	;READ PORTAL COUNTERS
	  TABENT NU.RCI,<XXXSEC!IPCBLS>	;CHANNEL STATE CHANGE
	  TABENT NU.SCA,<XXXSEC!IPCBAC>	;ADDRESS CHANGE
	TABEND

;Arp service
ARPDSP:	TABBEG NU.OPN,NU.MAX,<XXXSEC!ICBVCT>	;UNKNOWN CALLBACKS BUGCHK
	  TABENT NU.CLO,<XXXSEC!RSKP>	;CLOSE COMPLETED
	  TABENT NU.RCV,<XXXSEC!ARPCDR>	;RECEIVED A DATAGRAM
	  TABENT NU.XMT,<XXXSEC!ARPCDS>	;DATAGRAM SENT
	  TABENT NU.RPC,<XXXSEC!ARPCRP>	;READ PORTAL COUNTERS
	  TABENT NU.RCI,<XXXSEC!RSKP>	;CHANNEL STATE CHANGE
	  TABENT NU.SCA,<XXXSEC!RSKP>	;ADDRESS CHANGE
	TABEND

;Trailer encapsulation service
TRLDSP:	TABBEG NU.OPN,NU.MAX,<XXXSEC!ICBVCT>	;UNKNOWN CALLBACKS BUGCHK
	  TABENT NU.CLO,<XXXSEC!RSKP>	;CLOSE COMPLETED
	  TABENT NU.RCV,<XXXSEC!TRLCDR>	;RECEIVED A DATAGRAM
	  TABENT NU.RCI,<XXXSEC!RSKP>	;CHANNEL STATE CHANGE
	  TABENT NU.SCA,<XXXSEC!RSKP>	;ADDRESS CHANGE
	TABEND
	SUBTTL Initialization Routines

;NIPINI - INITIALIZATION 
;
; Called from MNTINI when initializing all of the networks known
; to  Multinet. 
;
; NCT/ NCT address 
;
; Returns + 1 always 

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIPINI::MOVEM NCT,NIPNCT	;SAVE OUR NCT FOR THE CALLBACK ROUTINE
	SETZM HSTGDM(NCT)	;CANCEL GOING DOWN MESSAGES
 	RET



;NICBAK - CALLBACK DISPATCH
;
; Routine  that  NISRV  calls  so  that  we  can  do  a callback
; dispatch for all types of service.
; 
; T1/ callback function code
; T2/ address of the UN block
; T3/ 0 if function succesfull or error code
;
; Returns + 1 always

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

NICBAK:	SAVEAC <T1,SRV,ARP,RID,NCT,UNB>
	LOAD SRV,UNUID,(T2)	;GET USERID
	HRRZS SRV		;BUT USE ONLY TYPE OF SERVICE PORTION
	ADD T1,CBTAB-1(SRV)	;POINT AT DISPATCH ADDRESS
	CALL @-1(T1)		;DISPATCH 
	 MOVEM T1,NIPERR	;ON ERROR - SAVE ERROR CODE AWAY
	RET

;Illegal callback vector from NISRV

ICBVCT: BUG. (CHK,IPFBCV,IPNIDV,SOFT,<IPNI: Illegal callback vector>,<<T1,CODE>>,<

Cause:	NISRV has passed an illegal or unknown callback vector to the
	internet ethernet software.

>)
	MOVEI T1,NI.ER3		;SET UP ERROR
	RET
	SUBTTL Initialization Routines - Restart

;NIPRST - RESTART
;
; Call here when we want to open the Internet portal.
;
; NCT/ NCT address
;
; Returns + 1 always

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIPRST::SKIPN INTON		;HAS INTERNET BEEN INITIALIZED ?
	RET			;NO. NOT READY YET.
	SKIPG T1,NTLADR(NCT)	;SEE IF WE HAVE HOST NUMBER YET
	RET			;NO. NOT READY YET.
	SETZM NTTOUT(NCT)	;CLEAR OUTPUT HUNG TIMEOUT
	CALL NIRINI		;INITIALIZE US IF NEEDED
	 JRST NRSTER		;COULDN'T
	MOVEI T1,NI.RDY
	MOVEM T1,NIPON		;INTERFACE IS READY
	AOS NTSTCH(NCT)		;CAUSE CHANGE IN STATE TO BE NOTED
	GTAD
	MOVEM T1,NTXUPP(NCT)	;SAVE TIME WHEN IT CAME UP
	SETOM NTRDY(NCT)	;INDICATE FULLY UP
	SETOM NTORDY(NCT)	;ALLOW OUTPUT
	SETZM NTOB(NCT)		;NO OUTPUT IN PROGRESS
	SKIPN ARPENA		;IS ARP ENABLED ?
	IFSKP.
	 CALL ARPINI		;YES, START IT UP
	  BUG.(CHK,IPARPE,IPNIDV,SOFT,<ARP did not initialize>,<<T1,ERROR>>,<

Cause:	The ethernet ARP (Address resolution protocol) portal did not initialize.
	This is probably a temporary resource allocation problem.

>)
	ENDIF.
	SKIPN TRLENA		;WANT TO ENABLE TRAILER DETECTION ?
	IFSKP.
	 CALL TRLINI		;YES
	  BUG.(CHK,IPTRLE,IPNIDV,SOFT,<Trailer detection code did not initialize>,<<T1,ERROR>>,<

Cause:	The ethernet trailer encapsulation detection portals did not initialize.
	This is probably a temporary resource allocation problem.

>)
	ENDIF.
	CALL INTUP		;INTERFACE IS UP
	CALL NIPSTO		;START OUTPUT IF NEEDED
	AOS JB0FLG		;NOTE NETWORK CHANGE
	CALL WERHER		;TELL EVERYONE THAT WE ARE NOW HERE
	RET

;Here to save away the error 

NRSTER:	MOVEM T1,NIPERR		;SAVE THE ERROR CODE FOR LATER
	CALL NIPHNG		;MAKE IT LOOK LIKE THE NI IS SHUTDOWN
	RET
	SUBTTL Initialization Routines - Driver Initialization

;NIRINI - INITIALIZE THE DRIVER
;
; Called from the network restart code to initialize IPNIDV.
;
; Returns + 1 on error with T1/ error code
;	  + 2 on success

NIRINI:	SAVEAC <UNB,SRV>
	SKIPE GHTAR1		;HOST TABLES INIT'D ?
	IFSKP.
	 CALL NIHINI		;SEE IF WE CAN READ THE GHT
	 IFNSK.
	  BUG.(INF,IPHTNI,IPNIDV,SOFT,<Error while reading GHT>,<<T1,ERROR>>,<

Cause:	The monitor detected a problem when attempting to read the
	SYSTEM:INTERNET-ETHERNET-MAPPINGS.BIN file during initialization.

>)
	  CAIN T1,IPHNSP	;WAS THERE SPACE FOR THE GHT ?
	  IFSKP.
	   SKIPE ARPENA		;YES - ARP GOING TO BE USED ? 
	   JRST RST2		;YES - ALLOW US TO GO ON
	  ENDIF.
	  CALL NIPKIL		;DON'T ALLOW THE INTERFACE TO COME UP
	  RETBAD              	;GET BACK THE ERROR CODE
	 ENDIF.
	ENDIF.
RST2:	CALL NIPGIB		;GRAB A BUNCH OF INPUT BUFFERS
	MOVE T1,NIPON		;GET "ON" FLAGS
	CAIL T1,NI.ON		;PORTAL ALREADY OPEN ?
	IFSKP.
	 CALL NIOPEN		;NO - GO TRY TO OPEN IT
	  RETBAD		;COULDN'T
	ENDIF.
	CALL INTUNB		;GET A UN BLOCK
	 RETBAD			;COULDN'T
	CALL NISTAT		;GET THE STATUS OF KLNI
	 JRST NIRST2		;ERROR. RELEASE THE UN BLOCK
	CALL NIPPIB		;INITIALIZE INPUT BUFFERS
	 JRST NIRST2		;ERROR. RELEASE THE UN BLOCK
	CALL RETUNB		;RELEASE THE UN BLOCK WE'VE BEEN USING
	RETSKP

;Here when we got an error, put the UN block on the free queue

NIRST2:	CALL RETUNB		;MAKE UN BLOCK AVAILABLE
	RETBAD
	SUBTTL Initialization Routines - Open NISRV Portal

;NIOPEN - OPEN NI PORTAL
;
; Called here from the restart code to open a portal
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIOPEN:	TRVAR <UNBLK>
	MOVEI T1,UN.LEN		;RESERVE WORDS FOR A UN BLOCK
	CALL GETBLK		;GET THEM
	JUMPE T1,[RETBAD <NI.ER5>] ;COULDN'T
	MOVEM T1,UNBLK		;SAVE UN BLOCK FOR LATER
	MOVE UNB,T1		;COPY IT
	MOVEI SRV,NI.INT	;TYPE OF SERVICE IS INTERNET
	MOVEI T1,IPROTO		;INTERNET ETHERNET PROTOCOL TYPE
	CALL UNSET		;SET UP THE UN BLOCK
	MOVX T1,NU.OPN		;OPEN NI PORT FUNCTION
	MOVE T2,UNB    		;POINT AT THE UN BLOCK
	CALL DLLUNI		;CALL NI DRIVER
	 JRST NIOPN1		;ERROR. RETURN UN BLOCK
	SKIPE UNBNFI		;HAVE SOME UN BLOCKS YET ?
	IFSKP.
	 LOAD T1,UNPID,(UNB)	;NO - USING THIS PORTAL ID,
	 CALL GUNBLK		;GET SOME UN BLOCKS
	  RETBAD		;COULDN'T
	ENDIF.
	MOVEI T1,NI.ON
	MOVEM T1,NIPON		;IPNI PORTAL IS OPEN
	CALL NIOPN2		;GO RELEASE THE UN BLOCK WE GOT
	RETSKP

;Here when we got an error opening the portal

NIOPN1:	MOVEM T1,NIPERR		;SAVE THE ERROR
	CALL NIOPN2		;RELEASE THE UN BLOCK
	RETBAD <>,<MOVE T1,NIPERR> ;RESTORE ERROR CODE

;Here to return the UN block we just got.

NIOPN2:	MOVE T1,UNBLK		;GET UN BLOCK ADR 
	CALLRET RETBLK		;AND RELEASE THE SPACE

	ENDTV.			;END OF NIOPEN TRVAR
	SUBTTL Status Checks for Multinet

;NIPSTA - STATUS CHECK 
;
; This  routine  is  called from Multinet to check the status of
; the KLNI.
;
; NCT/ NCT address
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIPSTA::SAVEAC <SRV,UNB>
	SKIPN UNBNFI		;DO WE HAVE ANY UN BLOCKS YET ?
	RETBAD			;NO - CAN'T CHECK STATUS UNTIL WE DO
	CALL INTUNB		;YES - SET UP POINTER TO UN BLOCK
	 RETBAD			;IGNORE THE ERROR UNTIL WE'RE INIT'D
	CALL NISTAT		;GET THE STATUS
	 RETBAD <>,<CALL RETUNB> ;IGNORE THE ERROR 
	CALL RETUNB		;RELEASE THE UN BLOCK
	RETSKP


;IPCBLS - LINE STATE CHANGE
;
; This  is  an  unsolicated callback which occurs when NISRV has
; detected a state change in the NI.
;
; Alternate  entry point  CKSTAT is called from  NIPSTA to check 
; the status returned in the UN block.
;
; T2/   UN block address
; T3/   0 or NISRV error code
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

IPCBLS:	MOVE NCT,NIPNCT		;GET THE NCT ADDRESS
	MOVE UNB,T2		;SET UP WITH NISRV'S UN BLOCK
	CALL CKSTAT		;CHECK THE STATUS
	IFNSK.
	 SETOM NIPSHT		;FLAG CHANGE TO SHUT KLNI DOWN
	 RETBAD <NI.ER9>
	ENDIF.
	SKIPN NIPON		;STATUS IS UP. ARE WE INIT'D
	RETBAD			;NO 
	AOS NIPRSF		;TELL THE INTERNET FORK TO RESTART IPNI
	AOS INTFLG		;WE WANT THE INTERNET FORK TO RUN
	AOS PSKD1		;MAKE THE SCHEDULER NOTICE THIS IF IN NULL JOB
	RETSKP			;GIVE A GOOD RETURN
	SUBTTL KLNI Status Check Routines

;NISTAT - CHECK STATUS OF KLNI
;
; NISTAT  is called from the restart code and from the ARP start
; up code to check the status of the NI after  the  channel  has
; been opened.
;
; UNB/ UN block address (for CKSTAT)
; NCT/ NCT address
;
; Returns + 1 from NIPHNG on error
;	  + 2 from CKSTAT on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NISTAT:	SETZM NTERRF(NCT)	;CLEAR NOTICES OF ERRORS
	MOVE T1,NIPON		;GET "ON" FLAGS
	SKIPE INTON		;HAS INTERNET BEEN STARTED ?
	 CAIGE T1,NI.ON		; AND HAVE WE DONE THE OPEN YET ?
	  CALLRET NIPHNG      	;NO - WAIT 
	MOVX T1,NU.RCI		;READ CHANNEL STATUS
	MOVE T2,UNB    		;POINT AT UN BLOCK
	CALL DLLUNI		;CALL NISRV
	 JRST NISTR1		;HANDLE THE ERROR
	JRST CKSTAT		;GO CHECK THE STATUS WORDS

;Here when no UN block was available

NISTER:	MOVEI T1,NI.ER8		;SET THE ERROR CODE
NISTR1:	MOVEM T1,NIPERR		;SAVE IT
	CALLRET NIPHNG		;SLOW DOWN RETRIES FOR A WHILE


;Here to check the status of the KLNI.

CKSTAT:	LOAD T3,UNCAR,(UNB)	;GET CURRENT ETHERNET ADDRESS
	LOAD T4,UNCAR,+1(UNB)	;GET 2ND HALF TOO
	DMOVEM T3,ETHADR	;SAVE THEM
	LOAD T1,UNSTA,(UNB)	;GET THE CHANNEL STATUS
	TXNE T1,UNRUN		;CHANNEL RUNNING OKAY ?
	RETSKP			;YES
	LOAD T1,UNSST,(UNB)	;GET SECONDARY STATUS
	MOVEM T1,ICHNST		;SAVE IT
	CALL NIPHNG		;FINISH UP ERROR RECOVERY
	RETBAD
	SUBTTL Output Routines

;NIPHDR - BUILD HEADER 
;
; Called from Multinet to build a header for the local transport
; layer. In our case, the only essential information is the host
; number of the next node which can route the packet.
;
; T1/  local address to send to
; T2/  address of buffer
; NCT/  NCT address
;
; Returns + 1 always

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIPHDR::MOVEM T1,NI.HOP(T2)	;STORE DESTINATION ADDRESS
	RET
	SUBTTL Output Routines - Start Output

;NIPSTO - START OUTPUT
;
; Called to send an output buffer.
;
; NCT/ NCT address 
; NTIOBO/ pointer to the list of internet buffers to send 
; NTIOBI/ tail end of the list
;
; Returns +1 always

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

NIPSTO::SAVEAC <SRV,UNB,RID>	;START OUTPUT 
	PIOFF			;STOP THE MACHINE
	SKIPN NTOB(NCT)		;OUTPUT IN PROGRESS?
	 SKIPN RID,NTIOBO(NCT)	;ANY INTERNET OUTPUT WAITING?
	  JRST NIPSTX		;NO WORK TO DO OR ALLREADY IN PROGRESS
NIPOS1:				;THIS IS THE LOOP FOR POSTING ALL THE BUFFERS
	SETOM NTOB(NCT)		;FLAG THAT OUTPUT IS IN PROGRESS
	LOAD T1,NBQUE,(RID)	;GET THE SUCCESSOR BUFFER TO THIS ONE
	SKIPE T1		;DOES IT HAVE A SUCCESSOR?
	IFSKP.
	 SETZM NTIOBI(NCT)	;NO SO RESET THE TAIL
	ELSE.
	 SETSEC T1,INTSEC	;YES SO SET THE SECTION NUMBER
	ENDIF.
	MOVEM T1,NTIOBO(NCT)	;SAVE THE NEW HEAD
	SETZRO NBQUE,(RID)	;DEQUEUE BUFFER FROM ITS OLD CHAIN
	PION			;BUFFER IS DEQUEUED SO GIVE BACK THE MACHINE
  	MOVEI SRV,NI.INT	;TYPE OF SERVICE IS INTERNET
	CALL NISEND		;NO. SEND TO NISRV
	 JRST NIPSTR		;HMMMM.  ERROR.
	SETZM NTTOUT(NCT)	;CLEAR OUTPUT HUNG TIMEOUT
	PIOFF			;LOOKS THAT WAY, SO STOP THE MACHINE
	SKIPE RID,NTIOBO(NCT)	;ANY INTERNET OUTPUT WAITING?
	 JRST NIPOS1		;TRY FOR MORE
NIPSTR:	SETZM NTOB(NCT)		;RESET OUTPUT IN PROGRESS FLAG
NIPSTX:	PION			;GIVE BACK THE MACHINE
	RET			;AND RETURN
	SUBTTL Output Routines - Send Packet

;NISEND - SEND PACKET TO NISRV
;
; Set up the UN block and gives the packet to NISRV. For IP packets that 
; are smaller than the Ethernet minimum, an MSD style transmit is done.
;
; NCT/ NCT address
; RID/ address of buffer
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NISEND:
IFN IPNDSW,<
	MOVE T1,RID		;PUT ADDRESS IN ITS PLACE
	CALL IPNENQ>		;LINK THIS BUFFER AS QUEUED
	XMOVEI T2,-LCLPKT(RID)	;POINT TO RIGHT LOCATION TO PICK UP PIDH
	LOAD T3,PIDH,(T2)	;GET THE DESTINATION HOST #
	CAMN T3,NTLADR(NCT)   	;DESTINED FOR US ?
	CALLRET NILCAL		;YES
	MOVE T2,NI.HOP(RID)	;GET THE ROUTING ADDRESS
	CALL INTSRC		;GO FIND HOST # IN GHT
	 CALLRET NIUNKA		;UNKNOWN ROUTING ADDRESS, CHECK IT
	SKIPN ARPON		;IS ARP ON ?
	IFSKP.
	 CALL NIVLDA		;YES - VALIDATE THE ETHERNET ADDRESS
	  CALLRET NIRELB 	;ADDRESS NOT VALID, ARP MSG SENT 
	ENDIF.
	CALL INTUNB		;GET A UN BLOCK TO USE
	 CALLRET NISND1		;NO UN BLOCK, DROP THE PACKET AND BUGINF
	DMOVE T3,GH.EN1(T2)	;GET BOTH WORDS OF ETHERNET ADDRESS
	STOR T3,UNDAD,(UNB)	;SAVE THEM IN THE UN BLOCK
	STOR T4,UNDAD,+1(UNB)	
	STOR RID,UNRID,(UNB)	;SAVE BUFFER ADR AS REQUEST ID
	XMOVEI T2,-LCLPKT(RID)	;POINT TO RIGHT LOCATION TO PICK UP LENGTH
	LOAD T1,PIPL,(T2)	;GET PACKET LENGTH 
	CAIGE T1,EMINPL		;LESS THAN THE MINIMUM ETHERNET REQUIREMENT?
	IFSKP.
	 STOR T1,UNBSZ,(UNB)	;NO - DON'T NEED MSD'S - SAVE LENGTH FOR NISRV 
	 XMOVEI T3,MAXLDR(RID)	;POINTER TO IP PACKET 
	 TXO T3,<OWGP. 8,>	;FORM BYTE POINTER TO BUFFER
	 STOR T3,UNBFA,(UNB)	;SAVE IT AWAY
	ELSE.
	 SETZRO UNBSZ,(UNB)	;YES - NEED MSD'S - ZERO THE UN BLOCK BYTE COUNT 
	 XMOVEI T3,MSD1(UNB)	;GET POINTER TO FIRST MSD
	 XMOVEI T4,MSD2(UNB)	;GET POINTER FOR 2ND MSD
	 STOR T3,UNBFA,(UNB)	;SAVE POINTER TO 1ST MSD IN UN BLOCK
	 STOR T1,MDBYT,(T3)	;SAVE PACKET BYTE COUNT IN MSD 1
	 MOVEI T2,EMINPL	;GET MINIMUM ETHERNET PACKET SIZE
	 SUB T2,T1		;COMPUTE # OF BYTES NEEDED FOR PADDING
	 STOR T2,MDBYT,(T4)	;SAVE PAD BYTE COUNT IN 2ND MSD
	 XMOVEI T2,MAXLDR(RID)	;POINTER TO IP PACKET 
	 STOR T2,MDALA,(T3)	;SAVE AS BUFFER ADDRESS IN MSD 1
	ENDIF.
	MOVX T1,NU.XMT		;SET FUNCTION CODE TO TRANSMIT
	MOVE T2,UNB      	;POINT AT UN BLOCK 
	CALL DLLUNI		;SEND THE BUFFER
	 CALLRET NISND2		;GO RELEASE THE UN BLOCK AND HANDLE ERROR
	CALL RETUNB		;GO RELEASE THIS UN BLOCK
	RETSKP
	SUBTTL Output Routines - Local Message Handling

;NILCAL - LOCAL LOOPBACK
;
; Called  from NISEND to handle a message to ourself. We reserve
; a input buffer and copy the IP packet into it, queue  it,  and
; release  the  old  packet.  This routine is needed because the
; KLNI only has one CRC generator and two are needed to send and
; receive a packet at the same time.
;
; RID/ address of the outgoing IP packet
; NCT/ address of the NCT
;
; Returns via NIRELB

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NILCAL:	STKVAR <BFA>
	CALL NIPGIB		;MAKE SURE WE HAVE ENOUGH BUFFERS
	CALL NIPBFR		;GET A BUFFER TO USE
	JUMPE T1,[MOVEI T1,NI.ER1 ;NO BUFFER ERROR
		  CALLRET NISND1]
	MOVEM T1,BFA   		;SAVE THE NEW BUFFER ADDRESS
	XMOVEI T2,-LCLPKT(RID)	;POINT AT PACKET HEADER BEGINNING
	LOAD T1,PIPL,(T2)	;HEADER LENGTH IN BYTES
	ADDI T1,3+PKTELI*4	;PACKET SIZE IN BYTES, ROUNDED UP
	ASH T1,-2		;PACKET SIZE IN FULL WORDS
	XMOVEI T2,MAXLDR(RID)	;POINT TO BEGINNING OF BUFFER
 	MOVE T3,BFA        	;DESTINATION IS THE POSTED RCV BUFFER'S
	ADDI T3,MAXLDR		; DATA AREA
	CALL XBLTA		;COPY IP HEADERS
	MOVE T1,BFA       	;POINT AT RCV BUFFER
	CALL NIPQUE		;GIVE THE BUFFER TO INTERNET
	CALLRET NIRELB		;RELEASE OLD BUFFER 

	ENDSV.


;Here to release the current output buffer

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NISND2:	CALL RETUNB		;RETURN THE UN BLOCK
NISND1:	SKIPA T3,T1		;WANT THE ERROR STATUS
NIRELB:	SETZ T3,		;DON'T WANT ANY ERROR STATUS
	MOVE T1,RID        	;GET BUFFER ADDRESS 
	CALLRET CBDS1		;GO RELEASE THE BUFFER
	SUBTTL Output Routines - Datagram Sent Callback

;IPCBDS - DATAGRAM SENT 
;
; Uses  the  request  ID in the UN block which is the address of
; the sent buffer and places it on the free buffer list.  
;
; Alternate  entry point CBDS1 is called from NISEND when  NISRV 
; returned an error at the time of the send.
;
; Alternate entry point CDSERR is called from ARPCDS.
;
; T1/ buffer address if called at CBDS1
; T2/ UN block address  
; T3/ 0 if function succesfull or error code 
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

IPCBDS:	MOVE UNB,T2		;SAVE UN BLOCK ADDRESS
	LOAD T1,UNRID,(UNB)	;GET THE BUFFER ADDRESS TO RELEASE
	LOAD SRV,UNUID,(UNB)	;GET USERID
	HRRZS SRV		;BUT USE ONLY TYPE OF SERVICE PORTION
CBDS1:	MOVE T2,T1		;COPY FOR INDEXING
	PIOFF			;STOP THE MACHINE
	IFN IPNDSW,<CALL IPNDEQ> ;UNLINK THIS BUFFER
	EXCH T1,INTNFB		;PUT ON FREE LIST
	STOR T1,NBQUE,(T2)	;HANG OLD LIST OFF OF THIS NEW HEAD
	PION			;GIVE BACK THE MACHINE
	AOS INTFLG		;GET INTERNET GATEWAY TO NOTICE IT
	AOS PSKD1		;MAKE THE SCHEDULER NOTICE THIS IF IN NULL JOB
	SKIPN T1,T3          	;NO, GET THE CHANNEL STATUS
	RETSKP			;NO ERRORS DETECTED  
CDSERR:	AOS NIOCNT		;BUMP THE OUTPUT ERROR COUNT
	BUG.(CHK,IPDWNS,IPNIDV,SOFT,<Datagram was not sent>,<<T1,ERROR>,<SRV,SERVICE>>,<

Cause:	The internet ethernet software passed a buffer to NISRV to be sent and
	and an error was returned.  This usually indicates that the KLNI has 
	changed state and IPNIDV has not yet been notified.  This should be
	a temporary condition.

>)
	MOVEM T1,NIPERR
	RETBAD
	SUBTTL Input Routines - Post Receive Buffer

;NIPOST - POST AN INTERNET INPUT BUFFER 
;
; This  routine gives NISRV a receive buffer. The buffer must be
; resident. Note, this routine assumes that there is room for  4
; bytes of CRC at the end.
;
; T1/ address of input buffer
; UNB/ address of the UN block
;
; Returns + 1 if error returned from NISRV, NIPERR has error code
;	  + 2 on success

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

NIPOST:	SKIPN T1		;ZERO IF NIPBFR COULDN'T GET A BUFFER
	RETBAD <NI.ER1>		;RETURN THE ERROR
IFN IPNDSW,<CALL IPNENQ>	;LINK THIS BUFFER AS QUEUED
	MOVE T3,INTXPB		;GET SIZE OF INTERNET PACKET
	ADDI T3,4		;ADD IN CRC 
	STOR T3,UNBSZ,(UNB)	;SAVE IT AS RECEIVE BUFFER SIZE
	STOR T1,UNRID,(UNB)	;SAVE INPUT BUFFER ADR AS REQUEST ID
	ADDI T1,MAXLDR		;POINT PAST LEADER FOR START OF IP HEADER
	TXO T1,<OWGP. 8,>	;FORM BYTE POINTER TO BUFFER
	STOR T1,UNBFA,(UNB)	;SAVE AS THE BUFFER ADDRESS
	MOVX T1,NU.RCV		;POST RECEIVE BUFFER FUNCTION
	MOVE T2,UNB      	;GET UN BLOCK ADR
	CALL DLLUNI		;NO. CALL NISRV
	 CALLRET POSTER		;NISRV RETURNED ERROR
	AOS NICNTP		;INC # OF BUFFERS POSTED RIGHT NOW
	RETSKP			;SUCCESS

;Here when NISRV returned an error from posting a new receive buffer
;Called from NIPOST or ARPOST.

POSTER:	MOVEM T1,NIPERR		;SAVE THE ERROR
	LOAD T2,UNUID,(UNB)	;GET THE USERID
	HRRZS T2		;KEEP ONLY THE SERVICE TYPE
	SKIPN NIPON		;INTERNET UP ?
	BUG. (CHK,IPPSTE,IPNIDV,SOFT,<Couldn't post a buffer>,<<T1,ERROR>,<T2,SERVICE>>,<

Cause:	The internet ethernet software tried to post a receive buffer to NISRV
	and received an error return.  This usually indicates that the KLNI has 
	changed state and IPNIDV has not yet been notified.  This should be
	a temporary condition.

>)
	CAIN T2,NI.INT		;INTERNET SERVICE POSTING ERROR ?
	IFSKP.
	 IFN IPNDSW,<MOVE T1,RID ;PUT ADDRESS IN ITS PLACE
	 CALL IPNDEQ>		;UNLINK THIS BUFFER 
	 LOAD T2,UNRID,(UNB)	;YES - GET BUFFER ADDRESS BACK
	 CALL NIPQIB		;PUT BUFFER BACK ON FREE QUEUE
	ENDIF.
	RETBAD <>,<MOVE T1,NIPERR> ;PICK UP ERROR CODE BEFORE RETURNING
	SUBTTL Input Routines - Datagram Received Callback

;IPCBDR - DATAGRAM RECEIVED
;
; The  NI  received  a  datagram  with  IP's  protocol type. The
; address is available in UNRID of the UN block.
;
; T2/ UN block address 
; T3/ 0 if function succesfull or error code 
; UNRID/ address of buffer 
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

IPCBDR:	STKVAR <UNBLK,STS>
	SOS NICNTP		;DECREMENT # OF BUFFERS POSTED NOW
	MOVEM T2,UNBLK		;SAVE THE UN BLOCK ADR
	MOVEM T3,STS		;SAVE THE ERROR STATUS
	LOAD T1,UNRID,(T2)	;GET THE ADDRESS OF THE BUFFER
	IFN IPNDSW,<CALL IPNDEQ> ;DEQUEUE THIS BUFFER
	JUMPN T3,CBDRCK		;PROBLEMS ?
	CALL NIPQUE 		;GIVE THE BUFFER TO INTERNET
	CALL NIPBFR		;GET ANOTHER BUFFER
	MOVE UNB,UNBLK		;PICK UP THE UN BLOCK TO USE
	CALL NIPOST		;POST IT
	 RETBAD                 ;GOT AN ERROR 
	RETSKP			;GIVE GOOD RETURN

; Here when an error was detected. If the channel is not shutting 
; down,  bump the  error  count and  re-post the buffer.   If the 
; channel is shutting down, put the buffer on the free queue.
;
; T1/ address of the buffer
; T3/ error status 

CBDRCK:				;HERE ON ERRORS FROM IPCBDR
	AOS NIICNT		;BUMP THE INPUT ERROR COUNTER
	CAIE T3,UNRDL%		;DATAGRAM TOO LONG ?
	 JRST CBDRC2		;NO
	CALL NIICMP		;YES GO SEND AN ICMP ERROR MESSAGE
	MOVE UNB,UNBLK		;GET THE UNBLOCK
	LOAD T1,UNRID,(UNB)	;GET BUFFER ADDRESS AGAIN
	CALL NIPOST		;POST IT
	 RETBAD <>,<MOVE T1,STS> ;GOT AN ERROR BUT USE ORIGINAL ERROR CODE
	RETSKP			;GIVE GOOD RETURN
CBDRC2:				;HERE WHEN ERROR WAS NOT DATAGRAM TOO LONG
	MOVE T2,T1		;PUT ADDRESS WHERE NIPQIB WANTS IT
	CALL NIPQIB		;PUT ON FREE BUFFER QUEUE
	RETSKP			;TAKE GOOD RETURN

	ENDSV.			;END OF IPCBDR STKVAR
	SUBTTL Address Change Callback

;IPCBAC - ADDRESS CHANGE CALLBACK
;
; This  is  an  unsolicated callback which occurs when NISRV has
; been  asked to  change it's  Ethernet address. 
;
; T2/   UN block address
; T3/   0 or NISRV error code
;
; Returns + 1 on error with error code in T1
;	      or when GHT does not agree with NISRV  
;	  + 2 on success

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

IPCBAC:	MOVE NCT,NIPNCT		;GET THE NCT ADDRESS
	MOVE UNB,T2		;USE NISRV'S UN BLOCK
	LOAD T3,UNCAR,(UNB)	;GET HIGH ORDER WORD OF ETHERNET ADR
	LOAD T4,UNCAR,+1(UNB)	;GET LOW ORDER BYTES
	CAMN T4,ETHADR+1  	;MATCH KNOWN LOW ORDER WORD 
	 CAME T3,ETHADR		;YES - MATCH KNOWN HIGH ORDER WORD 
	  IFNSK.		;NO. GHT DID NOT MATCH KLNI ADDRESS
	   SKIPN ARPENA		;IS ARP ENABLED ?
	   IFSKP.
	    DMOVEM T3,ETHADR	;YES - UPDATE OUR ADDRESS INFORMATION
	    SETOM NIPGTF	;RE-INIT THE GHT, OUR ADDRESS IS INVALID
	    RETSKP
	   ENDIF.
	   BUG.(INF,IPETHA,IPNIDV,SOFT,<Ethernet address change, IPNI shutting down>,,<

Cause:	The internet ethernet software has received an address changed 
	callback from NISRV and the ARP protocol is disabled.  The ARP
	protocol is needed to handle this situation.  Internet ethernet
	service has been terminated.

>)
	   SETOM NIPSHT		;FLAG THE SHUTDOWN
	   RETBAD <NI.ER2>		
	  ENDIF.
	RETSKP
	SUBTTL Shutdown and Error Routines

;NIPKIL - SHUTDOWN 
;
; Called from MNETDV to shut down both Internet and ARP 
; communications with NISRV.
;
; NCT/ NCT address 
;
; Returns + 1 always  (T1 IS PRESERVED)

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIPKIL::SAVEAC <SRV,UNB>
	MOVE T1,NTRDY(NCT)	;RECORD IF ANYTHING CHANGED
	IOR T1,NTORDY(NCT)
	SETZM NTTOUT(NCT)	;CLEAR OUTPUT HUNG TIMEOUT
	JUMPE T1,NIPKLD		;NOTHING CHANGED SO EXIT QUIETLY
	SETZM NTRDY(NCT)	;NI OFF
	SETZM NTORDY(NCT)	;OUTPUT OFF
 	AOS NTSTCH(NCT)		;JUST CHANGED STATE
	AOS JB0FLG		;NOTE THE NETWORK CHANGE
	CALL NIOFF		;SHUT DOWN THE INTERNET PROTOCOL
	SETZM NIPON		;INTERNET NOT ON ANYMORE
	CALL RUNBLK		;RELEASE THE UN BLOCKS
	SETZM NIPSHT		;CLEAR NEED TO SHUTDOWN FLAG
	SKIPN ARPON		;ARP ON ?
	RET			;NO
	CALL ARPKL1		;YES - SHUT IT OFF TOO
	 JFCL			;IGNORE THE ERROR
NIPKLD:	RET

;Here to shut off Internet communications over the NI

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIOFF:	MOVE T1,NIPON		;GET "ON" FLAGS
	CAIGE T1,NI.ON		;PORTAL OPEN OR BETTER ?
	RET
	CALL INTUNB		;SET UP UN POINTER
	 JRST NIOFF1		;IF NO UN BLOCK, DON'T TRY THE CLOSE
	MOVX T1,NU.CLO		;NI CLOSE FUNCTION
	MOVE T2,UNB    		;GET UN BLOCK ADDRESS
   	CALL DLLUNI		;DO THE CLOSE
	 JFCL       		;ERROR
	CALL RETUNB		;RETURN THE UN BLOCK
NIOFF1:	RET

;Set the error flags, turn off ready

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

NIPHNG:	SETOM NTERRF(NCT)	;YES, FLAG AN ERROR
	SETZM NTRDY(NCT)	;MAKE THE NETWORK NOT READY
	MOVE T1,TODCLK		;GET TIME NOW
	ADDI T1,^D60*^D1000	;TIMEOUT IN ONE MINUTE
	MOVEM T1,NTTOUT(NCT)	;SET INTERFACE HUNG TIMEOUT
	RET
	SUBTTL Internet Fork Background Service

;NIPSRV - GENERAL BACKGROUND SERVICE 
;
; Called   from  the  Internet  fork  to  service  miscellaneous
; requests.
;
; Returns + 1 always

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIPSRV::SAVEAC <NCT,UNB,RID> 	;SAVE THE NCT AC
	SKIPE NCT,NIPNCT	;GET OUR NCT
	SKIPN NIPON		;IPNI UP YET ?
	RET			;HASN'T INITIALIZED YET
	SKIPE NIPGTF		;SHOULD GHT BE INVALIDATED ?
	CALL NIHINV		;YES
	SKIPE NIPSHT		;SHOULD WE SHUT DOWN THE KLNI ?
	CALL NIPKIL		;YES - SO TURN EVERYTHING OFF
	SKIPN NIPRSF		;NEED TO RESTART IPNI?
	IFSKP.
	 CALL NIPRST		;YES - SO RESET IPNI NOW
	 SETZM NIPRSF		;AND RESET THE FLAG
	ENDIF.
	CALL INTUNB		;GET A UNB BLOCK 
	 RET			;COULDN'T
	CALL NIPPIB		;SEE IF ANY INPUT BUFFERS WATNED
	 JFCL			;IGNORE THE ERROR, BUGINFS HAVE BEEN ISSUED
	CALL RETUNB		;RETURN THE UN BLOCK
	SKIPE NTLOBO(NCT)	;ANY ARP MESSAGES TO PROCESS
	CALL ARPPRC		;YES
	SKIPE NIPSRQ		;ANY REQUESTS FOR READ PORTAL COUNTERS ?
	CALL NIPRPC		;YES
	SKIPE ARPSRQ		;ANY REQUEST FOR ARP COUNTERS ?
	CALL ARPRPC		;YES
	RET
 	SUBTTL Miscellaneous Subroutines

;NIVLDA - VALIDATE THE ETHERNET ADDRESS
;
; Called  by  NISEND to check the Ethernet address in the ght to
; see if it has been validated by ARP (if ARP is being used)  or
; to see if the remote host does ARP.
;
; T2/ GHT area 2 addres of the entry 
;
; Returns + 1 if address not valid, ARP message sent
;	  + 2 if address is valid, use it

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIVLDA:	MOVE T1,GH.GCF(T2)	;GET THE GATEWAY CONTROL FLAGS
	TXNE T1,GH%ARP!GH%DMB	;VALIDATED BY ARP OR HOST DOESN'T DO ARP
	RETSKP			;YES
	CALL ARPSND		;FORCE ARP TO VALIDATE IT
	 JFCL			;IGNORE THE ERROR
	RETBAD



;NIUNKA - UNKNOWN INTERNET ADDRESS
;
; Called  from  NISEND  when  we  found  that we didn't have the
; routing address in our GHT.
;
; RID/ address of the buffer
;
; Returns via NIRELB routine

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIUNKA:	SKIPN ARPON 		;IS ARP ON ?
	JRST NSND2A		;NO - BYPASS THE ARP CODE
	CALL ARPSND		;YES - GENERATE AN ARP PACKET
	 JFCL			;IGNORE THE ERROR
NSND2A:	MOVE T2,NI.HOP(RID)	;GET THE ROUTING ADDRESS
	XMOVEI T1,-LCLPKT(RID)	;POINT TO RIGHT LOCATION TO PICK UP PIDH
	LOAD T3,PIDH,(T1)	;GET THE DESTINATION HOST #
	SKIPN ARPON		;ARP BEING USED ?
	 CAMN T3,T2		;DOES IT MATCH ROUTING ADDRESS
	  SKIPA
	   BUG.(INF,IPRANF,IPNIDV,SOFT,<Routing address not found>,<<T2,RTE>,<T3,DEST>>,<

Cause:	The internet ethernet software has been asked to forward a message
	to an internet host whose ethernet address translation is not known.
	This situation is normally handled by the ARP protocol which is not
	enabled if this BUGINF occurs.

>)
	CALLRET NIRELB		;RELEASE THE BUFFER

;NIPQUE - QUEUE UP THE RECEIVE BUFFER FOR INTERNET FORK
;
; Called from the datagram received callback or from the local 
; loopback routine to queue up a buffer for input to Internet.
;
; T1/ Address of the buffer
;
; Returns + 1 always

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

NIPQUE:	SETZRO NBQUE,(T1)	;MAKE SURE POINTER FOR THIS BUFFER IS CLEAR
	PIOFF			;DON'T ALLOW US TO BE INTERRUPTED
	MOVE T3,INTIBI		;QUEUE FOR INTERNET GATEWAY
	JUMPN T3,CBDRQ1
	MOVEM T1,INTIBO		;ONLY THIS ITEM
	SKIPA
CBDRQ1:	STOR T1,NBQUE,(T3)
	MOVEM T1,INTIBI		;NEW POINTER
	AOS INTFLG		;CAUSE INTERNET TO NOTICE IT.
	AOS PSKD1		;MAKE THE SCHEDULER NOTICE THIS IF IN NULL JOB
	PION
	RET


;NIICMP - SEND ICMP FRAGMENTATION MESSAGE
;
; Called  from IPCBDR when a datagram has been received which is
; is too long for  our  input  buffers.  This  routine  (in  the
; future)  needs  to  queue up a request to the Internet fork to
; send a parameter problem/fragmentation needed ICMP message.  
;
;	SAVEAC <PKT>		;SAVE PKT
;	XMOVEI PKT,-LCLPKT(T1)	;PUT WHERE ICMERR WANTS BUFFER ADDRESSES
;	MOVX T1,<DU%FRG,,ICM%PP> ;FRAGMENTATION NEEDED, PARAMETER PROBLEM
;	CALL ICMERR		;GENERATE ICMP ERROR
;
; T1/ address of the input buffer 
; Returns + 1 always

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

NIICMP:	RET			;JUST A STUB FOR NOW
	SUBTTL Buffer Management Routines

;NIPGIB - GET INPUT BUFFERS.
;
; Called  from the Internet fork to get a bunch of input buffers
; to be used for incoming IP packets over the Ethernet.
;
; Returns + 1 always

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIPGIB:	MOVE T1,NIPNFI		;NUMBER OF FREE INPUT BUFFERS
NIPGB1: CAML T1,NIPNIB		;BELOW DESIRED LEVEL?
	RET			;NO - DO NOTHING
	CALL GETNIB		;GET A BUFFER
	JUMPE T1,NIPGB3   	;ZERO ADDRESS, NONE AVAILABLE
	SETZRO PKTFLG,(T1)	;CLEAR ALL INTERNAL CONTROL FLAGS
	SETONE PFSIZ,(T1)	;INDICATE IT'S A FULL SIZE PACKET
	XMOVEI T2,LCLPKT(T1)	;GET POINTER TO LOCAL HEADERS
	MOVE T3,MAXWPM		;MAX WORDS
	STOR T3,NBBSZ,(T2)	;SAVE AS BUFFER SIZE
	SETZRO NBQUE,(T2)
        CALL INTLKB		;MAKE SURE BUFFER IS RESIDENT
	CALL NIPQIB		;GO QUEUE THE INPUT BUFFER
	JRST NIPGB1		;GO TRY FOR MORE

;Here to queue up an input buffer

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

NIPQIB:	MOVE T1,T2		;COPY FOR QUEUEING
 	PIOFF
	EXCH T2,NIPFRI		;ADD TO LIST OF FREE INPUT BUFFERS
	STOR T2,NBQUE,(T1)	;OLD LIST IS SUCCESSOR OF THIS BUF
	AOS T1,NIPNFI		;BUMP THE COUNT TO MATCH
	PION
	RET

;Here when no buffers available
NIPGB3:	MOVE T1,NIPNFI		;GET NUMBER OF BUFFERS AVAILABLE
	CAIGE T1,NNIPTH		;BELOW THE THRESHOLD LEVEL ?
	BUG.(CHK,IPNBFA,IPNIDV,SOFT,<No IPNI input buffers available.>,<<T1,BFRCNT>>,<

Cause:	The internet ethernet software has attemted to assign an input 
	buffer and internet free space is exhausted.

>)
	RET

;NIPPIB - POST A BUNCH OF INPUT BUFFERS
;
; Called  in  make  sure  we have enough input buffers posted to
; NISRV.
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIPPIB:	CALL NIPGIB		;MAKE SURE WE HAVE ENOUGH BUFFERS
PIB1:	MOVE T1,NIPNIB		;GET # OF BUFFERS WE SHOULD HAVE
	LSH T1,-1		;MAKE # OF BUFFERS THAT WE WANT TO BE POSTED
	CAMG T1,NICNTP		;REACHED THAT LEVEL ?
	RETSKP			;YES
	CALL NIPBFR		;GET A RECEIVE BUFFER READY
	CALL NIPOST		;GO POST THE RECIEVE BUFFER
	 RETBAD
	JRST PIB1		;TRY TO GET MORE


;NIPBFR - GET AN INPUT BUFFER
;
; Returns + 1 always with T1 containing the buffer address

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

NIPBFR:	PIOFF
	SOSL T1,NIPNFI		;COUNT DOWN NUMBER OF FREE INTERNET BUFS
	 SKIPN T2,NIPFRI	;GET POINTER TO BUFFER TO USE
	 IFNSK.
	  AOS NIPNFI		;DON'T HAVE BUFFERS. DON'T LET IT GO NEGATIVE
	  PION
	  MOVE T2,NIPFRI	;MAKE SURE WE GET POINTER 
	  AOS T3,IPBLPC		;COUNT OCCURANCES OF IPIBLP'S
	  IDIVI T3,4		;ONLY BUGINF EVERY MULTIPLE OF 4 TIMES
	  SKIPN T4		;BUGINF TIME ?
	  BUG.(CHK,IPIBLP,IPNIDV,SOFT,<IPNI input buffer list problem>,<<T1,CNT>,<T2,BFR>,<T3,BCNT>>,<

Cause:	The internet ethernet software has attempted to queue an input 
	buffer and none were available.  This indicates that the
	internet asynchronous fork is not making buffers available fast enough.

>)
	  SETZ T1,		;FLAG TO NIPOST THAT WE HAVE NO BUFFER
	  AOS INTFLG		;TRY TO GET INTERNET FORK TO RUN AGAIN
	  AOS PSKD1		;MAKE THE SCHEDULER NOTICE THIS IF IN NULL JOB
	  RET			;TRY TO RECOVER
	 ENDIF.
	LOAD T1,NBQUE,(T2)	;NEXT INTERNET FREE BUFFER
        SETSEC T1,INTSEC	;YES SO SET THE SECTION NUMBER
	SETZRO NBQUE,(T2)	;CLEAR LIST POINTER
	MOVEM T1,NIPFRI		;BECOMES HEAD OF LIST
	PION
	MOVE T1,T2		;PUT THE ADDRESS WHERE IT'S EXPECTED
	RET
	SUBTTL UN Block Management Routines

;GUNBLK - GET UN BLOCKS
;
; Called to get a buffer which will contain a set number of
; UN blocks.
;
; T1/ portal id
;
; Returns + 1 on error
;	  + 2 on success   T1/ beginning address of the buffer
;		           T2/ number of UN blocks available

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

GUNBLK:	STKVAR <ULOC,CNTDWN,PID>
	MOVEM T1,PID		;SAVE THE PORTAL ID
	MOVEI T1,UN.TNB*<UN.LEN+MS.LEN+1> ;SIZE FOR "n" UN BLOCKS
	CALL GETBLK		;GET THE SPACE NEEDED
	SKIPE T1		;DID WE GET ONE ?
	IFSKP.
	 BUG. (CHK,IPNUNS,IPNIDV,SOFT,<No space for UN blocks>,,<

Cause:	The monitor attempted to assign some internet free space for
	UN blocks and none was available.

>)
	 RET
	ENDIF.
	MOVEM T1,IUNBLK		;SAVE THE POINTER TO THIS BLOCK
	MOVEM T1,ULOC		;SAVE THE POINTER TO THE FIRST BLOCK
	MOVEI T2,UN.TNB		;GET NUMBER OF UN BLOCKS
	MOVEM T2,CNTDWN 	;SAVE IT AWAY
GUNGB1:	MOVE T2,UNBNFI		;GET NUMBER OF FREE UN BLOCKS
	CAML T2,CNTDWN		;GOT ENOUGH YET ?
	RETSKP			;YES
	MOVE T1,ULOC		;GET POINTER TO ADR OF UN BLOCK
	PIOFF
	MOVE T2,T1		;COPY THE POINTER
	EXCH T2,UNBFRI		;ADD TO LIST OF FREE UN BLOCKS
	MOVEM T2,(T1)		;OLD LIST IS SUCCESSOR OF THIS BUF
	AOS UNBNFI		;BUMP THE COUNT TO MATCH
	PION
	XMOVEI UNB,1(T1)	;GET ADDRESS OF UN BLOCK
	MOVEI SRV,NI.INT	;TYPE OF SERVICE IS INTERNET
	MOVEI T1,IPROTO		;INTERNET ETHERNET PROTOCOL TYPE
	MOVE T2,PID		;GET THE PORTAL ID
	CALL UNSET		;SET UP THE UN BLOCK
	CALL MSDSET		;SET UP THE MSD PORTION OF THE UN BLOCKS
	MOVEI T1,UN.LEN+MS.LEN+1 ;OFFSET TO NEXT POINTER
	ADDM T1,ULOC		;ADD TO CURRENT POINTER
	JRST GUNGB1		;DO IT ALL AGAIN

	ENDSV.			;END OF GUNBLK STKVAR

;RUNBLK - RELEASE UN BLOCKS
;
; Called when killing IPNI, this code releases the space used 
; for UN blocks.
;
; Returns + 1 always

RUNBLK:	SETZM UNBNFI		;CLEAR UN BLOCK COUNTER
	SETZM UNBFRI		;CLEAR UN BLOCK LIST
	MOVE T1,IUNBLK		;GET THE POINTER TO THE LARGE BLOCK
	CALL RETBLK		;RELEASE THE BLOCK
	RET


;UNSET - SET UP UN BLOCK
;
; Sets up the static parameters for the UN block.
;
; T1/ protocol type
; T2/ portal id
; SRV/ type of service
; UNB/ address of the UN block
;
; Returns + 1 always

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

UNSET:	SASUBR <PROTO,PID>	;SAVE PROTOCOL TYPE AND PORTAL ID
	MOVE T1,UNB		;GET OUR UN BLOCK AREA
	MOVEI T2,UN.LEN  	;ZERO OUT THE FULL BLOCK
	CALL CLRBLK		;ZERO THE BLOCK
	XMOVEI T2,NICBAK	;SET THE CALL BACK ROUTINE
	STOR T2,UNCBA,(UNB)	;SAVE IT
	MOVX T2,<SIXBIT/NIP/> 	;GET OUR HANDLE
	HRR T2,SRV		;ADD TYPE OF SERVICE TO USERID
	STOR T2,UNUID,(UNB)	;SAVE IT
	SETZRO UNCHN,(UNB)	;NI UNIT 0
   	SETZRO UNPMS,(UNB)	;NO PI LEVEL MASK NEEDED
	SETZRO UNPTR,(UNB)	;UNDAD WILL ALWAYS BE THE ACTUAL ADRESS
	MOVE T1,PID		;GET PORTAL ID BACK
	STOR T1,UNPID,(UNB)	;SAVE PORTAL ID 
 	MOVE T2,PROTO 		;GET THE ETHERNET PROTOCOL TYPE
	STOR T2,UNPRO,(UNB)	;SAVE IT 
	MOVEI T1,UNA.EV		;BUFFERS ARE EXEC VIRTUAL ADDRESSES 
	STOR T1,UNADS,(UNB)	;SAVE IT FOR NISRV
	RET
	ENDSV.			;END OF UNSET STKVAR

;MSDSET - SET UP MSD PORTIONS OF THE UN BLOCK
;
; Called here from GUNBLK to set up the MSD's that are built
; into the UN block. 
;
; The MSD's are used only when the length of the TCP/IP packet
; is less than the minimum Ethernet packet size. The 1st MSD
; points the actual TCP/IP packet and the second points to the
; padding bytes to extend the packet to the minimum size.
;
; UNB/ address of the UN block
;
; Returns + 1 always

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

MSDSET:	XMOVEI T1,MSD1(UNB)	;POINTER TO THE 1ST MSD
	XMOVEI T2,MSD2(UNB)	;POINTER TO THE 2ND MSD
	STOR T2,MDNXT,(T1)	;LINK 2ND MSD POINT TO 1ST MSD
	SETZRO MDNXT,(T2)	;END OF MSD CHAIN IS THE 2ND MSD
	MOVX T3,<POINT 8,0>	;MAKE POINTER TO BE USED WITH MDALA
	STOR T3,MDAUX,(T1)	;SET UP IN THE 1ST MSD
	STOR T3,MDAUX,(T2)	;SET UP IN THE 2ND MSD
	XMOVEI T3,PDBYTS	;POINTER TO THE PADDING BYTES
	STOR T3,MDALA,(T2)	;SET UP IN 2ND MSD
	MOVX T3,VMC.XC		;ADDRESSES ARE EXEC VIRTUAL
	STOR T3,MDVMC,(T1)	;SET UP IN 1ST MSD
	STOR T3,MDVMC,(T2)	;SET UP IN 2ND MSD
	RET

;INTUNB - GET AN INTERNET UN BLOCK POINTER
;
; Called  wherever  we need to retrieve a pointer to an Internet
; UN block.
;
; Returns + 1 on error
;	  + 2 on success UNB/ adress of UN block or 0 if not set

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

INTUNB:	PIOFF		
	SOSL UNBNFI		;COUNT DOWN NUMBER OF FREE INTERNET BUFS
	 SKIPN UNB,UNBFRI	;GET POINTER TO BUFFER TO USE
	 IFNSK.
	  AOS UNBNFI		;NO BUFFERS AVAILABLE. DON'T LET COUNT GO NEG.
	  PION			;MAKE SURE INTERRUPTS ARE BACK ON
	  SKIPE NIPON		;IF NOT ON, DON'T BUGINF
	  BUG.(CHK,IPUNBP,IPNIDV,SOFT,<Free UN block queue problem>,,<

Cause:	  The monitor attempted to assign a UN block and none were available.

>)
	  RETBAD <NI.ER5>
	 ENDIF.
	MOVE T1,(UNB)		;NEXT UN BLOCK
	SETZM (UNB)		;CLEAR LIST POINTER
	MOVEM T1,UNBFRI		;BECOMES HEAD OF LIST
	PION			;MAKE SURE INTERRUPTS ARE BACK ON
	AOS UNB			;MAKE IT POINT TO REAL UN BLOCK START ADR
	RETSKP


;RETUNB - RETURN UN BLOCK TO FREE QUEUE
;
; Called whenever we are done with the current UN block. This
; routine puts it back on the free queue list.
;
; UNB/ UN block address
;
; Returns + 1 always

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

RETUNB:	SAVEAC <T1>
	PIOFF
	SOS T1,UNB 		;COPY AND POINT AT QUEUE INFO OF UN BLOCK
	EXCH T1,UNBFRI		;ADD TO LIST OF FREE INPUT BUFFERS
	MOVEM T1,(UNB)		;OLD LIST IS SUCCESSOR OF THIS BUF
	AOS UNBNFI		;BUMP THE COUNT TO MATCH
	PION
	RET
	SUBTTL Gateway Host Table Routines

;NIHINI - GHT table initialization. 
;
; NIHINI  is  called  at  system startup, or by the IPOPR% jsys.
; This will read the Internet-Ethernet host  number  translation
; table  file  and  set  up  2 areas which will be pointed at by
; GHTAR1 and GHTAR2.
;
; Area  1  will  contain  in sequential order, the Internet host
; numbers. It is used by the INTSRC routine for determining  the
; offset for that host into area 2 of the ght.
;
; Area  2  contains the per host data such as Ethernet addresses
; and gateway control flags.
;
; Returns + 1 on error, error code in T1
; 	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIHINI::TRVAR <TMPLEN,LSTNUM,INTJFN,GHTPT1,GHTPT2,GHTCT1,INTCKS,<INTBLK,NIHMDL>>
	SAVEAC <P1,P2,P3>
	CALL NIHSPC		;GET AND SET UP NEW GHT SPACE
	 RETBAD	<>,<MOVEM T1,NIPERR> ;NO SPACE ERROR
	CALL NIHOPN		;OPEN THE FILE AND READ HEADER
	 RETBAD	<>,<CALL NIHERR> ;GOT AN ERROR. CODE IN T1
	MOVE T1,GHTCT1		;GET NUMBER OF ENTRIES IN THE FILE
	CAMG T1,NIMAXH          ;DON'T LET THEM HAVE TOO MANY HOSTS
	IFSKP.
	 MOVEI T1,IPHEMX	;EXCEEDED MAX. SET THE ERROR CODE
	 CALL NIHERR		;HANDLE THE ERROR
	 RETBAD			;TAKE ERROR RETURN
	ENDIF.
	SETZ P3,		;INIT CHECKSUM
	SETOM LSTNUM		;INIT LAST HOST NUMBER SEEN
	CALL NICHK1		;READ THE FILE AND BUILD GHT
	 RETBAD <>,<CALL NIHERR> ;GOT AN ERROR
        CAMN P3,INTCKS		;COMPUTED CHECKSUM MATCH THE FILES ?
	IFSKP.
	 MOVEI T1,IPHCHK	;NO. SET THE ERROR CODE
	 CALL NIHERR		;HANDLE THE ERROR
	 RETBAD			;TAKE ERROR RETURN
	ENDIF.
	CALL NIHFIN		;UPDATE GHTAR1 AND 2, CLOSE THE FILE
	RETSKP			;GIVE GOOD RETURN

;NICHK1 - READ, CHECK, AND BUILD GHT
;
; Called from NIHINI to read the GHT file, build, and verify the
; GHT.  NOTE:  The Internet host # must be offset 0 in the data.
;
; P1/ area 1 pointer into ght
; P2/ area 2 pointer into ght
;
; Returns + 1 on error
; 	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NICHK1:	MOVE T1,INTJFN		;PICK UP THE JFN
	MOVE T2,[POINT 36,INTBLK] ;PUT DATA INTO TEMP AREA
	MOVEI T3,NIHMDL		;READ HOST MAX DATA LENGTH WORDS
	SIN			;READ A WORD FROM THE FILE
	 ERJMP NICHK3		;SHOULDN'T HAVE EOF YET. ERROR.
	XMOVEI T1,INTBLK	;GET GLOBAL ADDRESS OF TEMP AREA
	IOR T1,[EP. 0(T2)]	;MAKE INDIRECT WORD
	SETZ T2, 		;STARTING INDEX
NICHK2:	ADD P3,@T1		;COMPUTE A SIMPLE CHECKSUM
	CAIGE T2,NIHMDL-1	;END?
	AOJA T2,NICHK2		;NO, STEP COUNT AND LOOP
	MOVE T1,INTBLK		;GET THE INTERNET NUMBER
	CAMG T1,LSTNUM		;GREATER THAN LAST HOST NUMBER ?
	RETBAD <IPHSEQ>        	;SEQUENCE ERROR
	MOVEM T1,LSTNUM		;UPDATE THE LAST NUMBER
	MOVE T2,NIPNCT		;GET OUR NCT ADDRESS
	CAME T1,NTLADR(T2)	;IS THIS OUR ADDRESS ?
	IFSKP.
	 SOS GHTCT1		;YES - DON'T COUNT THIS ENTRY THEN
	 JRST NICHK4		;DON'T UPDATE GHT
	ENDIF.
	MOVEM T1,(P1)		;SAVE INTERNET NUMBER IN AREA 1
	AOS P1			;MAKE IT POINT TO NEXT ENTRY
	XMOVEI T2,INTBLK	;POINT AT TEMP AREA AGAIN
	ADDI T2,.NIINT+1	;GET PAST THE INTERNET NUMBER
	MOVEI T1,GH2MDL  	;LENGTH OF AREA 2 ENTRIES
	MOVE T3,P2		;POINT AT THE DATA AREA OF THE GHT (AREA 2)
	CALL XBLTA		;XFER IT
	ADDI P2,GH2MDL  	;BUMP INDEX INTO AREA 2
NICHK4:	MOVNI T2,NIHMDL		;GET NEGATIVE LENGTH OF THE ENTRY
	ADDB T2,TMPLEN		;SUBTRACT FROM WORDS LEFT
	JUMPL T2,[RETBAD <IPHCNT>] ;ARG COUNT IS WRONG IF NEGATIVE
	JUMPG T2,NICHK1		;LOOP UNTIL DONE
	RETSKP

;Here when premature end of file

NICHK3:	SKIPE GHTCT1		;DO WE HAVE ANY ENTRIES IN THE FILE?
	RETBAD <IPHCNT>		;YES - RETURN THE ERROR
	RETSKP			;NO - ALL IS WELL, EOF IS NOT PREMATURE

;NIHOPN - OPEN GHT FILE
;
; Called  from  NIHINI  this  code opens the GHT file and starts
; reading the header information.
;
; Returns + 1 on error, error code in T1
;	  + 2 on success, P3/ updated checksum

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIHOPN:	STKVAR <<HDRS,NIHMHL>>
	MOVX T1,GJ%SHT!GJ%OLD	;FILE MUST EXIST.
	HRROI T2,[ASCIZ/SYSTEM:INTERNET-ETHERNET-MAPPINGS.BIN/] 
	GTJFN%			;LOOK FOR THE FILE
	 ERJMP R		;ERROR 
	MOVEM T1,INTJFN		;SAVE THE JFN
	MOVX T2,^D36B5!OF%RD	;36 BIT READ ACCESS 
	OPENF%			;OPEN UP THE JFN
	 ERJMP R		;ERROR 
	MOVEM T1,INTJFN		;SAVE THE JFN
	MOVEI T2,HDRS		;POINT TO TEMP HEADER STORAGE
	IOR T2,[POINT 36,]	;FORM BYTE POINTER TO HEADERS
	MOVEI T3,NIHMHL 	;READ THE WHOLE HEADER
        SIN
	 ERJMP R		;ERROR 
	XMOVEI T1,HDRS		;POINT AT TEMP HEADER AREA AGAIN
	MOVE T2,.NICHK(T1)	;GET THE FILE CHECKSUM
        MOVEM T2,INTCKS 	;AND SAVE IT AWAY
	MOVE T2,.NILEN(T1)	;GET NUMBER OF WORDS LEFT
        MOVEM T2,GHTLEN 	;SAVE THE COUNT
	MOVEM T2,TMPLEN
	IDIVI T2,NIHMDL		;MAKE SURE COUNT IS MULTIPLE OF PER HOST LENGTH
	JUMPN T3,[RETBAD <IPHCNT>] ;IF REMAINDER, THEN COUNT IS BAD
	MOVEM T2,GHTCT1		;SAVE # OF ENTRIES
        RETSKP

	ENDSV.			;END OF NIHOPN STKVAR

;NIHSPC - GET AND SET UP NEW GHT SPACE
;
; Called from NIHINI to get Internet free space for a new ght.
; 
; Returns + 1 on error, error code in T1
; 	  + 2 on success, address of block in T1

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIHSPC:	STKVAR <GHSIZ>
	MOVE T1,NIMAXH		;GET MAX HOSTS IN GHT
	IMULI T1,NIHMDL+1	;COMPUTE SPACE FOR AREA 2
	ADD T1,NIMAXH		;NOW ADD IN SPACE FOR AREA 1
	MOVEM T1,GHSIZ		;SAVE THE SIZE
	CALL GETBLK		;GET A BLOCK IP FREE SPACE
	JUMPE T1,[RETBAD <IPHNSP>] ;RETURN NO SPACE ERROR TO CALLER
	MOVE T2,GHSIZ		;GET BUFFER SIZE
	CALL NIPLKB		;LOCK THE GHT
	MOVEM T1,GHTPT1		;SAVE THE POINTER TO THE NEW GHT
	MOVE P1,T1    		;COPY AREA 1 POINTER
	MOVE P2,T1		;GET ADR OF AREA 1
	ADD P2,NIMAXH		;CALCULATE ADR OF AREA 2
	MOVEM P2,GHTPT2		;SAVE AS TEMPORARY POINTER TO AREA 2
	CALL CLRBLK		;CLEAR OUT THE BLOCK (USES T1 AND T2)
	RETSKP

	ENDSV.			;END OF NIHSPC STKVAR


;NIHREL - RELEASE OLD GHT STORAGE
;
; Called from NIHINI to release any storage used by an old ght.
;
; T1/ Address of the block
;
; Returns + 1 always

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIHREL:	MOVE T2,NIMAXH		;GET MAX HOSTS IN GHT
	IMULI T2,NIHMDL+1	;COMPUTE SPACE FOR AREA 2
	ADD T2,NIMAXH		;NOW ADD IN SPACE FOR AREA 1
	CALL NIPULK		;UNLOCK THE SPACE
	CALL RETBLK		;RELEASE IT
	RET

;NIHFIN - FINISH UP GHT PROCESSING
;
; Called from NIHINI and NIHERR to update the GHTAR1 and GHTAR2
; locations and to close the file.
;
; GHTPT1/ new pointer to area 1 of the ght
; GHTPT2/ new pointer to area 2 of the ght
; GHTCT1/ number of entries in the ght
; INTJFN/ jfn of the ght file
;
; Returns + 1 always

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

;**;[7450] Replace 6 lines with 16 lines at NIHFIN    JMP   Apr 9 87

NIHFIN:	NOSKED			;[7450] MAKE SURE NO ONE INTERFERES
	SKIPE GHTLOK		;[7450] IS GHT STABLE ?
	IFSKP.			;[7450] 
	 MOVE T1,GHTPT2		;[7450] YES - GET TEMPORARY POINTER
	 MOVEM T1,GHTAR2	;[7450] EQUALS NEW POINTER TO AREA 2
	 MOVE T1,GHTCT1		;[7450] GET COUNT BACK
	 MOVEM T1,GHTCNT	;[7450] SAVE IT AS THE REAL COUNT
	 MOVE T1,GHTPT1		;[7450] GET THE NEW AREA
	 EXCH T1,GHTAR1		;[7450] AND EXCHANGE WITH THE OLD ONE
	ELSE.			;[7450]
	 OKSKED			;[7450] NO - GHT IS BEING UPDATED
	 MOVEI T1,1		;[7450] WAIT A SECOND
	 DISMS			;[7450] 
	 JRST NIHFIN		;[7450] TRY AGAIN
	ENDIF.			;[7450]
	OKSKED			;[7450] ALL IS SAFE AGAIN
	SKIPE T1		;IS THE OLD POINTER ZERO ?
	CALL NIHREL		;NO. RELEASE THE OLD TABLE SPACE
	SKIPE T1,INTJFN		;GET OUR JFN AGAIN
	 CLOSF			;CLOSE THE FILE IF WE HAD A JFN
	  ERJMP .+1		;WHO CARES IF ERROR HERE
	SKIPN NIPON		;IS IPNI CODE INIT'D YET
	IFSKP.
	 MOVE NCT,NIPNCT	;GET OUR NCT 
	 CALL INTUNB		;GET THE INTERNET UN BLOCK
	  RETBAD
	 CALL RETUNB		;RETURN THE UN BLOCK
	ENDIF.
	RET

;NIHERR - ERROR IN PROCESSING THE GHT FILE
;
; Called here from any number of places while processing the GHT
; file. Since IPNIDV requires a GHT, this routine will leave the
; existing GHT in place, or if no GHT has been assigned, it will
; use the space that we've just gotten for the GHT.
;
; T1/ error code
;
; Returns + 1 always with error code in T1

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIHERR:	MOVEM T1,NIPERR		;SAVE THE ERROR CODE
	SETZM GHTCT1		;TEMPORARY COUNT IS NO GOOD  
	SKIPN T1,GHTAR1		;HAVE CURRENT GHT POINTER ?
	IFSKP.
	 MOVE T1,GHTPT1		;YES - KEEP REAL GHT, RELEASE THE NEW ONE
	 CALL NIHREL		;RELEASE THE SPACE
	ELSE.
	 CALL NIHFIN		;NO GHT, CLOSE FILE AND UPDATE GHTxxx
	ENDIF.
	MOVE T1,NIPERR		;GET THE ERROR CODE BACK
	RET

	ENDTV.			;END OF NIHINI TRVAR

;NIHINV - INVALIDATE ALL GHT ENTRIES
;
; Called  by  the NIPSRV whenever an address change callback has
; occured which changes our ethernet address  to  something  new
; and  arp  is turned on. This routine turns off the GH%ARP flag
; in the flags word of each ght area 2 entry.
;
; Returns + 1 always

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

NIHINV:	MOVX T3,GH%ARP		;GOING TO TURN OFF THIS FLAG
	PIOFF			;NO INTERRUPTIONS
	MOVE T1,GHTCNT		;GET NUMBER OF ENTRIES
	MOVE T2,GHTAR2		;GET POINTER TO AREA 2
	ADDI T2,GH.GCF		;POINT AT EACH ENTRIES FLAG WORD
NINV1:	ANDCAM T3,(T2)		;TURN OFF THIS ENTRY'S FLAG
	ADDI T2,GH2MDL		;POINT TO THE NEXT
	SOJG T1,NINV1		;DECREMENT ENTRY COUNTER AND TRY NEXT IF MORE
NINV2:	PION			;ALLOW THE REST OF THE MACHINE
	SETZM NIPGTF		;CLEAR FLAG THAT GOT US HERE
	CALL WERHER		;TELL KNOWN HOSTS OUR NEW ADDRESS
	RET
	SUBTTL Internet to Ethernet Address Translation

;INTSRC - INTERNET HOST NUMBER SEARCH
;
; Search  for  the  entry in the gateway host table that matches
; the Internet host number in T2.
;
; T2/ Internet host # to search for
;
; Returns + 1 if not found, T1/ area 1 adr where entry could be inserted
;			    T2/ area 2 adr where entry could be inserted
;	  + 2 on success, T1/ area 1 address of entry that matched
;			  T2/ area 2 address of entry that matched

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

INTSRC:	SAVEAC <P1,P2,P3>	;SAVE LOW, MIDDLE, AND HIGH
	SETZB P1,P2		;INIT LOW (AND MIDDLE) TO ZERO
	MOVE T1,GHTAR1		;GET POINTER TO AREA1
	SKIPN P3,GHTCNT		;GET TABLE LENGTH IF ANY, AND MAKE IT HIGH
	CALLRET ISNFND		;NO ENTRIES,  NOT FOUND THEN
	CAIGE P3,SRCMAX		;USE SEQUENTIAL OR BINARY SEARCH
	CALLRET SEQSRC		;SEQUENTIAL
;**;[7450] Insert 1 line at INTSRC+6L     JMP  Apr 8 87
	SOS P3			;[7450] MAKE IT OFFSET TO LAST ENTRY
ISRCH:	MOVE P2,P3		;BUILD MIDDLE BY TAKING THE HIGH
	SUB P2,P1        	;SUBTRACT THE LOW 
	LSH P2,-1		;HALVING IT
	ADD P2,P1		;AND ADDING THE LOW
	MOVE T1,GHTAR1		;GET GHT ADR
	ADD T1,P2		;POINT TO GHT(MIDDLE)
	CAMN T2,(T1)        	;DOES MIDDLE ENTRY MATCH THE HOST #
	CALLRET ISFND		;FOUND IT
	CAMG T2,(T1)		;HOST # .GT. MIDDLE ?
	IFSKP.
	 MOVEI P1,1(P2)		;YES. LOW = MIDDLE + 1
;**;[7450] Insert 2 lines at ISRCH+10.L   JMP  Apr 8 87
	 AOS T1 		;[7450] ADJUST TO CORRECT INSERTION POINT
	 AOS P2			;[7450]  IN CASE LAST EXAMINED IS LT HOST
	 JRST ISCHK		;CHECK FOR ALL ENTRIES HAVING BEEN SEARCHED
	ENDIF.
	JUMPE P2,ISNFND		;IF MIDDLE IS ZERO, DONE - NOT FOUND
	MOVEI P3,-1(P2)		;NO. HIGH = MIDDLE - 1
ISCHK:	CAML P3,P1    		;HIGH AND LOW MEET YET ?
	JRST ISRCH     		;NO. WE HAVE MORE CHECKING TO DO
	CALLRET ISNFND		;ENTRY NOT FOUND
	SUBTTL Internet Address Translation - High Speed Sequential Search

;SEQSRC - USE SEQUENTIAL SEARCH FOR CHECKING GHT
;
; Search  backwards for the entry in the gateway host table that
; matches the Internet host number in T2.
;
; T1/ Pointer to area 1 of ght
; T2/ Internet host # to search for
; P3/ Number of entries in the table
;
; Returns + 1 if not found, T1/ area 1 adr where entry could be inserted
;			    T2/ area 2 adr where entry could be inserted
;	  + 2 on success, T1/ area 1 address of entry that matched
;			  T2/ area 2 address of entry that matched

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

SEQSRC:	MOVEI P2,-1(P3)		;GET THE OFFSET OF THE LAST ENTRY
SEQSR1:	MOVE P3,T1		;GET AREA 1 POINTER
	ADD P3,P2          	;ADD IN THE OFFSET TO BEGINNING OF THE TABLE
	CAME T2,(P3)		;DO THE ENTRIES MATCH
	IFSKP.
	 ADD T1,P2		;YES - FOUND IT. UPDATE GHT 1 POINTER
	 CALLRET ISFND
	ENDIF.
	CAMG T2,(P3)		;HOST # LESS THAN THIS ENTRY
	 SOJGE P2,SEQSR1	;YES - POINT TO PREVIOUS ENTRY
	AOS P2			;POINT TO ENTRY WHERE THIS HOST CAN BE INSERTED
	ADD T1,P2		;UPDATE GHT 1 POINTER
	CALLRET ISNFND		;NOT FOUND


;Here when the host we were looking for is in the ght

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

ISFND:	MOVE T2,P2		;GET MATCHING ENTRY
	IMULI T2,GH2MDL   	;MAKE OFFSET INTO AREA 2 
	ADD T2,GHTAR2
	RETSKP			;FOUND


;Here when the host we were looking for was not in the ght

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

ISNFND:	MOVE T2,P2 		;GET ENTRY WHERE IT SHOULD BE
	IMULI T2,GH2MDL  	;MAKE OFFSET INTO AREA 2 
	ADD T2,GHTAR2
	RET			;NOT FOUND
	SUBTTL Ethernet Internet Host Pinger

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

WERHER:				; Here to ping all hosts in GHTAR1
	SKIPN T1,GHTCNT		; Get the count of entries
	 RET			; If none then we are all done
	MOVE T2,GHTAR1		; Get area one address
WERHE1:				; Top of pinging loop
	MOVE T3,(T2)		; Get an internet address
	CALL SNDNOP		; Send him a NOP
	SOSLE T1		; Done them all yet?
	AOJA T2,WERHE1		; No so do the next one
	RET			; and return to caller

SNDNOP:				; Here to send a nop to adr in T3
	SAVEAC <T1,T2,P1,PKT,CPKT>
	STKVAR <SNOPA>
	MOVEM T3,SNOPA		; Save the target address
	MOVEI T1,<PKTELI+<<MINIHS+3>/4>+2> ;Echo packet size
	CALL GETBLK		; Get some free space
	 SKIPN PKT,T1		; Did we get the space?
	  RET			; No so we are all done
	MOVEI T2,<PKTELI+<<MINIHS+3>/4>+2> ;Echo packet size
	CALL CLRBLK		; Zero out the block
	MOVE T1,[BYTE (8)105,0,0,<8+MINIHS>]
	MOVEM T1,PKTELI+.IPKVR(PKT) ; Set version, length
	MOVEI T1,3		; Ping "lifetime"
	STOR T1,PITTL,(PKT)	; Set time to live field
	MOVEI T1,.ICMFM		; Protocol is ICMP
	STOR T1,PIPRO,(PKT)	; Set protocol type field
	MOVEI CPKT,<<MINIHS+3>/4>+PKTELI ; Min. Internet header size
	ADD CPKT,PKT		; Pointer to ICMP Section
	MOVE P1,NIPNCT		; Get out NCT
	MOVE T1,SNOPA		; Get the destination address
	STOR T1,PIDH,(PKT)	; Make it go there
	MOVE T2,NTLADR(P1)	; Get our address on the NI
	STOR T2,PISH,(PKT)	; That will be the source address
	MOVEI T3,ICM%EC		; Message type is ECHO
	STOR T3,CMTYP,(CPKT)	; Set into ICMP message type field
	SETZRO CMCOD,(CPKT)	; Clear code word
	SETONE CMID,(CPKT)	; (Make field non-zero)
	AOS T1,ICMSID		; Get an Id
	STOR T1,CMSEQ,(CPKT)	; Set ICMP sequence number
	STOR T1,PISID,(PKT)	; Set IP sequence number
	CALL ICMCKS		; Compute checksum of the packet
	STOR T1,CMCKS,(CPKT)	; Insert in packet
	CALL SNDGAT		; Send it off
	RET			; and return
	SUBTTL Address Resolution Protocol - Initialization

;ARPINI - INITIALIZE ARP
;
; Called when the Address Resolution Protocol is to be used.
; Enables the Arp multicast address "-1".
;
; Returns + 1 on errors with T1/ error code
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPINI::SAVEAC <SRV,NCT,ARP,UNB,RID>
	SKIPE ARPON		;IS ARP ALREADY ON ?
	JRST ARPIN1		;YES - DON'T REPORT ANY ERROR, GIVE SUCCESS
	MOVE NCT,NIPNCT		;GET THE NCT ADDRESS
	MOVE T1,NIPON		;GET "ON" FLAGS
	CAIGE T1,NI.ON		;MUST ATLEAST HAVE IPNI PORTAL RUNNING
	RETBAD <IPARP1>		;CAN'T START ARP UNTIL THEN
	CALL ARPOPN		;OPEN THE PORTAL
	 RETBAD			;COULDN'T
	MOVE UNB,AUNBLK		;GET THE ARP UN BLOCK
	CALL ARPGIB		;GET AND SET UP BUFFERS
	 RETBAD			;COULDN'T
	SETONE UNDAD,(UNB)	;DESTINATION IS BROADCAST (ALL ONES)
	SETONE UNDAD,+1(UNB)
	SETZRO UNRSP,(UNB)	;NO RESPONSE CALLBACK
	MOVX T1,NU.EMA		;SET FUNCTION CODE TO ENABLE MULTICAST
	MOVE T2,UNB      	;POINT AT UN BLOCK 
	CALL DLLUNI		;ENABLE IT
	 RETBAD			;COULDN'T
	CALL NISTAT		;GET THE STATUS AND HARDWARE ADDRESS
	 RETBAD			;COULDN'T
	SETOM ARPENA		;LET INTERNET KNOW THAT IT IS ENABLED
	SETOM ARPON		;ARP IS NOW ON
ARPIN1:	RETSKP
	SUBTTL Address Resolution Protocol - Open NISRV Portal

;ARPOPN - OPEN A PORTAL FOR ARP SERVICE
;
; Called  from  the  ARP  start  up  code to open a portal. This
; routine grabs some Internet free space and locks it for  a  UN
; block. It then sets up the UN block and does an OPEN function.
;
; NCT/ address of the nct
;
; Returns + 1 on error, error code in T1 
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPOPN:	SKIPE UNB,AUNBLK	;GET UN BLOCK ADR FOR THIS TYPE OF SERVICE
	JRST ARPO1		;ALREADY HAVE ONE
	MOVEI T1,UN.LEN		;GET SPACE FOR A UN BLOCK
	CALL GETBLK		;GET IT FROM THE IP FREE SPACE
	IFE. T1			;GOT A BUFFER IF NON-ZERO
	 BUG.(CHK,IPFNSP,IPNIDV,SOFT,<No free space for UN block for ARP>,,<

Cause:	The monitor attempted to assign some free space for the storage
	of ARP UN blocks and none was available.

>)
	 RETBAD <NI.ER5>	;FATAL ERROR FOR IPNI
	ENDIF.
	MOVEM T1,AUNBLK		;SAVE UN BLOCK POINTER, UPDATE UNB
	MOVE UNB,T1		;PUT IT WHERE IT SHOULD BE
	MOVEI T2,UN.LEN		;UN BLOCK LENGTH
	CALL NIPLKB		;LOCK IT
ARPO1:	MOVEI T1,APROTO		;GET PROTO TYPE FOR ARP
	SETZ T2,		;NO PORTAL ID SET YET
	MOVEI SRV,NI.ARP	;SET THE SERVICE TYPE
	CALL UNSET		;SET UP THE UN BLOCK
	MOVX T1,NU.OPN		;OPEN NI PORT FUNCTION
	MOVE T2,UNB    		;POINT AT THE UN BLOCK
	CALL DLLUNI		;CALL NI DRIVER
	 RET         		;TAKE ERROR RETURN. NI ERROR CODE IN T1
	RETSKP
	SUBTTL Address Resolution Protocol - Buffer Routines

;ARPGIB - GET AND INITIALIZE BUFFERS
;
; Called to get both input and output buffers for ARP.
;
; Returns + 1 on error, T1/ error code
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPGIB:	STKVAR <SWITCH,CNTDWN>
	SETZM SWITCH		;INIT SO THAT THE 1ST BUFFER IS FOR INPUT
	CALL ARPBUF		;GET A BUFFER
	JUMPE T1,[RETBAD]	;DIDN'T GET A BUFFER IF 0
	MOVEM T1,ABUFFR		;SAVE ADDRESS OF THIS BIG BUFFER
	LSH T2,-1		;ONLY 1/2 OF THE BUFFERS ARE FOR INPUT
	MOVEM T2,CNTDWN		;SAVE NUMBER OF BUFFERS WE GOT
	MOVE ARP,T1  		;SAVE THE BUFFER POINTER
	SETZM ARPNFI		;CLEAR OUT THE OLD COUNT
	SETZM ARPFRI		;AND THE OLD POINTER
ARPGB1:	MOVE T1,ARPNFI		;GET NUMBER OF FREE BUFFERS
	CAML T1,CNTDWN		;BELOW DESIRED LEVEL?
	RETSKP     		;NO
	SETZRO ARPNT,(ARP)	;CLEAR POINTER TO NEXT
	SETCMM SWITCH		;COMPLIMENT THE "USE BUFFER FOR INPUT"
	SKIPN SWITCH		;SHOULD BUFFER BE USED FOR INPUT ?
	IFSKP.
	 SETONE ARTYP,(ARP)	;FLAG AS AN INPUT BUFFER
	 MOVE T1,ARP   		;YES - GET THE BUFFER ADDRESS
         CALL ARPOST		;POST IT
	  RETBAD		;COULDN'T
	ELSE.
	 CALL ARPQIT		;PUT BUFFER ON THE FREE LIST QUEUE
	 MOVX T2,AR.ETH		;NO - SET UP CONSTANT DATA FOR SEND BUFFERS
	 STOR T2,AR$HD,(ARP)	;SET HARDWARE TYPE AS ETHERNET
	 MOVX T2,IPROTO		;SET ETHERNET PROTOCOL TYPE TO INTERNET
	 STOR T2,AR$PR,(ARP)
	 MOVX T2,AR.HLN		;SET HARDWARE ADDRESS LENGTH FOR ETHERNET
	 STOR T2,AR$HL,(ARP)
	 MOVX T2,AR.PLN		;SET PROTOCOL ADDRESS LENGTH FOR INTERNET
	 STOR T2,AR$PL,(ARP)
	 MOVX T2,AR.REQ		;OPCODE IS REQUEST
	 STOR T2,AR$OP,(ARP)
	ENDIF.
	ADDI ARP,AR.WRD		;POINT TO ADDRESS IF NEXT BUFFER
	JRST ARPGB1		;SEE IF ENOUGH

	ENDSV.			;END OF ARPGIB STKVAR

;ARPQIT - PUT BUFFER ON FREE QUEUE
;
; Here from ARPGIB to put the buffer on the free queue
;
; ARP/ address of the buffer
;
; Returns + 1 always

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

ARPQIT:	PIOFF
	MOVE T2,ARP 
	EXCH T2,ARPFRI		;ADD TO LIST OF FREE INPUT BUFFERS
	STOR T2,ARPNT,(ARP)	;OLD LIST IS SUCCESSOR OF THIS BUF
	AOS ARPNFI		;BUMP THE COUNT TO MATCH
	PION
	RET


;ARPBUF - GET A BUFFER 
;
; Called  to  get  a buffer. One buffer should hold aprox 16 ARP
; packets based on a MAXWPM set to 370 words as buffer size.
;
; Returns + 1 always, T1/ beginning address of the buffer
;		      T2/ number of ARP buffers available

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPBUF:	SKIPN T1,ABUFFR		;ALREADY HAVE A BUFFER ?
	IFSKP.
	 SUBI T1,MAXLDR		;YES - POINT AT BEGINNING
	 JRST ARPBF1
	ENDIF.
	CALL NIPBFR		;GET A BUFFER
	SKIPE T1		;DID WE GET ONE ?
	IFSKP.
	 BUG. (CHK,IPNARP,IPNIDV,SOFT,<No buffer space for ARP>,,<

Cause:	The monitor attempted to assign a buffer for use by ARP and
	none were available.

>)
	 RET
	ENDIF.
ARPBF1:	LOAD T2,NBBSZ,(T1) 	;GET BUFFER SIZE
	SUBI T2,LCLPKT+MAXLDR	;DON'T INCLUDE LEADER SIZE
	ADDI T1,MAXLDR		;FOR CONSISTENCY WITH OTHER BUFFERS
	IDIVI T2,AR.WRD		;GET NUMBER OF BUFFERS
	CAIL T2,AR.TNB		;GET ENOUGH BUFFERS ?
	RET			;YES
	BUG. (INF,IPFRAB,IPNIDV,SOFT,<Fewer than required ARP buffers assigned>,,<

Cause:	The monitor has assigned a buffer for use by ARP but further analysis
	shows that the buffer is not large enough for the number of messages
	ARP wants to allow.

>)
	RET

;ARPBFR - GET AN INPUT BUFFER
;
; Returns + 1 always with T1 containing the buffer address

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

ARPBFR:	PIOFF		
	SOSL ARPNFI		;COUNT DOWN NUMBER OF FREE INTERNET BUFS
	 SKIPN T2,ARPFRI	;GET POINTER TO BUFFER TO USE
	 IFNSK.
	  AOS ARPNFI		;NO BUFFERS AVAILABLE. DON'T LET COUNT GO NEG.
	  PION			;MAKE SURE INTERRUPTS ARE BACK ON
	  BUG.(CHK,IPABFL,IPNIDV,SOFT,<ARP input buffer list fouled>,,<

Cause:	The internet ethernet software has detected that the buffer list for
	the ARP protocol is smashed.  This probably indicates a software
	problem.

>)
	  SETZ T1,		;FLAG TO NIPOST THAT WE HAVE NO BUFFER
	  RETBAD		;TRY TO RECOVER
	 ENDIF.
	LOAD T1,ARPNT,(T2)	;NEXT INTERNET FREE BUFFER
        SETSEC T1,INTSEC	;YES SO SET THE SECTION NUMBER
	SETZRO ARPNT,(T2)	;CLEAR LIST POINTER
	MOVEM T1,ARPFRI		;BECOMES HEAD OF LIST
	PION			;MAKE SURE INTERRUPTS ARE BACK ON
	MOVE T1,T2		;PUT THE ADDRESS WHERE IT'S EXPECTED
	RET
	SUBTTL Address Resolution Protocol - Send ARP Message

;ARPSND - BUILD AND SEND AN ARP MESSAGE 
;
; Called  from  the  NISEND  routine  when it found out that the
; Internet  routing  host number was  not found  in the GHT.  We 
; discard  the IP datagram by  putting it on  the Internet  free 
; queue  and  generate  an  ARP  packet  requesting the Ethernet 
; address of that Internet host.
;
; Alternate  entry point ARPSD1 is called from ARPRCV to send  a 
; reply ARP packet.   It sets up the variable data of ARP packet 
; and UN block. The UN block address is that specified by NISRV.
;
; RID/ address of the IP buffer
;
; Returns + 1 on error, T1/ error code
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPSND:	SAVEAC <SRV,ARP,NCT,UNB,RID>
	MOVE NCT,NIPNCT		;GET THE NCT ADDRESS
	MOVE UNB,AUNBLK		;GET THE UN BLOCK POINTER
	CALL ARPBFR		;GET A BUFFER TO USE
	JUMPE T1,R     		;NONE AVAILABLE IF ZERO, ARPBFR BUGINF'D
	MOVE ARP,T1		
	MOVE T2,NI.HOP(RID)	;PROTOCOL TARGET ADR IS INTERNET ROUTING ADR
	STOR T2,AR$TA,(ARP)
	MOVX T2,AR.REQ		;OPCODE IS REQUEST
	STOR T2,AR$OP,(ARP)
ARPSD1:	DMOVE T2,ETHADR		;GET OUR CURRENT ETHERNET ADDRESS
	LSH T2,-4		;SHIFT RIGHT BECAUSE ETHADR IS FULL WORD
	STOR T2,AR$S1,(ARP)	; AND AR$S1 IS 32 BITS.  SAVE IT
	LSH T3,-^D20		;SHIFT RIGHT BECAUSE ETHADR+1 IS FULL WORD
	STOR T3,AR$S2,(ARP)	; AND AR$S2 IS 16 BITS.  SAVE IT
	MOVE T2,NTLADR(NCT)	;GET OUR INTERNET HOST NUMBER
	LSHC T2,-^D16		;HIGH 2 BYTES IN T2
	LSH T3,-^D20		;LOW 2 BYTES IN T3
	STOR T2,AR$P1,(ARP)
	STOR T3,AR$P2,(ARP)
	NOSKED			;DON'T LET OTHERS IN HERE
	XMOVEI T2,ARPPKT(ARP)	;POINT AT DATA PORTION OF BUFFER
	TXO T2,<OWGP. 8,>	;FORM BYTE POINTER TO BUFFER
	STOR T2,UNBFA,(UNB)	;SAVE THE BYTE POINTER AWAY AS BUFFER ADR
	STOR ARP,UNRID,(UNB)	;SAVE BUFFER ADR AS REQUEST ID
	MOVEI T1,AR.LEN		;GET ARP PACKET LENGTH
	STOR T1,UNBSZ,(UNB)	;SAVE LENGTH FOR NISRV 
	MOVX T1,NU.XMT		;SET FUNCTION CODE TO TRANSMIT
	MOVE T2,UNB      	;POINT AT UN BLOCK 
	CALL DLLUNI		;SEND THE BUFFER
	 RETBAD <>,<OKSKED>	;NI RETURNED ERROR 
	OKSKED			;OKAY FOR OTHERS
	RETSKP
	SUBTTL Address Resolution Protocol - Post ARP Receive Buffer

;ARPOST - POST AN ARP INPUT BUFFER 
;
; This routine gives NISRV a receive buffer. The buffer must 
; be resident.
;
; T1/ address of input buffer
; UNB/ address of the UN block
;
; Returns + 1 if error returned from NISRV
;	  + 2 on success

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

ARPOST:	SKIPN T1		;ZERO IF NIPBFR COULDN'T GET A BUFFER
	RETBAD <NI.ER1>		;RETURN THE ERROR
	MOVEI T3,AR.MAX		;GET MAX PACKET SIZE
	STOR T3,UNBSZ,(UNB)	;SAVE IT AS RECEIVE BUFFER SIZE
	STOR T1,UNRID,(UNB)	;SAVE INPUT BUFFER ADR AS REQUEST ID
	ADDI T1,ARPPKT		;POINT PAST HEADER FOR START OF ARP PACKET
	TXO T1,<OWGP. 8,>	;FORM BYTE POINTER TO BUFFER
	STOR T1,UNBFA,(UNB)	;SAVE AS THE BUFFER ADDRESS
	MOVX T1,NU.RCV		;POST RECEIVE BUFFER FUNCTION
	MOVE T2,UNB      	;GET UN BLOCK ADR
	CALL DLLUNI		;CALL NISRV
	 CALLRET POSTER		;NISRV RETURNED ERROR
	RETSKP			;SUCCESS

;ARPKIL - SHUTDOWN ARP
;
; Called from the IPOPR to shut off ARP communications.
;
; Alternate entry point ARPKL1 is called from NIPKIL. This
; leaves ARPENA on for later use of ghts.
;
; Returns + 2 always

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPKIL::SETZM ARPENA		;CLEAR THE ENABLE FLAG
ARPKL1:	MOVE UNB,AUNBLK		;GET THE ARP UN BLOCK
	MOVX T1,NU.CLO		;NI CLOSE FUNCTION
	MOVE T2,UNB    		;GET UN BLOCK ADDRESS
   	CALL DLLUNI		;DO THE CLOSE
	 JFCL
	SETZM ARPON		;CLEAR ARP ON FLAG
	RETSKP
	SUBTTL ARP Datagram Sent Callback

;ARPCDS - ARP DATAGRAM SENT 
;
; Called  when  the ARP packet has been sent. It puts the buffer
; back on the free buffer list.
;
; T2/ UN block address 
; T3/ 0 if function succesfull or error code 
; UNRID/ address of buffer 
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

ARPCDS:	MOVE UNB,T2		;SAVE UN BLOCK ADDRESS
	LOAD ARP,UNRID,(UNB)	;GET THE BUFFER ADDRESS TO RELEASE
	MOVE T2,ARP		;COPY FOR INDEXING
 	PIOFF
	EXCH T2,ARPFRI		;ADD TO LIST OF FREE INPUT BUFFERS
	STOR T2,ARPNT,(ARP)	;OLD LIST IS SUCCESSOR OF THIS BUF
	AOS ARPNFI		;BUMP THE COUNT TO MATCH
	PION
	SKIPE T1,T3		;DID WE HAVE AN ERROR?
	 CALLRET CDSERR		;YES SO PROCESS IT
	RETSKP			;NO ERROR SO SUCCESS RETURN
	SUBTTL ARP Datagram Received Callback

;ARPCDR - DATAGRAM RECEIVED
;
; The  NI  received an ARP datagram. The address is available 
; in UNRID of the UN block.
;
; T2/ UN block address 
; T3/ 0 if function succesfull or error code 
; UNRID/ address of buffer 
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

ARPCDR:	LOAD T1,UNRID,(T2)	;GET THE ADDRESS OF THE BUFFER
	JUMPN T3,[CAIN T3,UNRAB% ;CHANNEL SHUTTING DOWN ?
	 	  RETBAD <>,<MOVE T1,T3> ;YES - DO NOTHING
	          AOS NIICNT	;NO. BUMP THE INPUT ERROR COUNTER
		  MOVE UNB,T2	;USE NISRV UN BLOCK TO REPOST BUFFER
	          CALLRET ARPOST] ;USE THIS BUFFER OVER
	MOVE NCT,NIPNCT		;GET OUR NCT
	PIOFF			;DON'T ALLOW US TO BE INTERRUPTED
	MOVE T3,NTLOBI(NCT)	;QUEUE FOR PROCESSING BY INTERNET FORK
	JUMPN T3,ACDRQ1		;ANYTHING ELSE ON THE LIST ?
	MOVEM T1,NTLOBO(NCT)	;ONLY THIS ITEM IN THE LIST
	SKIPA
ACDRQ1:	STOR T1,ARPNT,(T3)	;LINK IT IN
	MOVEM T1,NTLOBI(NCT)	;NEW POINTER
	AOS INTFLG		;CAUSE INTERNET TO NOTICE IT.
	AOS PSKD1		;MAKE THE SCHEDULER NOTICE THIS IF IN NULL JOB
	PION
	RETSKP			;GIVE GOOD RETURN
	SUBTTL ARP Processing by the Internet Fork 

;ARPPRC - ARP PACKET PROCESSOR
;
; Called by NIPSRV by the internet fork to process any ARP
; packets that have been sent to us.  After the packet has 
; been processed, the input buffer is given back to NISRV.
;
; NTLOBO/ Local network (ARP) list head pointer
; NTLOBI/ Tail pointer
;
; Returns + 1 always

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

;**;[7450] Change some comments in the ARPRO1 code      JMP  Apr 8 87
;**;[7450] Also insert 1 line at ARPRO1+8L and +10 L    JMP  Apr 8 87

ARPPRC:	SAVEAC <SRV,ARP,RID,NCT,UNB>
	MOVE NCT,NIPNCT		;GET OUR NCT ADDRESS
	MOVE UNB,AUNBLK		;GET THE ARP UN BLOCK POINTER
ARPRO1:	SKIPN ARP,NTLOBO(NCT)	;[7450] ANY ARP PACKETS TO PROCESS ?
	RET             	;NO
	PIOFF			;NO INTERRUPTS
	LOAD T2,ARPNT,(ARP)	;GET ITS SUCCESSOR
	SKIPN T2        	;SKIP IF NOT LAST ONE
	SETZM NTLOBI(NCT)	;YES.  MAKE QUEUE NULL
	MOVEM T2,NTLOBO(NCT)	;[7450] UPDATE ARP QUEUE POINTER
	SETZRO ARPNT,(ARP)	;[7450] DEQUEUE PACKET FROM ITS OLD CHAIN
 	PION			;ALLOW INTERRUPTS AGAIN
	SETOM GHTLOK		;[7450] LOCK THE GHT FROM OUTSIDE UPDATES
	CALL ARPRCV		;GO PROCESS THE PACKET
	 JFCL                   ;ERROR. IGNORE IT
	SETZM GHTLOK		;[7450] OKAY TO UNLOCK THE GHT NOW
	MOVE T1,ARP		;GET PACKET ADDRESS BACK
	CALL ARPOST		;RE-POST IT
	 RETBAD
	JRST ARPRO1		;GO TRY FOR ANOTHER
	SUBTTL ARP Incoming Packet Processing

;ARPRCV - PROCESS INCOMING ARP PACKETS
;
; Called  to  process  an incoming ARP packet. Provided that the
; packet  is  accepted,  this  routine  updates  the  GHT   with
; information about the host that sent the packet. If the packet
; is a request for us, we will generate a reply message.
;
; ARP/ address of the buffer
; UNB/ address of the UN block 
; NCT/ NCT address
;
; Returns + 1 on error with T1/ error code
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPRCV:	TRVAR <AREA1,AREA2,SPADR,<SHADR,2>>
	SAVEAC <ARP>		;SAVE THE CURRENT ARP POINTER 
	LOAD T1,AR$HD,(ARP)	;GET HARDWARE TYPE
	LOAD T2,AR$PR,(ARP)	;GET PROTOCOL TYPE
	CAIN T1,AR.ETH		;IS IT ETHERNET HARDWARE ?
	 CAIE T2,IPROTO		;YES - IS IT INTERNET PROTOCOL
	  RET        		;NO, IGNORE THE PACKET
	LOAD T1,AR$HL,(ARP)	;GET LENGTH OF HARDWARE ADDRESS
	LOAD T2,AR$PL,(ARP)	;GET LENGTH OF PROTOCOL ADDRESS
	CAIN T1,AR.HLN		;HARDWARE ADR LENGTH SAME AS OUR'S ?
	 CAIE T2,AR.PLN		;YES - PROTOCOL LENGTH SAME AS OUR'S ?
	  RET        		;NO, IGNORE THE PACKET
	LOAD T1,AR$S1,(ARP)	;GET ETHERNET ADR (WORD 1) OF SENDER
	LSH T1,4		;SHIFT LEFT, OUR ADR IS LEFT ADJUSTED
	LOAD T2,AR$S2,(ARP)	; AND THE 2ND WORD
	LSH T2,^D20		;ALIGN THE 2ND WORD TO THE LEFT
	DMOVEM T1,SHADR     	;SAVE AWAY THE NEW DATA
	LOAD T1,AR$P1,(ARP)	;GET WORD 1 OF INTERNET ADDRESS
	LOAD T2,AR$P2,(ARP)	;GET WORD 2 OF INTERNET ADDRESS
	DPB T1,[POINT 16,T2,19]	;FORM REAL INTERNET ADDRESS IN T2
	MOVEM T2,SPADR		;SAVE SENDER PROTOCOL ADDRESS
	CALL INTSRC		;THIS HOST IN THE GHT ?
	 JRST ARPRC1		;NO, POSSIBLE ENTRY INSERTION NEEDED
	MOVE T3,T2		;COPY GHT POINTER 
	DMOVE T1,SHADR		;GET SENDERS HARDWARE ADDRESS
	DMOVEM T1,GH.EN1(T3)	;SAVE AS ETHERNET ADDRESS
	MOVX T1,GH%ARP		;GET UPDATED BY ARP FLAG
	IORM T1,GH.GCF(T3)	;SET IT IN THE GHT
	SETZB T1,T2		;NO INSERT OF ENTRY NEEDED NOW
ARPRC1:	MOVEM T1,AREA1		;SAVE AREA 1 POINTER
	MOVEM T2,AREA2		;SAVE AREA 2 POINTER
	CALL ARPRC2		;NEXT STEP, PROCESS OPCODE
	 RETBAD			;GO AN ERROR OR IGNORE PACKET
	RETSKP

;ARPRC2 - STEP 2 OF PROCESSING INCOMING ARP PACKETS
;
; This routine checks to see if the ARP packet was actually sent
; to  us and checks to see if it was a request. If it was to us,
; and the insert flag is on, we add the information to  the GHT.
; If the packet is a request, we send a reply.
;
; AREA1/ 0 if merge was done or adr of ght area 1 if insertion needed
; AREA2/ 0 if merge was done or adr of ght area 2 if insertion needed
; SPADR/ sender protocol address
; SHADR/ sender hardware address
; ARP/ address of ARP packet
; NCT/ NCT address
; UNB/ address of the UN block given to us by NISRV

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPRC2:	LOAD T1,AR$TA,(ARP)	;GET THE TARGET INTERNET ADDRESS
	CAME T1,NTLADR(NCT)	;WAS THE PACKET FOR US ?
	RET         		;NO, IGNORE IT
	SKIPE AREA2 		;SHOULD THIS INFORMATION BE INSERTED ?
	CALL ARPUPD		;YES, UPDATE THE GHT
	LOAD T1,AR$OP,(ARP)	;GET THE OPCODE
	CAIE T1,AR.REQ		;IS IT A REQUEST ?
	RET        		;NO, WE'RE DONE WITH THE PACKET NOW
	CALLRET ARPRC3		;YES, GO REPLY TO IT


;ARPRC3 - STEP 3 IN PROCESSING AN ARP PACKET
;
; Here to send a reply ARP packet
;
; ARP/ address of the ARP packet
; SPADR/ sender protocol address
; UNB/ address of the UN block given to us by NISRV
;
; Returns + 1 if packet is to be ignored
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPRC3:	CALL ARPBFR		;GET SEND BUFFER TO USE
	JUMPE T1,R     		;NONE AVAILABLE IF ZERO, ARPBFR BUGINF'D
	MOVE ARP,T1		
	MOVE T1,SPADR		;GET THE INTERNET ADDRESS OF SENDER
	STOR T1,AR$TA,(ARP)	;SAVE THIS AS THE TARGET ADDRESS
	MOVEI T1,AR.REP		;SET OPCODE TO REPLY
	STOR T1,AR$OP,(ARP)
	CALL ARPSD1		;SET UP REST OF ARP, UN BLOCK AND SEND IT
	 RETBAD
	RETSKP
	SUBTTL ARP GHT Updating

;ARPUPD - UPDATE THE GHT
;
; Called from ARPRC2, this routine inserts an entry into
; the ght.
;
; AREA1/ adr of ght area 1 where entry is to be inserted
; AREA2/ adr of ght area 2 where entry is to be inserted
; SPADR/ sender protocol address
; SHADR/ sender hardware address
;
; Returns + 1 always

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPUPD:	MOVE T3,GHTCNT		;GET # OF ENTRIES IN THE GHT
	CAML T3,NIMAXH		;ANY MORE ROOM ?
	CALLRET ARPMAX		;NO
;**;[7450] Delete 1 line at ARPUPD+3      JMP   Apr 9 87
	MOVE T2,GHTAR1		;GET ADDRESS OF AREA ONE
	ADD T2,GHTCNT		;GET ADDRESS OF END OF AREA ONE
	MOVN T1,T2		;WE ARE GOING TO DO A REVERSE XBLT
	ADD T1,AREA1		;DETERMINE THE REAL COUNT
	XMOVEI T3,1(T2)		;DESTINATION IS ONE GREATER THAN SOURCE
	XBLT. T1,		;SHUFFLE AREA ONE WITH REVERSE XBLT
	MOVE T1,AREA2		;GET ADR OF AREA 2 ENTRY
	MOVE T2,GHTCNT		;GET CURRENT NUMBER OF GHT ENTRIES
	IMULI T2,GH2MDL		;GET CURRENT LENGTH OF AREA 2
	ADD T2,GHTAR2		;DETERMINE LAST ADR IN AREA 2
	SUB T1,T2		;GET NEGATIVE COUNT FOR REVERSE XBLT
	XMOVEI T3,GH2MDL(T2)	;GET DEST ADR FOR REVERSE XBLT
	XBLT. T1,		;SHUFFLE AREA TWO 
	MOVE T1,SPADR		;GET SENDERS INTERNET ADDRESS
	MOVE T2,AREA1		;GET THE ADDRESS WHERE TO INSERT
	MOVEM T1,(T2)		;INSERT THE ADDRESS
	DMOVE T1,SHADR		;GET ETHERNET ADDRESS OF SENDER
	MOVE T3,AREA2		;GET THE ADDRESS WHERE TO INSERT
	DMOVEM T1,GH.EN1(T3)	;INSERT IT
	AOS GHTCNT		;BUMP THE COUNT
;**;[7450] Delete 1 line from ARPUPD+25   JMP   Apr 8 87
	MOVX T1,GH%ARP		;GET UPDATED BY ARP FLAG
	IORM T1,GH.GCF(T3)	;SET IT IN THE GHT
	RET

;Here when the entry could not be inserted.
ARPMAX:	BUG.(INF,IPGHTF,IPNIDV,SOFT,<ARP information not inserted, GHT is full>,,<

Cause:	The internet ethernet ARP software has attempted to add another 
	internet/ethernet address translation to the GHT and the GHT was
	full.  This problem could be avoided by increasing NIMAXH.

>)
	RETBAD <NI.ER7>

	ENDTV.			;END OF ARPRCV ARPVAR TRVAR
	SUBTTL Trailer Encapsulation Handling

;TRLINI - INITIALIZE TRAILER ENCAPSULATION
;
; Called here from the restart code to open portal for the 
; trailer encapsultion protocol types. 
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

TRLINI:	TRVAR <UNBLK,PROTO>
	SKIPE TRLON		;ALREADY ON ?
	 RETSKP			;YES
	MOVEI T1,UN.LEN		;RESERVE WORDS FOR A UN BLOCK
	CALL GETBLK		;GET THEM
	JUMPE T1,[RETBAD <NI.ER5>] ;COULDN'T
	MOVEM T1,UNBLK		;SAVE UN BLOCK FOR LATER
	MOVE UNB,T1		;COPY IT
	MOVEI T1,TPROTO		;1ST INTERNET TRAILERS PROTOCOL TYPE 
	MOVEM T1,PROTO		;SAVE IT
TROPN3:	MOVEI SRV,NI.TRL	;TYPE OF SERVICE IS TRAILERS
	CALL UNSET		;SET UP THE UN BLOCK
	MOVX T1,NU.OPN		;OPEN NI PORT FUNCTION
	MOVE T2,UNB    		;POINT AT THE UN BLOCK
	CALL DLLUNI		;CALL NI DRIVER
	 JRST TROPN1		;ERROR. RETURN UN BLOCK
	CALL NIPBFR		;GET A BUFFER FOR THIS PROTOCOL TYPE
	CALL TRPOST		;POST IT
	 JRST TROPN1		;ERROR
	AOS T1,PROTO		;BUMP TO NEXT HIGHER TRAILER SIZE
	CAIG T1,TRMAXP+TPROTO	;OPENED ENOUGH TYPES ?
	 JRST TROPN3		;YES
	SETOM TRLON		;PORTALS ARE OPEN
	CALL TROPN2		;GO RELEASE THE UN BLOCK WE GOT
	RETSKP

;Here when we got an error opening the portal

TROPN1:	MOVEM T1,TRLERR		;SAVE THE ERROR
	CALL TROPN2		;RELEASE THE UN BLOCK
	RETBAD <>,<MOVE T1,TRLERR> ;RESTORE ERROR CODE

;Here to return the UN block we just got.

TROPN2:	MOVE T1,UNBLK		;GET UN BLOCK ADR 
	CALLRET RETBLK		;AND RELEASE THE SPACE

	ENDTV.			;END OF NIOPEN TRVAR

;TRPOST - POST AN TRAILER ENCAPSULATION INPUT BUFFER 
;
; This routine gives NISRV a receive buffer. The buffer must 
; be resident.
;
; T1/ address of input buffer
; UNB/ address of the UN block
;
; Returns + 1 if error returned from NISRV
;	  + 2 on success

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

TRPOST:	SKIPN T1		;ZERO IF NIPBFR COULDN'T GET A BUFFER
	RETBAD <NI.ER1>		;RETURN THE ERROR
	LOAD T3,NBBSZ,(T1) 	;GET BUFFER SIZE
	SUBI T3,LCLPKT+MAXLDR	;DON'T INCLUDE LEADER SIZE
	LSH T3,2		;MAKE WORDS INTO BYTES
	STOR T3,UNBSZ,(UNB)	;SAVE IT AS RECEIVE BUFFER SIZE
	STOR T1,UNRID,(UNB)	;SAVE INPUT BUFFER ADR AS REQUEST ID
	ADDI T1,MAXLDR		;POINT PAST LEADER FOR START OF IP HEADER
	TXO T1,<OWGP. 8,>	;FORM BYTE POINTER TO BUFFER
	STOR T1,UNBFA,(UNB)	;SAVE AS THE BUFFER ADDRESS
	MOVX T1,NU.RCV		;POST RECEIVE BUFFER FUNCTION
	MOVE T2,UNB      	;GET UN BLOCK ADR
	CALL DLLUNI		;NO. CALL NISRV
	 CALLRET POSTER		;NISRV RETURNED ERROR
	RETSKP			;SUCCESS


;TRLCDR - TRAILER ENCAPSULTED DATAGRAM RECEIVED
;
; The NI received a trailer encapsulted datagram, we don't accept
; those messages. We will buginf and then toss the message.
;
; T2/ UN block address 
; T3/ 0 if function succesfull or error code 
; UNRID/ address of buffer 
;
; Returns + 1 on error
;	  + 2 on success

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

TRLCDR:	MOVE UNB,T2		;COPY THE UN BLOCK POINTER
	LOAD T1,UNSAD,(UNB)	;GET THE ETHER ADDRESS OF SENDER
	LOAD T2,UNSAD,+1(UNB)
	LOAD T3,UNPRO,(UNB)	;GET THE PROTO TYPE
	BUG.(INF,IPTENC,IPNIDV,SOFT,<Received a trailer encapsulated packet>,<<T1,ETH1>,<T2,ETH2>,<T3,PROTO>>,<

Cause:	 The monitor has received a trailer encapsulation IP datagram
	 over the Ethernet.

Description:
	 
         A  system  on  the  Ethernet  is using trailer encapsulation
	 formats for the transmission of IP datagrams.  TOPS-20  (and
	 most  other  operating  systems)  does  not  support trailer
	 encapsulation.   Some   Berkeley   Unix   and   VMS   TCP/IP
	 implementations support trailer encapsulation in an effort to
	 enhance their Internet performance characteristics.

Action:  Stop the indicated systems from using trailer encapsulation.

Additional Data:

Ethernet address of host sending trailer encapsulation in octal and 
the protocol type received.

>)
	LOAD T1,UNRID,(UNB)	;GET THE ADDRESS OF THE BUFFER
	CALL TRPOST		;POST IT
	 RETBAD                 ;GOT AN ERROR 
	RETSKP			;GIVE GOOD RETURN
	SUBTTL Read Portal Counters 

;ARPRPC - READ ARP PORTAL COUNTERS
;
; Reads  the portal  counters for ARP.  Information  is returned 
; by the RPC callback.
;
; Returns + 1 always. If error is returned from NISRV, ARPSRQ/ -1

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

ARPRPC:	SAVEAC <NCT,SRV,UNB>
	MOVE UNB,AUNBLK		;GET UN BLOCK POINTER
	JUMPE UNB,[RETBAD <>,<SETOM ARPSRQ>] ;NO UN BLOCK SET UP YET
	XMOVEI T1,ARPTRS	;USE THE ARP BLOCK
	CALL GETRPC		;GET THE COUNTERS
	 RETBAD <>,<SETOM ARPSRQ> ;NO UN BLOCK SET UP YET
	RET


;ARPCRP - READ ARP PORTAL COUNTERS CALLBACK
;
; This  is  callback  occurs  when  NISRV  has  completed a read
; counters function. It clears the ARPSRQ flag which signals the
; completion of the RPC. If NISRV returns an  error,  ARPSRQ  is
; set to -1.
;
; T2/   UN block address
; T3/   0 or NISRV error code

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

ARPCRP:	SKIPE T1,T3
	 RETBAD <>,<SETOM ARPSRQ> ;ERROR DETECTED ?
	SETZM ARPSRQ		;SIGNAL SUCCESSFUL COMPLETION
	RETSKP

;NIPRPC - READ INTERNET PORTAL COUNTERS
;
; Called  by  the  NIPSRV  background  routine to service a user
; IPOPR request to return the portal counters.   All information
; is returned in the block pointed to by the NICTRS word.
;
; Returns + 1 always. If error is returned from NISRV, NIPSRQ/ -1

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

NIPRPC:	SAVEAC <NCT,SRV,UNB>
	CALL INTUNB		;GET UN BLOCK POINTER
	 RETBAD <>,<SETOM NIPSRQ> ;NO UN BLOCK SET UP YET
	XMOVEI T1,NICTRS	;USE THE INTERNET COUNTERS BLOCK
	CALL GETRPC		;GET PORTAL COUNTERS
	 SETOM NIPSRQ		;NO UN BLOCK SET UP YET
	CALL RETUNB		;RETURN THE UN BLOCK
	RET
	 

;IPCBRC - READ INTERNET PORTAL COUNTERS CALLBACK  
;
; This  is  callback  occurs  when  NISRV  has  completed a read
; counters function. It clears the NIPSRQ flag which signals the
; completion of the RPC. If NISRV returns an  error,  NIPSRQ  is
; set to -1.
;
; T2/   UN block address
; T3/   0 or NISRV error code

IFE REL6,<RESCD>
IFN REL6,<XRESCD>

IPCBRC:	SKIPE T1,T3
	RETBAD <>,<SETOM NIPSRQ> ;ERROR DETECTED ?
	SETZM NIPSRQ		;SIGNAL SUCCESSFUL COMPLETION
	RETSKP

;GETRPC - GET PORTAL COUNTERS
;
; Used by both Internet and Arp, this routine tells NISRV to
; return the portal counter information.
;
; T1/ address that points to the block to put counter data
; UNB/ address of the UN block
;
; Returns + 1 on errors
;         + 2 on success

IFE REL6,<SWAPCD>
IFN REL6,<XSWAPCD>

GETRPC:	SASUBR <CTRBLK>		;SAVE T1 - POINTER TO COUNTER BLOCK
	SKIPE (T1)  		;ALREADY HAVE SPACE ?
	JRST RPC1		;YES
	MOVEI T1,PC.LEN		;GET SPACE FOR PORTAL COUNTERS 
	CALL GETBLK		;GET IT FROM THE IP FREE SPACE
	IFE. T1			;GOT A BUFFER IF NON-ZERO
RPCERR:	 BUG.(CHK,IPNSPC,IPNIDV,SOFT,<No free space for portal counters>,<<SRV,SERVICE>>,<

Cause:	The internet ethernet software has attempted to read the counters for
	a portal and no internet free space was available.

>)
	 RETBAD <NI.ER6>
	ENDIF.
	MOVE T2,CTRBLK		;GET POINTER TO THE BLOCK
	MOVEM T1,(T2)  		;SAVE POINTER TO PORTAL COUNTER BLOCK
	MOVEI T2,PC.LEN		;LENGTH OF THE BLOCK
	CALL NIPLKB		;LOCK THE COUNTER BLOCK
	CALL CLRBLK		;CLEAR OUT THE BLOCK
RPC1:	SETZRO UNZRO,(UNB)	;NEVER CLEAR COUNTERS
	LOAD T1,UNPID,(UNB)	;GET OUR PORTAL ID
	STOR T1,UNSPI,(UNB)
	MOVE T1,CTRBLK		;PUT DATA IN OUR COUNTER STORAGE
	STOR T1,UNBFA,(UNB)
	MOVX T1,PC.LEN		;NUMBER OF COUNTER WORDS
	STOR T1,UNBSZ,(UNB)
	MOVX T1,NU.RPC		;READ PORTAL COUNTERS FUNCTION
	MOVE T2,UNB      	;POINT AT UN BLOCK
	CALL DLLUNI		;ASK NISRV
	 RETBAD 		;NISRV RETURNED AN ERROR
	RETSKP

	TNXEND
	END