(FILECREATED "29-Nov-83 19:31:29" {PHYLUM}<LISPCORE>SOURCES>LLNS.;23 63378  

      changes to:  (FNS \HANDLE.RAW.XIP \ROUTE.XIP SWAPXIPADDRESSES)

      previous date: "10-NOV-83 22:34:04" {PHYLUM}<LISPCORE>SOURCES>LLNS.;22)


(* Copyright (c) 1983 by Xerox Corporation)

(PRETTYCOMPRINT LLNSCOMS)

(RPAQQ LLNSCOMS ((COMS (* Xerox Internet Packet stuff.)
		       (DECLARE: DONTCOPY (EXPORT (RECORDS XIP)
						  (CONSTANTS \XIPOVLEN \MAX.XIPDATALENGTH)
						  (CONSTANTS * RAWXIPTYPES))
				 (CONSTANTS * XIPERRORCODES))
		       (ADDVARS * (LIST (CONS (QUOTE XIPTYPES)
					      RAWXIPTYPES)))
		       (ALISTS (XIPERRORMESSAGES 1 2 3 513 514 515 516))
		       (GLOBALVARS XIPTYPES XIPERRORMESSAGES))
		 (COMS (* Parsing and looking up NS addresses)
		       (DECLARE: DONTCOPY (MACROS \GPNCHAR)
				 (* Get Previous Numerical-valued CHARacter from string pointer))
		       (FNS \NS.FINDNSADDRESS \PARSE.NSADDRESSCONSTANT \PARSEANUM))
		 (COMS (* New SOCKET datatype stuff)
		       (DECLARE: DONTCOPY (EXPORT (RECORDS NSOCKET)
						  (* Well-known NS sockets)
						  (CONSTANTS (\NS.WKS.RoutingInformation 1)
							     (\NS.WKS.Echo 2)
							     (\NS.WKS.RouterError 3)
							     (\NS.WKS.Courier 5)
							     (\NS.WKS.PUPLOOKUP 9)))
				 (GLOBALVARS \NSOCKETS \MAX.EPKTS.ON.NSOCKET)
				 (MACROS \NSOCKET.FROM#))
		       (INITRECORDS NSOCKET)
		       (SYSRECORDS NSOCKET)
		       (FNS OPENNSOCKET CLOSENSOCKET NSOCKETEVENT NSOCKETFROMNUMBER \FLUSHNSOCQUEUE)
		       (INITVARS (\NSOCKETS)
				 (\MAX.EPKTS.ON.NSOCKET 16)))
		 (COMS (* assorted level 1 and 2)
		       (FNS \NSINIT STOPNS)
		       (FNS \HANDLE.RAW.XIP \XIPERROR \FORWARD.XIP)
		       (COMS (INITVARS (\NS.CHECKSUMFLG T))
			     (GLOBALVARS \NS.CHECKSUMFLG))
		       (FNS GETXIP DISCARDXIPS SENDXIP SWAPXIPADDRESSES \SETXIPCHECKSUM 
			    \CLEARXIPHEADER)
		       (GLOBALRESOURCES (\ROUTEBOX.HOST (create NSHOSTNUMBER)))
		       (FNS \FILLINXIP XIPAPPEND.BYTE XIPAPPEND.WORD XIPAPPEND.CELL XIPAPPEND.STRING 
			    XIPAPPEND.IFSSTRING XIPAPPEND.INTEGER))
		 (COMS (* XIP routing)
		       (FNS \NSGATELISTENER \HANDLE.NS.ROUTING.INFO \ROUTE.XIP \LOCATE.NSNET)
		       (INITVARS (\NS.ROUTING.TABLE NIL)
				 (\NS.ROUTING.TABLE.RADIUS 5)
				 (\NSROUTER.PROBECOUNT 0)
				 (\NSROUTER.PROBETIMER)
				 (\NSROUTER.PROBEINTERVAL 3000)
				 (\NS.READY)
				 (\NS.READY.EVENT (CREATE.EVENT "NS Ready")))
		       (ADDVARS (\SYSTEMCACHEVARS \NS.READY))
		       (DECLARE: DONTCOPY (RECORDS NSROUTINGINFO)
				 (CONSTANTS \NS.ROUTINGINFO.WORDS)
				 (GLOBALVARS \NS.ROUTING.TABLE \NS.ROUTING.TABLE.RADIUS 
					     \NSROUTER.PROBECOUNT \NSROUTER.PROBETIMER 
					     \NSROUTER.PROBEINTERVAL \NS.READY \NS.READY.EVENT)))
		 (COMS (* Analogous to PUP stuff for tracing activity.)
		       (FNS XIPTRACE)
		       (FNS PRINTXIP PRINTERRORXIP PRINTXIPROUTE PRINTXIPDATA)
		       (INITVARS (XIPTRACEFLG)
				 (XIPTRACEFILE T)
				 (XIPTRACETIME))
		       (ALISTS (XIPONLYTYPES)
			       (XIPIGNORETYPES)
			       (XIPPRINTMACROS 1 2 3 4))
		       (PROP VARTYPE XIPPRINTMACROS)
		       (ADDVARS (\PACKET.PRINTERS (1536 . PRINTXIP)))
		       (DECLARE: DONTCOPY (RECORDS ERRORXIP)
				 (GLOBALVARS XIPTRACEFLG XIPTRACEFILE XIPIGNORETYPES XIPONLYTYPES 
					     XIPTRACETIME XIPPRINTMACROS)))
		 [COMS (* Peeking)
		       (FNS \PEEKNS \MAYBEPEEKNS)
		       (GLOBALVARS \PEEKNSNUMBER)
		       (INITVARS (\PEEKNSNUMBER))
		       (COMS (FNS \PROMISCUOUS.ON \PROMISCUOUS.OFF)
			     (DECLARE: EVAL@COMPILE DONTCOPY (CONSTANTS \ETHERHOSTLOC]
		 (COMS (* Simple packet exchange protocols)
		       (FNS \GETMISCNSOCKET EXCHANGEXIPS \LOOKUPPUPNUMBER RELEASE.XIP)
		       [DECLARE: DONTEVAL@LOAD DOCOPY (P (AND (CCODEP (QUOTE \ALLOCATE.ETHERPACKET))
							      (MOVD (QUOTE \ALLOCATE.ETHERPACKET)
								    (QUOTE ALLOCATE.XIP)))
							 (AND (CCODEP (QUOTE \RELEASE.ETHERPACKET))
							      (MOVD (QUOTE \RELEASE.ETHERPACKET)
								    (QUOTE RELEASE.XIP]
		       (RECORDS PACKETEXCHANGEXIP)
		       (CONSTANTS (\EXTYPE.REQUEST 1)
				  (\EXTYPE.RESPONSE 2)
				  (\EXTYPE.NEGATIVE 3))
		       (GLOBALVARS \MISC.NSOCKET)
		       (INITVARS (\MISC.NSOCKET)))
		 (COMS (* Time service)
		       (FNS NSNETDAYTIME0 \NS.SETTIME NSNETDATE)
		       (DECLARE: DONTCOPY (RECORDS TIMEBODY)
				 (CONSTANTS \TIMESOCKET \TIMEOP.TIMEREQUEST \TIMEOP.TIMERESPONSE 
					    \TIMEVERSION \EXTYPE.TIME)))
		 (COMS (* Background activities)
		       (FNS NS.ECHOSERVER)
		       (DECLARE: DONTCOPY (CONSTANTS \XECHO.OP.REQUEST \XECHO.OP.REPLY 
						     \XROUTINGINFO.OP.REQUEST 
						     \XROUTINGINFO.OP.RESPONSE)))
		 (COMS (* Debugging)
		       (FNS NS.ECHOUSER)
		       (INITVARS (\DEFAULTECHOSERVER NIL)
				 (\NS.ECHOUSERSOCKET NIL)))
		 (DECLARE: DONTEVAL@LOAD DOCOPY (P (\NSINIT)))
		 (DECLARE: EVAL@COMPILE DONTCOPY (FILES (LOADCOMP)
							LLETHER))))



(* Xerox Internet Packet stuff.)

(DECLARE: DONTCOPY 
(* FOLLOWING DEFINITIONS EXPORTED)


[DECLARE: EVAL@COMPILE 

(ACCESSFNS XIP [(XIPBASE (LOCF (fetch (ETHERPACKET EPBODY) of DATUM]
	       [BLOCKRECORD XIPBASE ((XIPCHECKSUM WORD)
			     (XIPLENGTH WORD)
			     (XIPTCONTROL BYTE)
			     (XIPTYPE BYTE)
			     (XIPDESTNET FIXP)
			     (XIPDESTWORD1 3 WORD)
			     (XIPDESTSOCKET WORD)
			     (XIPSOURCENET FIXP)
			     (XIPSOURCEWORD1 3 WORD)
			     (XIPSOURCESOCKET WORD)
			     (XIPFIRSTDATAWORD WORD)         (* Start of data)
			     )
			    [ACCESSFNS XIPLENGTH ((XIPCHECKSUMBASE (LOCF DATUM]
			    [ACCESSFNS XIPFIRSTDATAWORD ((XIPCONTENTS (LOCF DATUM]
			    [ACCESSFNS XIPSOURCEWORD1 ((XIPSOURCEHOST (LOADNSHOSTNUMBER (LOCF DATUM))
								      (STORENSHOSTNUMBER
									(LOCF DATUM)
									NEWVALUE]
			    [ACCESSFNS XIPDESTWORD1 ((XIPDESTHOST (LOADNSHOSTNUMBER (LOCF DATUM))
								  (STORENSHOSTNUMBER (LOCF DATUM)
										     NEWVALUE]
			    [ACCESSFNS XIPSOURCENET ((XIPSOURCENSADDRESS (\LOADNSADDRESS
									   (LOCF DATUM))
									 (\STORENSADDRESS
									   (LOCF DATUM)
									   NEWVALUE]
			    (ACCESSFNS XIPDESTNET ((XIPDESTNSADDRESS (\LOADNSADDRESS (LOCF DATUM))
								     (\STORENSADDRESS (LOCF DATUM)
										      NEWVALUE]
	       (TYPE? (type? ETHERPACKET DATUM)))
]
(DECLARE: EVAL@COMPILE 

(RPAQQ \XIPOVLEN 30)

(RPAQQ \MAX.XIPDATALENGTH 546)

(CONSTANTS \XIPOVLEN \MAX.XIPDATALENGTH)
)

(RPAQQ RAWXIPTYPES ((\XIPT.ROUTINGINFO 1)
		    (\XIPT.ECHO 2)
		    (\XIPT.ERROR 3)
		    (\XIPT.EXCHANGE 4)
		    (\XIPT.SPP 5)
		    (\XIPT.PUPLOOKUP 6)))
(DECLARE: EVAL@COMPILE 

(RPAQQ \XIPT.ROUTINGINFO 1)

(RPAQQ \XIPT.ECHO 2)

(RPAQQ \XIPT.ERROR 3)

(RPAQQ \XIPT.EXCHANGE 4)

(RPAQQ \XIPT.SPP 5)

(RPAQQ \XIPT.PUPLOOKUP 6)

(CONSTANTS (\XIPT.ROUTINGINFO 1)
	   (\XIPT.ECHO 2)
	   (\XIPT.ERROR 3)
	   (\XIPT.EXCHANGE 4)
	   (\XIPT.SPP 5)
	   (\XIPT.PUPLOOKUP 6))
)


(* END EXPORTED DEFINITIONS)



(RPAQQ XIPERRORCODES ((\XIPE.CHECKSUM 1)
		      (\XIPE.NOSOCKET 2)
		      (\XIPE.SOCKETFULL 3)
		      (\XIPE.GATEWAY.CHECKSUM 513)
		      (\XIPE.NOROUTE 514)
		      (\XIPE.LOOPED 515)
		      (\XIPE.TOOLARGE 516)))
(DECLARE: EVAL@COMPILE 

(RPAQQ \XIPE.CHECKSUM 1)

(RPAQQ \XIPE.NOSOCKET 2)

(RPAQQ \XIPE.SOCKETFULL 3)

(RPAQQ \XIPE.GATEWAY.CHECKSUM 513)

(RPAQQ \XIPE.NOROUTE 514)

(RPAQQ \XIPE.LOOPED 515)

(RPAQQ \XIPE.TOOLARGE 516)

(CONSTANTS (\XIPE.CHECKSUM 1)
	   (\XIPE.NOSOCKET 2)
	   (\XIPE.SOCKETFULL 3)
	   (\XIPE.GATEWAY.CHECKSUM 513)
	   (\XIPE.NOROUTE 514)
	   (\XIPE.LOOPED 515)
	   (\XIPE.TOOLARGE 516))
)
)

(ADDTOVAR XIPTYPES (\XIPT.ROUTINGINFO 1)
		   (\XIPT.ECHO 2)
		   (\XIPT.ERROR 3)
		   (\XIPT.EXCHANGE 4)
		   (\XIPT.SPP 5)
		   (\XIPT.PUPLOOKUP 6))

(ADDTOVAR XIPERRORMESSAGES (1 "Bad checksum")
			   (2 "No socket at destination")
			   (3 "Destination congestion")
			   (513 "Gateway: Bad checksum")
			   (514 "Can't get there from here")
			   (515 "Too many hops")
			   (516 "Packet too large to forward"))
(DECLARE: DOEVAL@COMPILE DONTCOPY

(ADDTOVAR GLOBALVARS XIPTYPES XIPERRORMESSAGES)
)



(* Parsing and looking up NS addresses)

(DECLARE: DONTCOPY 
(DECLARE: EVAL@COMPILE 

(PUTPROPS \GPNCHAR MACRO [OPENLAMBDA (BAR)
				     (\GETBASEBYTE (FETCH (STRINGP BASE) OF BAR)
						   (SUB1 (FETCH (STRINGP OFFST) OF BAR])
)




(* Get Previous Numerical-valued CHARacter from string pointer)

)
(DEFINEQ

(\NS.FINDNSADDRESS
  [LAMBDA (HOST)                                             (* bvm: "12-OCT-83 16:22")
    (COND
      ((LITATOM HOST)
	(\PARSE.NSADDRESSCONSTANT (MKSTRING HOST)))
      ((type? NSADDRESS HOST)
	HOST)
      ((type? NSHOSTNUMBER HOST)
	(create NSADDRESS
		NSHOSTNUMBER ← HOST))
      ((STRINGP HOST)
	(\PARSE.NSADDRESSCONSTANT HOST])

(\PARSE.NSADDRESSCONSTANT
  [LAMBDA (STR)                                              (* JonL " 8-AUG-82 04:35")
                                                             (* If STR is a constant NS address of form 
							     net#host#socket, or net#host#, or net#host, or host# 
							     then returns an NSADDRESS, else NIL)
    (OR (STRINGP STR)
	(SHOULDNT STR))
    (SETQ STR (SUBSTRING STR 1))                             (* Copies string pointer)
    (PROG ((NET 0)
	   (HOST 0)
	   (SOC# 0)
	   VAL CH)
          (if [NOT (FIXP (SETQ CH (NTHCHAR STR 1]
	      then (if (EQ CH (QUOTE #))
		       then (GNC STR)
		     else (RETURN)))
          (if (NOT (FIXP (NTHCHAR STR 1)))
	      then (RETURN))
          (if (NULL (SETQ VAL (\PARSEANUM STR)))
	      then (RETURN)
	    elseif (EQ 0 (NCHARS STR))
	      then (OR (EQ (\GPNCHAR STR)
			   (CHARCODE #))
		       (RETURN))
		   (SETQ HOST VAL)
		   (GO DONE))
          (SETQ NET VAL)
          (if (NULL (SETQ VAL (\PARSEANUM STR)))
	      then (RETURN))
          (SETQ HOST VAL)
          (if (NEQ 0 (NCHARS STR))
	      then (SETQ SOC# (\PARSEANUM STR))
		   (if (OR (NULL SOC#)
			   (EQ (\GPNCHAR STR)
			       (CHARCODE #)))
		       then (RETURN)))
      DONE(RETURN (create NSADDRESS
			  NSNET ← NET
			  NSHNM0 ← 0
			  NSHNM1 ←(\HINUM HOST)
			  NSHNM2 ←(\LONUM HOST)
			  NSSOCKET ← SOC#])

(\PARSEANUM
  [LAMBDA (STR)                                              (* bvm: " 1-FEB-83 15:51")
                                                             (* GNC from STR, accumulating a FIXP, stopping when # or
							     end of string seen.)
    (PROG ((N 0)
	   N1 N2 N3 CH)
      START
          [while (AND (FIXP (SETQ CH (GNC STR)))
		      (ILEQ 0 CH)
		      (ILEQ CH 7))
	     do (SETQ N (IPLUS CH (if N
				      then (LLSH N 3)
				    else 0]                  (* Accumulate digits)
          (if (EQ CH (QUOTE %.))
	      then (if (NULL N1)
		       then (SETQ N1 N)
		     elseif (NULL N2)
		       then (SETQ N2 N)
		     elseif (NULL N3)
		       then (SETQ N3 N))
		   (SETQ N)
		   (GO START)
	    elseif [NOT (MEMB CH (QUOTE (# NIL]
	      then                                           (* Losing format)
		   (RETURN))
          (RETURN (COND
		    ((NULL N1)
		      N)
		    ((NULL N2)
		      (\MAKENUMBER N1 N))
		    [(NULL N3)
		      (COND
			((EQ 0 N1)
			  (\MAKENUMBER N2 N]
		    (T (HELP])
)



(* New SOCKET datatype stuff)

(DECLARE: DONTCOPY 
(* FOLLOWING DEFINITIONS EXPORTED)


[DECLARE: EVAL@COMPILE 

(DATATYPE NSOCKET ((NIL BYTE)
		   (NSOCLINK POINTER)                        (* So that we can Queue them)
		   (ID# WORD)
		   (NSOCHANDLE WORD)
		   (NSOC#OPENP FLAG)
		   (NSOC#CONNECTIONP FLAG)
		   (NIL BITS 6)
		   (INQUEUE POINTER)
		   (INQUEUELENGTH WORD)
		   (NSOC#ALLOCATION WORD)
		   (NSOCEVENT POINTER))
		  INQUEUE ←(create SYSQUEUE)
		  NSOC#ALLOCATION ← \MAX.EPKTS.ON.NSOCKET)
]
(/DECLAREDATATYPE (QUOTE NSOCKET)
		  (QUOTE (BYTE POINTER WORD WORD FLAG FLAG (BITS 6)
			       POINTER WORD WORD POINTER)))



(* Well-known NS sockets)

(DECLARE: EVAL@COMPILE 

(RPAQQ \NS.WKS.RoutingInformation 1)

(RPAQQ \NS.WKS.Echo 2)

(RPAQQ \NS.WKS.RouterError 3)

(RPAQQ \NS.WKS.Courier 5)

(RPAQQ \NS.WKS.PUPLOOKUP 9)

(CONSTANTS (\NS.WKS.RoutingInformation 1)
	   (\NS.WKS.Echo 2)
	   (\NS.WKS.RouterError 3)
	   (\NS.WKS.Courier 5)
	   (\NS.WKS.PUPLOOKUP 9))
)


(* END EXPORTED DEFINITIONS)


(DECLARE: DOEVAL@COMPILE DONTCOPY

(ADDTOVAR GLOBALVARS \NSOCKETS \MAX.EPKTS.ON.NSOCKET)
)

(DECLARE: EVAL@COMPILE 

(PUTPROPS \NSOCKET.FROM# MACRO (OPENLAMBDA (SOCNUM)
					   (for SOC in \NSOCKETS when (EQ SOCNUM
									  (fetch ID# of SOC))
					      do (RETURN SOC))))
)
)
(/DECLAREDATATYPE (QUOTE NSOCKET)
		  (QUOTE (BYTE POINTER WORD WORD FLAG FLAG (BITS 6)
			       POINTER WORD WORD POINTER)))
[ADDTOVAR SYSTEMRECLST

(DATATYPE NSOCKET ((NIL BYTE)
		   (NSOCLINK POINTER)
		   (ID# WORD)
		   (NSOCHANDLE WORD)
		   (NSOC#OPENP FLAG)
		   (NSOC#CONNECTIONP FLAG)
		   (NIL BITS 6)
		   (INQUEUE POINTER)
		   (INQUEUELENGTH WORD)
		   (NSOC#ALLOCATION WORD)
		   (NSOCEVENT POINTER)))
]
(DEFINEQ

(OPENNSOCKET
  [LAMBDA (SKT# IFCLASH)                                     (* bvm: " 7-SEP-83 21:45")

          (* Creates a new local NSOCKET If SKT# is supplied, it is the identifying number (16-bit) of the socket, and an 
	  error occurs if that socket is already in use.)


    (PROG ((ID#EXPLICIT? (FIXP SKT#))
	   NSOC CLASHP)
          [COND
	    ((type? NSOCKET SKT#)
	      (SETQ NSOC (OR (\NSOCKET.FROM# (fetch ID# of SKT#))
			     (PROGN (push \NSOCKETS SKT#)
				    SKT#)))
	      (\FLUSHNSOCQUEUE NSOC))
	    (T [COND
		 ((NOT ID#EXPLICIT?)                         (* Pick a socket that is reasonably random but won't 
							     conflict with well-known sockets)
		   (SETQ SKT# (LOGOR 32768 (\LONUM (DAYTIME]
	       (UNINTERRUPTABLY
                   [do (COND
			 ((NOT (SETQ CLASHP (\NSOCKET.FROM# SKT#)))
			   (push \NSOCKETS (SETQ NSOC (create NSOCKET
							      ID# ← SKT#)))
			   (replace NSOCEVENT of NSOC with (CREATE.EVENT NSOC))
			   (RETURN))
			 [(NOT ID#EXPLICIT?)
			   (SETQ SKT# (LOGOR 32768 (ADD1 (LOGAND SKT# 32767]
			 (T (RETURN])
	       (COND
		 (CLASHP (SELECTQ IFCLASH
				  ((T ACCEPT)
				    (\FLUSHNSOCQUEUE (SETQ NSOC CLASHP)))
				  ((DON'T FAIL)
				    (RETURN NIL))
				  (ERROR "Socket number is already in use" SKT#]
          (RETURN NSOC])

(CLOSENSOCKET
  [LAMBDA (NSOC NOERRORFLG)                                  (* bvm: "26-MAY-83 14:11")
                                                             (* Closes a local NSOCKET -- argument = T means close 
							     all sockets)
    (COND
      [(EQ NSOC T)
	(while \NSOCKETS do (UNINTERRUPTABLY
                                (\FLUSHNSOCQUEUE (SETQ NSOC (pop \NSOCKETS)))
				(replace NSOCEVENT of NSOC with NIL))]
      (T (SETQ NSOC (\DTEST NSOC (QUOTE NSOCKET)))
	 (UNINTERRUPTABLY
             (\FLUSHNSOCQUEUE NSOC)
	     (replace NSOCEVENT of NSOC with NIL)            (* Break circular link)
	     (COND
	       ((FMEMB NSOC \NSOCKETS)
		 (SETQ \NSOCKETS (DREMOVE NSOC \NSOCKETS))
		 T)
	       ((NOT NOERRORFLG)
		 (ERROR NSOC "not an open NS socket"))))])

(NSOCKETEVENT
  [LAMBDA (NSOC)                                             (* bvm: "26-MAY-83 14:14")
    (ffetch NSOCEVENT of (\DTEST NSOC (QUOTE NSOCKET])

(NSOCKETFROMNUMBER
  [LAMBDA (SOC#)                                             (* bvm: " 7-AUG-83 01:40")
    (\NSOCKET.FROM# SOC#])

(\FLUSHNSOCQUEUE
  [LAMBDA (NSOC)                                             (* bvm: "11-FEB-83 12:56")
    (\FLUSH.PACKET.QUEUE (fetch (NSOCKET INQUEUE) of NSOC))
    (replace (NSOCKET INQUEUELENGTH) of NSOC with 0)
    NSOC])
)

(RPAQ? \NSOCKETS )

(RPAQ? \MAX.EPKTS.ON.NSOCKET 16)



(* assorted level 1 and 2)

(DEFINEQ

(\NSINIT
  [LAMBDA (EVENT MINI)                                       (* bvm: "28-OCT-83 13:58")
                                                             (* MINI means just enough to broadcast packets and 
							     receive answers. Used by \LOOKUPPUPNUMBER)
    (for SOC in \NSOCKETS do (\FLUSHNSOCQUEUE SOC))
    (\ADD.PACKET.FILTER (FUNCTION \HANDLE.RAW.XIP))
    [PROG [(PROC (FIND.PROCESS (QUOTE \NSGATELISTENER]
          (OR \LOCALNDBS (RETURN))
          (COND
	    ((NULL MINI)
	      [COND
		(\3MBLOCALNDB                                (* If we want to talk XIPs on 3mb net, we need to be 
							     able to handle translations)
			      (\ADD.PACKET.FILTER (FUNCTION \HANDLE.RAW.10TO3)))
		(T (\DEL.PACKET.FILTER (FUNCTION \HANDLE.RAW.10TO3]
                                                             (* Initiate router probe to find out what our net is)
	      (\LOCATE.NSNET 0)
	      (COND
		(\GATEWAYFLG (AND PROC (DEL.PROCESS PROC)))
		(PROC (RESTART.PROCESS PROC))
		(T (ADD.PROCESS (QUOTE (\NSGATELISTENER))
				(QUOTE RESTARTABLE)
				(QUOTE SYSTEM)
				(QUOTE AFTEREXIT)
				\NS.READY.EVENT)))
	      (SETQ \NSFLG T]
    (SETQ \NS.READY T)
    (NOTIFY.EVENT \NS.READY.EVENT])

(STOPNS
  [LAMBDA NIL                                                (* bvm: "17-FEB-83 15:57")
    (\DEL.PACKET.FILTER (FUNCTION \HANDLE.RAW.XIP))
    (\DEL.PACKET.FILTER (FUNCTION \HANDLE.RAW.10TO3))
    (DEL.PROCESS (QUOTE \NSGATELISTENER))
    (CLOSENSOCKET T)
    (SETQ \NSFLG NIL])
)
(DEFINEQ

(\HANDLE.RAW.XIP
  [LAMBDA (XIP TYPE)                                         (* bvm: "28-Nov-83 17:59")

          (* Handles the arrival of a raw XIP. If it is destined for a local socket that has room for it, we queue it up, 
	  else release it)


    (COND
      ((EQ TYPE \EPT.XIP)
	[PROG (NSOC CSUM NDB DESTNET MYNET)
	      [COND
		((NULL \NS.READY)
		  (RETURN (RELEASE.XIP XIP]
	      [COND
		((AND (NOT (EQNSHOSTNUMBER (fetch XIPDESTHOST of XIP)
					   \MY.NSHOSTNUMBER))
		      (NOT (EQNSHOSTNUMBER (fetch XIPDESTHOST of XIP)
					   BROADCASTNSHOSTNUMBER)))
                                                             (* Not for us)
		  (RETURN (\FORWARD.XIP XIP]
	      (SETQ NDB (fetch EPNETWORK of XIP))
	      [COND
		((AND [NOT (IEQP (SETQ DESTNET (fetch XIPDESTNET of XIP))
				 (SETQ MYNET (fetch NDBNSNET# of NDB]
		      (NOT (ZEROP MYNET))
		      (NOT (ZEROP DESTNET)))                 (* explicitly for a net other than us)
		  (RETURN (\FORWARD.XIP XIP]
	      (COND
		[[NULL (SETQ NSOC (\NSOCKET.FROM# (fetch XIPDESTSOCKET of XIP]
                                                             (* Packets addressed to non-active sockets are just 
							     ignored.)
		  (COND
		    (XIPTRACEFLG (PRIN1 (QUOTE &)
					XIPTRACEFILE)))
		  (PROG (XIPBASE)
		        (COND
			  [(AND (EQ (fetch XIPTYPE of XIP)
				    \XIPT.ECHO)
				(EQ (fetch XIPDESTSOCKET of XIP)
				    \NS.WKS.Echo)
				(EQ (\GETBASE (SETQ XIPBASE (fetch XIPCONTENTS of XIP))
					      0)
				    \XECHO.OP.REQUEST))      (* Play echo server)
			    (COND
			      ([AND (NEQ (SETQ CSUM (fetch XIPCHECKSUM of XIP))
					 MASKWORD1'S)
				    (NEQ CSUM (\CHECKSUM (fetch XIPCHECKSUMBASE of XIP)
							 (SUB1 (FOLDHI (fetch XIPLENGTH of XIP)
								       BYTESPERWORD]
				(\XIPERROR XIP \XIPE.CHECKSUM))
			      (T (\PUTBASE XIPBASE 0 \XECHO.OP.REPLY)
				 (SWAPXIPADDRESSES XIP)
				 (replace EPREQUEUE of XIP with (QUOTE FREE))
				 (SENDXIP NIL XIP]
			  (T (\XIPERROR XIP \XIPE.NOSOCKET]
		((IGEQ (fetch (NSOCKET INQUEUELENGTH) of NSOC)
		       (fetch (NSOCKET NSOC#ALLOCATION) of NSOC))
                                                             (* Note that packets are just "dropped" when the queue 
							     overflows.)
		  (\XIPERROR XIP \XIPE.SOCKETFULL))
		([AND \NS.CHECKSUMFLG (NEQ (SETQ CSUM (fetch XIPCHECKSUM of XIP))
					   MASKWORD1'S)
		      (NEQ CSUM (\CHECKSUM (fetch XIPCHECKSUMBASE of XIP)
					   (SUB1 (FOLDHI (fetch XIPLENGTH of XIP)
							 BYTESPERWORD]
		  (\XIPERROR XIP \XIPE.CHECKSUM))
		(T [COND
		     ((ZEROP DESTNET)                        (* Fill in unspecified destination net 
							     (possibly redundantly with zero))
		       (replace XIPDESTNET of XIP with MYNET))
		     ((ZEROP MYNET)

          (* Packet of specific destination net has arrived on a socket that we listen to. If we don't know our own net 
	  number, assume sender is telling the truth)


		       (replace NDBNSNET# of NDB with DESTNET)
		       (PROG ((ENTRY (\LOCATE.NSNET DESTNET T)))
			     [OR ENTRY (push (CDR \NS.ROUTING.TABLE)
					     (SETQ ENTRY (create ROUTING
								 RTNET# ← DESTNET]
			     (replace RTHOPCOUNT of ENTRY with 0)
			     (replace RTGATEWAY# of ENTRY with NIL)
			     (replace RTNDB of ENTRY with NDB)
			     (replace RTRECENT of ENTRY with T]
		   (UNINTERRUPTABLY
                       (\ENQUEUE (fetch (NSOCKET INQUEUE) of NSOC)
				 XIP)
		       (add (fetch (NSOCKET INQUEUELENGTH) of NSOC)
			    1)
		       (NOTIFY.EVENT (fetch NSOCEVENT of NSOC)))]
	T])

(\XIPERROR
  [LAMBDA (XIP ERRCODE)                                      (* bvm: "19-FEB-83 20:00")

          (* * Turn packet around into an error packet with given error)


    [COND
      ((AND (NOT (EQNSHOSTNUMBER (fetch XIPDESTHOST of XIP)
				 BROADCASTNSHOSTNUMBER))
	    (NEQ (fetch XIPTYPE of XIP)
		 \XIPT.ERROR))                               (* Don't respond to errors or to broadcasts!)
	(COND
	  ((AND XIPTRACEFLG (NEQ XIPTRACEFLG (QUOTE PEEK)))
	    (printout XIPTRACEFILE "Incoming packet dropped because: "
		      (OR (CADR (ASSOC ERRCODE XIPERRORMESSAGES))
			  ERRCODE)
		      T)
	    (OR (EQ XIPTRACEFLG (QUOTE RAW))
		(PRINTXIP XIP]
    (\RELEASE.ETHERPACKET XIP])

(\FORWARD.XIP
  [LAMBDA (XIP)                                              (* bvm: "12-OCT-83 15:44")
                                                             (* Called when we receive a XIP not addressed to us.
							     Unless we are a gateway, dump it)
    (COND
      (\GATEWAYFLG (\GATEWAY.FORWARD.XIP XIP))
      (\PEEKNSNUMBER (\MAYBEPEEKNS XIP))
      (T (COND
	   (XIPTRACEFLG (PRINTXIP XIP (QUOTE GET)
				  NIL "XIP not addressed to this host: ")))
	 (\RELEASE.ETHERPACKET XIP])
)

(RPAQ? \NS.CHECKSUMFLG T)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(ADDTOVAR GLOBALVARS \NS.CHECKSUMFLG)
)
(DEFINEQ

(GETXIP
  [LAMBDA (NSOC WAIT)                                        (* bvm: "26-MAY-83 15:48")
    (PROG ([NSOCQ (ffetch (NSOCKET INQUEUE) of (\DTEST NSOC (QUOTE NSOCKET]
	   EPKT TIMER)
      LP  (UNINTERRUPTABLY
              (AND (SETQ EPKT (\DEQUEUE NSOCQ))
		   (add (ffetch (NSOCKET INQUEUELENGTH) of NSOC)
			-1)))
          (COND
	    [(NULL EPKT)
	      (COND
		(WAIT (COND
			((EQ WAIT T))
			[TIMER (COND
				 ((TIMEREXPIRED? TIMER)
				   (RETURN]
			(T (OR (FIXP WAIT)
			       (LISPERROR "NON-NUMERIC ARG" WAIT))
			   (SETQ TIMER (SETUPTIMER WAIT))
			   T))
		      (AWAIT.EVENT (ffetch NSOCEVENT of NSOC)
				   TIMER T)
		      (GO LP]
	    [(EQ \EPT.XIP (fetch EPTYPE of EPKT))
	      (AND XIPTRACEFLG (\MAYBEPRINTPACKET EPKT (QUOTE GET]
	    (T (AND XIPTRACEFLG (printout XIPTRACEFILE T "Non-XIP packet " EPKT " arrived on " NSOC T)
		    )
	       (SETQ EPKT)))
          (RETURN EPKT])

(DISCARDXIPS
  [LAMBDA (NSOC)                                             (* bvm: "11-FEB-83 12:56")
    (UNINTERRUPTABLY
        (\FLUSH.PACKET.QUEUE (fetch (NSOCKET INQUEUE) of NSOC))
	(replace (NSOCKET INQUEUELENGTH) of NSOC with 0))])

(SENDXIP
  [LAMBDA (SOCKET XIP)                                       (* bvm: "26-OCT-83 16:31")
                                                             (* Returns the XIP arg iff packet can be sent;
							     returns a litatom explaining error otherwise)
    (replace EPTYPE of XIP with \EPT.XIP)
    (SETQ XIP (\DTEST XIP (QUOTE ETHERPACKET)))
    (replace XIPTCONTROL of XIP with 0)
    (until \NS.READY do (AWAIT.EVENT \NS.READY.EVENT))
    (PROG (NDB)
          (\RCLK (LOCF (fetch EPTIMESTAMP of XIP)))
          (RETURN (COND
		    ((fetch EPTRANSMITTING of XIP)
		      (AND XIPTRACEFLG (printout XIPTRACEFILE 
						 "[Put failed--packet already being transmitted]"))
		      (QUOTE AlreadyQueued))
		    ((NULL (SETQ NDB (\ROUTE.XIP XIP)))
		      (AND XIPTRACEFLG (PRINTXIPROUTE XIP "[Put fails--no routing]" XIPTRACEFILE))
		      (\REQUEUE.ETHERPACKET XIP)
		      (QUOTE NoRouting))
		    (T (\SETXIPCHECKSUM XIP)
		       (AND XIPTRACEFLG (\MAYBEPRINTPACKET XIP (QUOTE PUT)))
		       (TRANSMIT.ETHERPACKET NDB XIP)
		       NIL])

(SWAPXIPADDRESSES
  [LAMBDA (XIP)                                              (* bvm: "28-Nov-83 17:59")
    (SETQ XIP (\DTEST XIP (QUOTE ETHERPACKET)))
    (PROG ((NDB (\DTEST (ffetch EPNETWORK of XIP)
			(QUOTE NDB)))
	   (DESTSOCKET (ffetch XIPDESTSOCKET of XIP)))
          (\BLT (LOCF (ffetch XIPDESTNET of XIP))
		(LOCF (ffetch XIPSOURCENET of XIP))
		\#WDS.NSADDRESS)
          (freplace XIPSOURCESOCKET of XIP with DESTSOCKET)
          (freplace XIPSOURCENET of XIP with (ffetch NDBNSNET# of NDB))
          (freplace XIPSOURCEHOST of XIP with \MY.NSHOSTNUMBER])

(\SETXIPCHECKSUM
  [LAMBDA (XIP)                                              (* bvm: " 6-FEB-83 18:43")
                                                             (* Sets the XIPCHECKSUM field of XIP to checksum over 
							     its current contents)
    (replace XIPCHECKSUM of XIP with (COND
				       [\NS.CHECKSUMFLG (\CHECKSUM (fetch XIPCHECKSUMBASE
								      of XIP)
								   (SUB1 (FOLDHI (fetch XIPLENGTH
										    of XIP)
										 BYTESPERWORD]
				       (T \NULLCHECKSUM)))
    T])

(\CLEARXIPHEADER
  [LAMBDA (XIP)                                              (* bvm: "16-FEB-83 15:07")
                                                             (* Clears the header of XIP)
    (\ZEROWORDS [fetch XIPBASE of (SETQ XIP (\DTEST XIP (QUOTE ETHERPACKET]
		(LOCF (fetch XIPFIRSTDATAWORD of XIP])
)

(RPAQQ \ROUTEBOX.HOST NIL)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(ADDTOVAR GLOBALVARS \ROUTEBOX.HOST)
)
(DECLARE: DOEVAL@COMPILE DONTCOPY 
(PUTDEF (QUOTE \ROUTEBOX.HOST)
	(QUOTE GLOBALRESOURCES)
	(QUOTE (create NSHOSTNUMBER)))
)
(DEFINEQ

(\FILLINXIP
  [LAMBDA (TYPE SOURCENSOCKET DESTHOST DESTSOCKET# DESTNET LENGTH EPKT)
                                                             (* lmm "11-JUN-83 22:28")
                                                             (* Sets indicated fields of EPKT to non-NIL args.
							     DESTHOST may be either an NSADDRESS or a NSHOSTNUMBER)
    (PROG NIL
          (COND
	    ((NULL EPKT)
	      (SETQ EPKT (\ALLOCATE.ETHERPACKET))
	      (replace EPTYPE of EPKT with \EPT.XIP)
	      (\CLEARXIPHEADER EPKT)
	      (OR LENGTH (SETQ LENGTH \XIPOVLEN)))
	    (T (SETQ EPKT (\DTEST EPKT (QUOTE ETHERPACKET)))
	       (replace EPTYPE of EPKT with \EPT.XIP)))
          (replace XIPTCONTROL of EPKT with 0)               (* Always zero when transmitted)
          (replace XIPTYPE of EPKT with (OR TYPE 0))
          (replace XIPSOURCENSADDRESS of EPKT with (\LOCALNSADDRESS))
                                                             (* Will put 0 in the socket field)
          (AND SOURCENSOCKET (replace XIPSOURCESOCKET of EPKT with (fetch (NSOCKET ID#) of 
										    SOURCENSOCKET)))
          (replace XIPLENGTH of EPKT with (OR LENGTH \XIPOVLEN))
          (COND
	    ((type? NSADDRESS DESTHOST)
	      (replace XIPDESTNSADDRESS of EPKT with DESTHOST))
	    ((type? NSHOSTNUMBER DESTHOST)                   (* Just doesn't put anything in the NET or DESTSOCKET# 
							     fields)
	      (replace XIPDESTHOST of EPKT with DESTHOST))
	    (T (SETQ DESTHOST (OR (COND
				    ((LITATOM DESTHOST)
				      (\PARSE.NSADDRESSCONSTANT (MKSTRING DESTHOST)))
				    ((STRINGP DESTHOST)
				      (\PARSE.NSADDRESSCONSTANT DESTHOST)))
				  (ERROR DESTHOST "Isn't a valid DestinationHost specificaton.")))
	       (replace XIPDESTNSADDRESS of EPKT with DESTHOST)))
          (AND (FIXP DESTNET)
	       (replace XIPDESTNET of EPKT with DESTNET))
          (AND DESTSOCKET# (replace XIPDESTSOCKET of EPKT with DESTSOCKET#))
          (AND (IGREATERP (fetch XIPLENGTH of EPKT)
			  0)
	       (\SETXIPCHECKSUM EPKT))
          (RETURN EPKT])

(XIPAPPEND.BYTE
  [LAMBDA (XIP BYTE OFFSET)                                  (* bvm: "16-FEB-83 15:09")
                                                             (* Make OFFSET'th byte of XIP'S data be BYTE.
							     OFFSET defaults to the end of the packet, in which case 
							     the length is updated)
    (SETQ XIP (\DTEST XIP (QUOTE ETHERPACKET)))
    (PROG [(WHERE (OR OFFSET (IDIFFERENCE (fetch XIPLENGTH of XIP)
					  \XIPOVLEN]
          (COND
	    ((IGEQ WHERE \MAX.XIPDATALENGTH)
	      (RETURN)))
          (COND
	    ((NOT OFFSET)
	      (add (fetch XIPLENGTH of XIP)
		   1)))
          (\PUTBASEBYTE (fetch XIPCONTENTS of XIP)
			WHERE BYTE])

(XIPAPPEND.WORD
  [LAMBDA (XIP WORD OFFSET)                                  (* bvm: "16-FEB-83 15:11")
                                                             (* Make OFFSET'th word of XIP'S data be WORD.
							     OFFSET defaults to the end of the packet, in which case 
							     the length is updated)
    (SETQ XIP (\DTEST XIP (QUOTE ETHERPACKET)))
    (PROG (LENGTH WHERE)
          [SETQ WHERE (COND
	      (OFFSET (UNFOLD OFFSET BYTESPERWORD))
	      (T (IDIFFERENCE (SETQ LENGTH (CEIL (fetch XIPLENGTH of XIP)
						 BYTESPERWORD))
			      \XIPOVLEN]
          (COND
	    ((IGREATERP (IPLUS WHERE BYTESPERWORD)
			\MAX.XIPDATALENGTH)
	      (ERROR XIP "Not enough room for another word")))
          [COND
	    ((NOT OFFSET)
	      (replace XIPLENGTH of XIP with (IPLUS LENGTH BYTESPERWORD]
          (\PUTBASE (fetch XIPCONTENTS of XIP)
		    (FOLDLO WHERE BYTESPERWORD)
		    WORD])

(XIPAPPEND.CELL
  [LAMBDA (XIP CELL OFFSET)                                  (* bvm: "16-FEB-83 15:13")

          (* Word-aligns the beginning, and puts down two words (a "cell", or LONG CARDINAL). OFFSET defaults to the end of 
	  the packet, in which case the length is updated)


    (SETQ XIP (\DTEST XIP (QUOTE ETHERPACKET)))
    (PROG (LENGTH WHERE)
          [SETQ WHERE (COND
	      (OFFSET (UNFOLD OFFSET BYTESPERWORD))
	      (T (IDIFFERENCE (SETQ LENGTH (CEIL (fetch XIPLENGTH of XIP)
						 BYTESPERWORD))
			      \XIPOVLEN]
          (COND
	    ((IGREATERP (IPLUS WHERE BYTESPERCELL)
			\MAX.XIPDATALENGTH)
	      (ERROR XIP "Not enough room for another word")))
          [COND
	    ((NOT OFFSET)
	      (replace XIPLENGTH of XIP with (IPLUS LENGTH BYTESPERCELL]
          (SETQ WHERE (\ADDBASE (fetch XIPCONTENTS of XIP)
				(FOLDLO WHERE BYTESPERWORD)))
          (\PUTBASE WHERE 0 (\HINUM CELL))
          (\PUTBASE WHERE 1 (\LONUM CELL])

(XIPAPPEND.STRING
  [LAMBDA (EPKT STRING OFFST IFSP)                           (* bvm: " 4-FEB-83 12:00")

          (* Store STRING beginning at OFFST'th byte of XIP. OFFST defaults to end of packet, in which case the packet's 
	  XIPLENGTH accordingly. IFSP means to store the string in IFS format -- the length word preceeds the string bytes.)


    (OR (STRINGP STRING)
	(LITATOM STRING)
	(SETQ STRING (MKSTRING STRING)))
    (PROG ((LEN (NCHARS STRING))
	   WHERE)
          (SETQ WHERE (OR OFFST (IDIFFERENCE (fetch XIPLENGTH of EPKT)
					     \XIPOVLEN)))
          [COND
	    (IFSP (SETQ WHERE (CEIL WHERE BYTESPERWORD))
		  (COND
		    ((ILESSP \MAX.XIPDATALENGTH (IPLUS WHERE LEN BYTESPERWORD))
		      (RETURN)))
		  (\PUTBASE (fetch XIPCONTENTS of EPKT)
			    (FOLDLO WHERE BYTESPERWORD)
			    LEN)
		  (add WHERE BYTESPERWORD)
		  (add LEN BYTESPERWORD))
	    (T (COND
		 ((ILESSP \MAX.XIPDATALENGTH (IPLUS WHERE LEN))
		   (RETURN]
          (COND
	    ((NULL OFFST)
	      (add (fetch XIPLENGTH of EPKT)
		   LEN)))
          (RETURN (\PUTBASESTRING (fetch XIPCONTENTS of EPKT)
				  WHERE STRING])

(XIPAPPEND.IFSSTRING
  [LAMBDA (XIP STRING OFFST)                                 (* JonL "31-JUL-82 03:40")

          (* Store STRING as an IFS string (length word followed by string) beginning at OFFST'th byte of XIP.
	  OFFST defaults to end of packet, in which case the packet's XIPLENGTH is updated accordingly)


    (XIPAPPEND.STRING XIP STRING OFFST T])

(XIPAPPEND.INTEGER
  [LAMBDA (XIP N #BITS ALIGNMENT)                            (* bvm: " 6-FEB-83 17:08")
    (PROG ((#IBYTES (FOLDHI #BITS BITSPERBYTE))
	   LEN NEWLEN CURBASE)
          (SETQ NEWLEN (SETQ LEN (fetch XIPLENGTH of XIP)))
          (SELECTQ ALIGNMENT
		   ((NIL BYTE 0 1))
		   ((WORD 2)
		     (SETQ NEWLEN (CEIL NEWLEN BYTESPERWORD))
		     (SETQ #IBYTES (CEIL #IBYTES BYTESPERWORD)))
		   ((CELL 4)
		     (SETQ NEWLEN (CEIL NEWLEN BYTESPERCELL))
		     (SETQ #IBYTES (CEIL #IBYTES BYTESPERCELL)))
		   (PROGN (add NEWLEN (IDIFFERENCE (SUB1 ALIGNMENT)
						   (IMOD (SUB1 NEWLEN)
							 ALIGNMENT)))
                                                             (* FOO -- CEIL macro only works for constant modulii!)
			  NIL))
          (\PUTBASEINTEGER (fetch XIPCONTENTS of XIP)
			   (UNFOLD (IPLUS NEWLEN #IBYTES)
				   BITSPERBYTE)
			   (UNFOLD #IBYTES BITSPERBYTE)
			   N)
          (add NEWLEN #IBYTES)
          (replace XIPLENGTH of XIP with NEWLEN)
          (RETURN (IDIFFERENCE NEWLEN LEN])
)



(* XIP routing)

(DEFINEQ

(\NSGATELISTENER
  [LAMBDA NIL                                                (* bvm: "10-JUN-83 11:24")
    (PROG ((NSOC (OPENNSOCKET \NS.WKS.RoutingInformation T))
	   (TIMER (SETUPTIMER 0))
	   EVENT XIP BASE)
          (SETQ EVENT (fetch NSOCEVENT of NSOC))
      LP  (COND
	    ((SETQ XIP (GETXIP NSOC))
	      (\HANDLE.NS.ROUTING.INFO XIP)
	      (BLOCK))
	    ((EQ (AWAIT.EVENT EVENT (COND
				((IGREATERP \NSROUTER.PROBECOUNT 0)
				  \NSROUTER.PROBETIMER)
				(T TIMER))
			      T)
		 EVENT)
	      (GO LP)))
          (COND
	    ((TIMEREXPIRED? TIMER)
	      (\AGE.ROUTING.TABLE \NS.ROUTING.TABLE)
	      (SETUPTIMER \RT.AGEINTERVAL TIMER)))
          [COND
	    ((AND (IGREATERP \NSROUTER.PROBECOUNT 0)
		  (TIMEREXPIRED? \NSROUTER.PROBETIMER))      (* Routing info desired. Broadcast a routing request on 
							     each directly-connected net)
	      [SETQ XIP (\FILLINXIP \XIPT.ROUTINGINFO NSOC BROADCASTNSHOSTNUMBER 
				    \NS.WKS.RoutingInformation 0 (IPLUS \XIPOVLEN BYTESPERWORD
									(UNFOLD \NS.ROUTINGINFO.WORDS 
										BYTESPERWORD]
	      (replace XIPFIRSTDATAWORD of XIP with \XROUTINGINFO.OP.REQUEST)
	      (SETQ BASE (\ADDBASE (fetch XIPCONTENTS of XIP)
				   1))
	      (replace (NSROUTINGINFO NET#) of BASE with -1)
	      (replace (NSROUTINGINFO #HOPS) of BASE with \RT.INFINITY)
	      (SENDXIP NSOC XIP)
	      (SETUPTIMER \NSROUTER.PROBEINTERVAL \NSROUTER.PROBETIMER)
	      (SETQ \NSROUTER.PROBECOUNT (SUB1 \NSROUTER.PROBECOUNT]
          (GO LP])

(\HANDLE.NS.ROUTING.INFO
  [LAMBDA (XIP)                                              (* bvm: "10-NOV-83 22:30")
                                                             (* Processes a routing info XIP)
    [COND
      ((EQ (fetch XIPFIRSTDATAWORD of XIP)
	   \XROUTINGINFO.OP.RESPONSE)                        (* Unless we're a gateway, we only handle responses)
	(PROG ((HOST (fetch XIPSOURCEHOST of XIP))
	       (NDB (fetch EPNETWORK of XIP))
	       (LENGTH (SUB1 (FOLDLO (IDIFFERENCE (fetch XIPLENGTH of XIP)
						  \XIPOVLEN)
				     BYTESPERWORD)))
	       (BASE (\ADDBASE (fetch XIPCONTENTS of XIP)
			       1))
	       ENTRY NET HOPS)
	      [COND
		((NEQ (fetch NETTYPE of NDB)
		      10)
		  (OR (SETQ HOST (\TRANSLATE.10TO3 HOST NDB))
		      (RETURN]
	      (SETQ \NSROUTER.PROBECOUNT 0)
	      (while (IGEQ LENGTH \NS.ROUTINGINFO.WORDS)
		 do (SETQ NET (fetch (NSROUTINGINFO NET#) of BASE))
		    (SETQ HOPS (fetch (NSROUTINGINFO #HOPS) of BASE))
		    [COND
		      ((OR (SETQ ENTRY (.RTLOOKUP. NET \NS.ROUTING.TABLE))
			   (COND
			     ((ILEQ HOPS \NS.ROUTING.TABLE.RADIUS)
			       [push (CDR \NS.ROUTING.TABLE)
				     (SETQ ENTRY (create ROUTING
							 RTNET# ← NET
							 RTTIMER ←(SETUPTIMER 0]
			       T)))

          (* Update the entry if this entry not for directly connected net and -
	  current entry timed out, or -
	  new gateway same as old, or -
	  new route has fewer hops than old)


			(COND
			  ([AND (NEQ (fetch RTHOPCOUNT of ENTRY)
				     0)
				(OR (NOT (fetch RTRECENT of ENTRY))
				    (AND (EQUAL HOST (fetch RTGATEWAY# of ENTRY))
					 (EQ NDB (fetch RTNDB of ENTRY)))
				    (ILESSP HOPS (fetch RTHOPCOUNT of ENTRY]
			    (replace RTGATEWAY# of ENTRY with HOST)
			    (replace RTNDB of ENTRY with NDB)
			    (replace RTHOPCOUNT of ENTRY with HOPS)
			    (COND
			      ((ILESSP HOPS \RT.INFINITY)
				(replace RTRECENT of ENTRY with T)
				(SETUPTIMER \RT.TIMEOUTINTERVAL (fetch RTTIMER of ENTRY]
		    (SETQ LENGTH (IDIFFERENCE LENGTH \NS.ROUTINGINFO.WORDS))
		    (SETQ BASE (\ADDBASE BASE \NS.ROUTINGINFO.WORDS]
    (\RELEASE.ETHERPACKET XIP])

(\ROUTE.XIP
  [LAMBDA (XIP READONLY)                                     (* bvm: "28-Nov-83 17:41")

          (* Encapsulates XIP, choosing the right network and immediate destination host. Returns an NDB for the 
	  transmission. Unless READONLY is true, defaults source and destination nets if needed)


    (GLOBALRESOURCE \ROUTEBOX.HOST (PROG ((NET (fetch XIPDESTNET of XIP))
					  PDH ROUTE NDB)
				         (COND
					   ((ZEROP NET)
					     (OR (SETQ NDB (OR \10MBLOCALNDB \3MBLOCALNDB))
						 (RETURN)))
					   ((SETQ ROUTE (\LOCATE.NSNET NET))
					     (SETQ NDB (fetch RTNDB of ROUTE)))
					   (T (RETURN)))
				         [SETQ PDH (COND
					     ((AND ROUTE (NEQ (fetch RTHOPCOUNT of ROUTE)
							      0))
					       (fetch RTGATEWAY# of ROUTE))
					     ((EQ (fetch NETTYPE of NDB)
						  10)
					       (LOADNSHOSTNUMBER (LOCF (fetch XIPDESTWORD1
									  of XIP))
								 \ROUTEBOX.HOST)
					       \ROUTEBOX.HOST)
					     ((EQNSHOSTNUMBER (fetch XIPDESTHOST of XIP)
							      BROADCASTNSHOSTNUMBER)
                                                             (* On 3, broadcast goes to zero)
					       0)
					     ((PROGN (LOADNSHOSTNUMBER (LOCF (fetch XIPDESTWORD1
										of XIP))
								       \ROUTEBOX.HOST)
						     (\TRANSLATE.10TO3 \ROUTEBOX.HOST NDB)))
					     (T (RETURN]
				         (replace EPNETWORK of XIP with NDB)
				         (ENCAPSULATE.ETHERPACKET NDB XIP PDH (fetch XIPLENGTH
										 of XIP)
								  \EPT.XIP)
				         [COND
					   ((NOT READONLY)
					     [COND
					       ((ZEROP NET)
						 (replace XIPDESTNET of XIP
						    with (fetch NDBNSNET# of NDB]
					     (replace XIPSOURCENET of XIP
						with (fetch NDBNSNET# of NDB]
				         (RETURN NDB])

(\LOCATE.NSNET
  [LAMBDA (NET DONTPROBE)                                    (* lmm "11-JUN-83 23:10")
    (for (PREVTAIL ← \NS.ROUTING.TABLE) bind TAIL DATA while (LISTP (SETQ TAIL (CDR PREVTAIL)))
       do (SETQ DATA (CAR TAIL))
	  [COND
	    ([OR (EQ NET (fetch (ROUTING RTNET#) of DATA))
		 (AND (ZEROP NET)
		      (ZEROP (fetch (ROUTING RTHOPCOUNT) of DATA]
	      [COND
		((NEQ PREVTAIL \NS.ROUTING.TABLE)            (* Promote this entry to the front, so we find it faster
							     in the future)
		  (FRPLACD \NS.ROUTING.TABLE (PROG1 TAIL (FRPLACD PREVTAIL (CDR TAIL))
						    (FRPLACD TAIL (CDR \NS.ROUTING.TABLE]
	      (RETURN (AND (ILESSP (fetch RTHOPCOUNT of DATA)
				   \RT.INFINITY)
			   DATA]
	  (SETQ PREVTAIL TAIL)
       finally (COND
		 ((NOT DONTPROBE)
		   (push (CDR \NS.ROUTING.TABLE)
			 (create ROUTING
				 RTNET# ← NET
				 RTHOPCOUNT ← \RT.INFINITY
				 RTTIMER ←(SETUPTIMER 30000)))
                                                             (* Insert an entry for the net, to be purged in 30 sec 
							     if router process hasn't filled it by then)
		   (SETQ \NSROUTER.PROBECOUNT 5)
		   (SETQ \NSROUTER.PROBETIMER (SETUPTIMER 0 \NSROUTER.PROBETIMER))
		   (WAKE.PROCESS (QUOTE \NSGATELISTENER))
		   (BLOCK])
)

(RPAQ? \NS.ROUTING.TABLE NIL)

(RPAQ? \NS.ROUTING.TABLE.RADIUS 5)

(RPAQ? \NSROUTER.PROBECOUNT 0)

(RPAQ? \NSROUTER.PROBETIMER )

(RPAQ? \NSROUTER.PROBEINTERVAL 3000)

(RPAQ? \NS.READY )

(RPAQ? \NS.READY.EVENT (CREATE.EVENT "NS Ready"))

(ADDTOVAR \SYSTEMCACHEVARS \NS.READY)
(DECLARE: DONTCOPY 
[DECLARE: EVAL@COMPILE 

(BLOCKRECORD NSROUTINGINFO (                                 (* Format of each entry in a routing info packet)
			    (NET# FIXP)
			    (#HOPS WORD)))
]

(DECLARE: EVAL@COMPILE 

(RPAQQ \NS.ROUTINGINFO.WORDS 3)

(CONSTANTS \NS.ROUTINGINFO.WORDS)
)

(DECLARE: DOEVAL@COMPILE DONTCOPY

(ADDTOVAR GLOBALVARS \NS.ROUTING.TABLE \NS.ROUTING.TABLE.RADIUS \NSROUTER.PROBECOUNT 
	  \NSROUTER.PROBETIMER \NSROUTER.PROBEINTERVAL \NS.READY \NS.READY.EVENT)
)
)



(* Analogous to PUP stuff for tracing activity.)

(DEFINEQ

(XIPTRACE
  [LAMBDA (FLG REGION)                                       (* bvm: "11-JUL-83 17:19")
    (COND
      ((NULL FLG)
	(COND
	  ((ACTIVEWP XIPTRACEFILE)
	    (CLOSEW XIPTRACEFILE)))
	(SETQ XIPTRACEFILE T)
	(SETQ XIPTRACEFLG NIL))
      (T (OR (ACTIVEWP XIPTRACEFILE)
	     (SETQ XIPTRACEFILE (CREATEW REGION "Xerox Internet Packet Traffic")))
	 [WINDOWPROP XIPTRACEFILE (QUOTE BUTTONEVENTFN)
		     (FUNCTION (LAMBDA (WINDOW)
			 (COND
			   ((LASTMOUSESTATE (NOT UP))
			     (\CHANGE.ETHER.TRACING WINDOW (QUOTE XIPTRACEFLG]
	 [WINDOWPROP XIPTRACEFILE (QUOTE CLOSEFN)
		     (FUNCTION (LAMBDA (WINDOW)
			 (COND
			   ((EQ WINDOW XIPTRACEFILE)
			     (SETQ XIPTRACEFLG)
			     (SETQ XIPTRACEFILE T]
	 (DSPFONT (FONTCREATE (QUOTE GACHA)
			      8)
		  XIPTRACEFILE)
	 (SETQ XIPTRACEFLG FLG)
	 (DSPSCROLL T XIPTRACEFILE)
	 (TOTOPW XIPTRACEFILE)
	 XIPTRACEFILE])
)
(DEFINEQ

(PRINTXIP
  [LAMBDA (XIP CALLER FILE PRE.NOTE DOFILTER)                (* bvm: "13-FEB-83 16:10")
    (OR FILE (SETQ FILE XIPTRACEFILE))
    (PROG ((TYPE (fetch XIPTYPE of XIP))
	   MACRO LENGTH)
          [COND
	    (DOFILTER (COND
			((COND
			    (XIPONLYTYPES (NOT (FMEMB TYPE XIPONLYTYPES)))
			    (XIPIGNORETYPES (FMEMB TYPE XIPIGNORETYPES)))
			  (RETURN (PRIN1 (SELECTQ CALLER
						  ((PUT RAWPUT)
						    (QUOTE !))
						  ((GET RAWGET)
						    (QUOTE +))
						  (QUOTE ?))
					 FILE]
          (AND PRE.NOTE (printout FILE T PRE.NOTE))
          (PRINTXIPROUTE XIP CALLER FILE)
          [COND
	    ((SETQ MACRO (CDR (FASSOC TYPE XIPPRINTMACROS)))
                                                             (* Macro is a function to which to dispatch for the 
							     printing.)
	      (AND (NLISTP MACRO)
		   (RETURN (RESETFORM (OUTPUT FILE)
				      (APPLY* MACRO XIP FILE]
          (printout FILE "Length = " .P2 (SETQ LENGTH (fetch XIPLENGTH of XIP))
		    " bytes" " (header + " .P2 (IDIFFERENCE LENGTH \XIPOVLEN)
		    ")" T "Type = ")
          (PRINTCONSTANT TYPE XIPTYPES FILE)
          (TERPRI FILE)
          (COND
	    ((IGREATERP LENGTH \XIPOVLEN)                    (* MACRO tells how to print data.)
	      (PRIN1 "Contents: " FILE)
	      (PRINTXIPDATA XIP (OR MACRO (QUOTE (BYTES 14Q ...)))
			    NIL FILE)))
          (TERPRI FILE)
          (RETURN XIP])

(PRINTERRORXIP
  [LAMBDA (XIP FILE)                                         (* bvm: "16-FEB-83 16:04")
    (SETQ XIP (\DTEST XIP (QUOTE ETHERPACKET)))
    (PROG ((ERRCODE (fetch ERRORXIPCODE of XIP))
	   (ERRARG (fetch ERRORXIPARG of XIP)))
          [printout FILE "[Error] " (OR (CADR (ASSOC ERRCODE XIPERRORMESSAGES))
					(CONCAT (QUOTE #)
						(OCTALSTRING ERRCODE]
          (COND
	    ((NOT (ZEROP ERRARG))
	      (printout FILE ", Parameter " .P2 ERRARG)))
          (TERPRI FILE])

(PRINTXIPROUTE
  [LAMBDA (PACKET CALLER FILE)                               (* bvm: "26-OCT-83 15:51")
    (OR (ZEROP (POSITION FILE))
	(TERPRI FILE))
    (AND CALLER (printout FILE CALLER ":  "))
    (PROG ((CONTROL (fetch XIPTCONTROL of PACKET))
	   CSECS)
          (printout FILE "From " (\PRINTNSADDRESS (LOCF (fetch (XIP XIPSOURCENET) of PACKET))
						  FILE)
		    " to "
		    (\PRINTNSADDRESS (LOCF (fetch (XIP XIPDESTNET) of PACKET))
				     FILE))
          (COND
	    ((NEQ CONTROL 0)
	      (printout FILE ", Hops = " .P2 CONTROL)))
          (COND
	    (XIPTRACETIME (printout FILE " [" .I4 (IQUOTIENT (SETQ CSECS (\CENTICLOCK PACKET))
							     100)
				    (QUOTE %.)
				    .I2..T
				    (IREMAINDER CSECS 100)
				    "]")))
          (TERPRI FILE])

(PRINTXIPDATA
  [LAMBDA (XIP MACRO OFFSET FILE)                            (* JonL " 1-AUG-82 19:52")

          (* * Prints DATA part of XIP starting at OFFSET (Default zero) according to MACRO. MACRO contains elements 
	  describing what format the data is in -
	  WORDS, BYTES, CHARS: print as words, bytes (numeric) or ascii characters -
	  <number>: subsequent commands apply starting at this byte offset -
	  ...: print "..." and quit if you still have data at this point)


    (PROG ((DATA (fetch XIPCONTENTS of XIP))
	   (LENGTH (IDIFFERENCE (fetch XIPLENGTH of XIP)
				\XIPOVLEN)))
          (PRINTPACKETDATA DATA OFFSET MACRO LENGTH FILE])
)

(RPAQ? XIPTRACEFLG )

(RPAQ? XIPTRACEFILE T)

(RPAQ? XIPTRACETIME )

(ADDTOVAR XIPONLYTYPES )

(ADDTOVAR XIPIGNORETYPES )

(ADDTOVAR XIPPRINTMACROS (1 "Operation = " WORDS 2 "Info: " ...)
			 (2 "Operation: " WORDS 2 "Data: " CHARS 100 ...)
			 (3 . PRINTERRORXIP)
			 (4 "ID = " INTEGER 4 "Type = " WORDS 6 BYTES 8))

(PUTPROPS XIPPRINTMACROS VARTYPE ALIST)

(ADDTOVAR \PACKET.PRINTERS (1536 . PRINTXIP))
(DECLARE: DONTCOPY 
[DECLARE: EVAL@COMPILE 

(ACCESSFNS ERRORXIP ((ERRORXIPBASE (fetch XIPCONTENTS of DATUM)))
		    (BLOCKRECORD ERRORXIPBASE ((ERRORXIPCODE WORD)
				  (ERRORXIPARG WORD)
				  (ERRORXIPBODY WORD)        (* As many words of offending XIP as sender felt like 
							     including...)
				  )))
]

(DECLARE: DOEVAL@COMPILE DONTCOPY

(ADDTOVAR GLOBALVARS XIPTRACEFLG XIPTRACEFILE XIPIGNORETYPES XIPONLYTYPES XIPTRACETIME XIPPRINTMACROS)
)
)



(* Peeking)

(DEFINEQ

(\PEEKNS
  [LAMBDA (HOST FILE)                                        (* bvm: "12-OCT-83 16:22")
    (PROG NIL
          [COND
	    ((NULL HOST)
	      (\PROMISCUOUS.OFF)
	      (RPTQ 20 (BLOCK))                              (* empty the pipe)
	      (SETQ \PEEKNSNUMBER))
	    (T (COND
		 ((EQ HOST T)
		   (SETQ \PEEKNSNUMBER T))
		 ((SETQ HOST (\NS.FINDNSADDRESS HOST))
		   (SETQ \PEEKNSNUMBER (fetch NSHOSTNUMBER of HOST)))
		 (T (RETURN)))                               (* Now make us promiscuous)
	       (\PROMISCUOUS.ON)
	       [COND
		 (FILE (SETQ XIPTRACEFILE (OR (OPENP FILE (QUOTE OUTPUT))
					      (OPENFILE FILE (QUOTE OUTPUT]
	       (OR XIPTRACEFLG (SETQ XIPTRACEFLG T]
          (RETURN \PEEKNSNUMBER])

(\MAYBEPEEKNS
  [LAMBDA (XIP)                                              (* bvm: "12-OCT-83 16:25")
    [COND
      ((AND \PEEKNSNUMBER XIPTRACEFLG)
	(PROG (DIRECTION)
	      (COND
		([OR (EQ \PEEKNSNUMBER T)
		     (AND (EQNSHOSTNUMBER (fetch XIPDESTHOST of XIP)
					  BROADCASTNSHOSTNUMBER)
			  (NEQ \PEEKNSNUMBER 0))
		     [COND
		       ((EQNSHOSTNUMBER (fetch XIPSOURCEHOST of XIP)
					\PEEKNSNUMBER)
			 (SETQ DIRECTION (QUOTE PUT]
		     (COND
		       ((EQNSHOSTNUMBER (fetch XIPDESTHOST of XIP)
					\PEEKNSNUMBER)
			 (SETQ DIRECTION (QUOTE GET]
		  (PRINTXIP XIP DIRECTION XIPTRACEFILE NIL T]
    (\RELEASE.ETHERPACKET XIP])
)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(ADDTOVAR GLOBALVARS \PEEKNSNUMBER)
)

(RPAQ? \PEEKNSNUMBER )
(DEFINEQ

(\PROMISCUOUS.ON
  [LAMBDA NIL                                                (* bvm: "12-OCT-83 15:58")
    (SELECTQ (fetch NETTYPE of \LOCALNDBS)
	     (3 (\PUTBASE (EMADDRESS \ETHERHOSTLOC)
			  0 0))
	     (10 (\10MB.STARTDRIVER \LOCALNDBS T BROADCASTNSHOSTNUMBER))
	     NIL])

(\PROMISCUOUS.OFF
  [LAMBDA NIL                                                (* bvm: "12-OCT-83 15:58")
    (SELECTQ (fetch NETTYPE of \LOCALNDBS)
	     (3 (\PUTBASE (EMADDRESS \ETHERHOSTLOC)
			  0
			  (fetch NDBPUPHOST# of \LOCALNDBS)))
	     (10 (\10MB.STARTDRIVER \LOCALNDBS T T))
	     NIL])
)
(DECLARE: EVAL@COMPILE DONTCOPY 
(DECLARE: EVAL@COMPILE 

(RPAQQ \ETHERHOSTLOC 392)

(CONSTANTS \ETHERHOSTLOC)
)
)



(* Simple packet exchange protocols)

(DEFINEQ

(\GETMISCNSOCKET
  [LAMBDA NIL                                                (* bvm: "24-FEB-83 17:51")
                                                             (* Opens a socket for miscellaneous services, if we 
							     don't have it open yet)
    (COND
      ((AND \MISC.NSOCKET (FMEMB \MISC.NSOCKET \NSOCKETS))
	\MISC.NSOCKET)
      (T (SETQ \MISC.NSOCKET (OPENNSOCKET])

(EXCHANGEXIPS
  [LAMBDA (SOC OUTXIP IDFILTER TIMEOUT)                      (* bvm: "24-FEB-83 18:25")

          (* Sends out OUTXIP on SOC and waits for a reply, which it puts in INXIP. If IDFILTER is true, only replies with 
	  the same ID are accepted. Returns input pup on success, or NIL on failure. TIMEOUT overrides the default timeout.)


    (OR TIMEOUT (SETQ TIMEOUT \ETHERTIMEOUT))
    (DISCARDXIPS SOC)                                        (* Flush any pups waiting on this socket)
    (SENDXIP SOC OUTXIP)
    (bind INXIP (TIMER ←(SETUPTIMER TIMEOUT)) until (TIMEREXPIRED? TIMER)
       do (\BACKGROUND)
	  (COND
	    ([AND (SETQ INXIP (GETXIP SOC))
		  (OR (NOT IDFILTER)
		      (IEQP (fetch PACKETEXCHANGEID of (fetch XIPCONTENTS of INXIP))
			    (fetch PACKETEXCHANGEID of (fetch XIPCONTENTS of OUTXIP]
	      (RETURN INXIP])

(\LOOKUPPUPNUMBER
  [LAMBDA (NSNUMBER)                                         (* bvm: " 7-JUL-83 14:12")

          (* * Looks up the pup host number for NSNUMBER. These numbers are in gateway's database)


    (PROG ((SOC (\GETMISCNSOCKET))
	   OXIP RESULT BUF)
          (SETQ OXIP (\FILLINXIP \XIPT.PUPLOOKUP SOC BROADCASTNSHOSTNUMBER \NS.WKS.PUPLOOKUP 0))
          (add (fetch XIPLENGTH of OXIP)
	       (UNFOLD (IPLUS \#WDS.NSHOSTNUMBER 3)
		       BYTESPERWORD))
          (SETQ BUF (fetch XIPCONTENTS of OXIP))
          (replace PACKETEXCHANGEID of BUF with (CLOCK 0))
          (replace PACKETEXCHANGETYPE of BUF with \EXTYPE.REQUEST)
          (\STORENSHOSTNUMBER (LOCF (fetch PACKETEXCHANGEBODY of BUF))
			      NSNUMBER)
          (DISCARDXIPS SOC)
          (to \MAXETHERTRIES bind INXIP TIMER
	     do (SENDXIP SOC OXIP)
		(SETQ TIMER (SETUPTIMER \ETHERTIMEOUT TIMER))
	     repeatuntil (do (BLOCK)
			     (COND
			       [(NULL (SETQ INXIP (GETXIP SOC]
			       ((IEQP (fetch PACKETEXCHANGEID of (fetch XIPCONTENTS of INXIP))
				      (fetch PACKETEXCHANGEID of (fetch XIPCONTENTS of OXIP)))
				 (SELECTC (fetch PACKETEXCHANGETYPE of (SETQ BUF
									 (fetch XIPCONTENTS
									    of INXIP)))
					  [\EXTYPE.RESPONSE (RETURN (PROG1 (SETQ RESULT
									     (fetch 
									       PACKETEXCHANGEBODY
										of BUF))
									   (RELEASE.XIP INXIP]
					  (\EXTYPE.NEGATIVE
					    (COND
					      (XIPTRACEFLG (printout
							     XIPTRACEFILE
							     [\GETBASESTRING
							       (LOCF (fetch PACKETEXCHANGEBODY
									of BUF))
							       0
							       (IDIFFERENCE (fetch XIPLENGTH
									       of INXIP)
									    (IPLUS \XIPOVLEN
										   (UNFOLD 3 
										     BYTESPERWORD]
							     T)))
                                                             (* For now, ignore negative responses.
							     some gateways are confused)
					    )
					  NIL)
				 (RELEASE.XIP INXIP))
			       (T (RELEASE.XIP INXIP)))
			    repeatuntil (TIMEREXPIRED? TIMER)))
          (COND
	    ((AND XIPTRACEFLG (NULL RESULT))
	      (printout XIPTRACEFILE "NS to Pup number lookup timed out" T)))
          (RELEASE.XIP OXIP)
          (RETURN RESULT])

(RELEASE.XIP
  [LAMBDA (XIP)                                              (* bvm: "24-FEB-83 18:08")
    (\RELEASE.ETHERPACKET XIP])
)
(DECLARE: DONTEVAL@LOAD DOCOPY 
(AND (CCODEP (QUOTE \ALLOCATE.ETHERPACKET))
     (MOVD (QUOTE \ALLOCATE.ETHERPACKET)
	   (QUOTE ALLOCATE.XIP)))
(AND (CCODEP (QUOTE \RELEASE.ETHERPACKET))
     (MOVD (QUOTE \RELEASE.ETHERPACKET)
	   (QUOTE RELEASE.XIP)))
)
[DECLARE: EVAL@COMPILE 

(BLOCKRECORD PACKETEXCHANGEXIP ((PACKETEXCHANGEID FIXP)      (* Arbitrary id in packet exchange XIP)
				(PACKETEXCHANGETYPE WORD)    (* Protocol-specific type)
				(PACKETEXCHANGEBODY WORD)    (* Body starts here)
				))
]
(DECLARE: EVAL@COMPILE 

(RPAQQ \EXTYPE.REQUEST 1)

(RPAQQ \EXTYPE.RESPONSE 2)

(RPAQQ \EXTYPE.NEGATIVE 3)

(CONSTANTS (\EXTYPE.REQUEST 1)
	   (\EXTYPE.RESPONSE 2)
	   (\EXTYPE.NEGATIVE 3))
)
(DECLARE: DOEVAL@COMPILE DONTCOPY

(ADDTOVAR GLOBALVARS \MISC.NSOCKET)
)

(RPAQ? \MISC.NSOCKET )



(* Time service)

(DEFINEQ

(NSNETDAYTIME0
  [LAMBDA NIL                                                (* bvm: " 3-MAR-83 17:15")

          (* * Returns a 32-bit unsigned alto time from the network, if possible)


    (PROG ((SOC (\GETMISCNSOCKET))
	   OXIP RESULT IXIP BUF)
          [SETQ OXIP (\FILLINXIP \XIPT.EXCHANGE SOC BROADCASTNSHOSTNUMBER \TIMESOCKET 0
				 (IPLUS \XIPOVLEN (UNFOLD 5 BYTESPERWORD]
          (SETQ BUF (fetch XIPCONTENTS of OXIP))
          (replace PACKETEXCHANGETYPE of BUF with \EXTYPE.TIME)
          (replace PACKETEXCHANGEID of BUF with (RAND))
          (replace TIMEOP of BUF with \TIMEOP.TIMEREQUEST)
          (replace TIMEVERSION of BUF with \TIMEVERSION)
          (RETURN (to \MAXETHERTRIES when (SETQ IXIP (EXCHANGEXIPS SOC OXIP T))
		     do (SELECTC (fetch TIMEOP of (SETQ BUF (fetch XIPCONTENTS of IXIP)))
				 (\TIMEOP.TIMERESPONSE (RETURN (fetch TIMEVALUE of BUF)))
				 NIL])

(\NS.SETTIME
  [LAMBDA NIL                                                (* bvm: "26-MAY-83 15:46")

          (* * Returns a 32-bit unsigned alto time from the network, if possible)


    (PROG ((SOC (\GETMISCNSOCKET))
	   OXIP RESULT IXIP BUF)
          [SETQ OXIP (\FILLINXIP \XIPT.EXCHANGE SOC BROADCASTNSHOSTNUMBER \TIMESOCKET 0
				 (IPLUS \XIPOVLEN (UNFOLD 5 BYTESPERWORD]
          (SETQ BUF (fetch XIPCONTENTS of OXIP))
          (replace PACKETEXCHANGETYPE of BUF with \EXTYPE.TIME)
          (replace PACKETEXCHANGEID of BUF with (RAND))
          (replace TIMEOP of BUF with \TIMEOP.TIMEREQUEST)
          (replace TIMEVERSION of BUF with \TIMEVERSION)
          (RETURN (to \MAXETHERTRIES when (SETQ IXIP (EXCHANGEXIPS SOC OXIP T))
		     do (SELECTC (fetch TIMEOP of (SETQ BUF (fetch XIPCONTENTS of IXIP)))
				 (\TIMEOP.TIMERESPONSE (\SETNEWTIME0 (create FIXP
									     HINUM ←(fetch 
										      TIMEVALUEHI
										       of BUF)
									     LONUM ←(fetch 
										      TIMEVALUELO
										       of BUF)))
						       (SETQ \TimeZoneComp
							 (ITIMES (COND
								   ((ZEROP (fetch TIMEZONESIGN
									      of BUF))
								     1)
								   (T -1))
								 (fetch TIMEZONEHOURS of BUF)))
						       (SETQ \BeginDST (fetch TIMEBEGINDST
									  of BUF))
						       (SETQ \EndDST (fetch TIMEENDDST of BUF))
						       (RETURN T))
				 NIL])

(NSNETDATE
  [LAMBDA NIL                                                (* bvm: " 3-MAR-83 17:38")
    (GDATE (ALTO.TO.LISP.DATE (OR (NSNETDAYTIME0)
				  (DAYTIME0 (create FIXP])
)
(DECLARE: DONTCOPY 
[DECLARE: EVAL@COMPILE 

(BLOCKRECORD TIMEBODY ((NIL 3 WORD)                          (* Packet exchange header)
		       (TIMEVERSION WORD)                    (* Protocol version)
		       (TIMEOP WORD)                         (* What kind of request/response)
		       (TIMEVALUE FIXP)
		       (TIMEZONESIGN WORD)                   (* 0 = west of prime meridian, 1 = east)
		       (TIMEZONEHOURS WORD)                  (* Hours from prime meridian)
		       (TIMEZONEMINUTES WORD)                (* Minutes ...)
		       (TIMEBEGINDST WORD)                   (* Day of year when DST starts)
		       (TIMEENDDST WORD)                     (* Day of year when DST stops)
		       )
		      (BLOCKRECORD TIMEBODY ((NIL 5 WORD)
				    (TIMEVALUEHI WORD)
				    (TIMEVALUELO WORD))))
]

(DECLARE: EVAL@COMPILE 

(RPAQQ \TIMESOCKET 8)

(RPAQQ \TIMEOP.TIMEREQUEST 1)

(RPAQQ \TIMEOP.TIMERESPONSE 2)

(RPAQQ \TIMEVERSION 2)

(RPAQQ \EXTYPE.TIME 1)

(CONSTANTS \TIMESOCKET \TIMEOP.TIMEREQUEST \TIMEOP.TIMERESPONSE \TIMEVERSION \EXTYPE.TIME)
)
)



(* Background activities)

(DEFINEQ

(NS.ECHOSERVER
  [LAMBDA (DURATION.MINUTES)                                 (* bvm: " 7-AUG-83 01:40")
                                                             (* Process that watches for packets on the Well-Known 
							     socket number 2, and echos them.)
    (RESETLST (PROG ((ECHOSKT (OPENNSOCKET \NS.WKS.Echo T))
		     [TIMEOUT (AND (FIXP DURATION.MINUTES)
				   (SETUPTIMER (ITIMES 165140Q DURATION.MINUTES]
		     XIP ECHOSKT)
		    (RESETSAVE NIL (LIST (QUOTE CLOSENSOCKET)
					 ECHOSKT))
		    (until (AND TIMEOUT (TIMEREXPIRED? TIMEOUT))
		       do (COND
			    ((SETQ XIP (GETXIP ECHOSKT (OR TIMEOUT T)))
                                                             (* Got something)
			      (COND
				((AND (EQ (fetch XIPTYPE of XIP)
					  \XIPT.ECHO)
				      (EQ (fetch XIPFIRSTDATAWORD of XIP)
					  \XECHO.OP.REQUEST))
				  (replace XIPFIRSTDATAWORD of XIP with \XECHO.OP.REPLY)
				  (\SWAPNSADDRESSES (LOCF (fetch XIPDESTNET of XIP))
						    (LOCF (fetch XIPSOURCENET of XIP)))
				  (SENDXIP ECHOSKT XIP))
				(T                           (* Just drop the packet if it doesn't look good)
				   (COND
				     (XIPTRACEFLG (PRINTPACKET XIP (QUOTE GET)
							       XIPTRACEFILE 
							"Garbage Packet sent to the Echo socket:")))
				   (\RELEASE.ETHERPACKET XIP])
)
(DECLARE: DONTCOPY 
(DECLARE: EVAL@COMPILE 

(RPAQQ \XECHO.OP.REQUEST 1)

(RPAQQ \XECHO.OP.REPLY 2)

(RPAQQ \XROUTINGINFO.OP.REQUEST 1)

(RPAQQ \XROUTINGINFO.OP.RESPONSE 2)

(CONSTANTS \XECHO.OP.REQUEST \XECHO.OP.REPLY \XROUTINGINFO.OP.REQUEST \XROUTINGINFO.OP.RESPONSE)
)
)



(* Debugging)

(DEFINEQ

(NS.ECHOUSER
  [LAMBDA (ECHOHOST ECHOSTREAM INTERVAL NTIMES)              (* bvm: " 7-AUG-83 01:49")
    (RESETLST (PROG ((RESULT (QUOTE WIN!))
		     (NSOC (OPENNSOCKET))
		     (TIMER (SETUPTIMER 0))
		     OXIP IXIP EVENT I XIPBASE ECHOXIPLENGTH OXIPBASE)
		    (RESETSAVE NIL (LIST (QUOTE CLOSENSOCKET)
					 NSOC))
		    (SETQ ECHOHOST (\NS.FINDNSADDRESS ECHOHOST))
		    (SETQ OXIP (\FILLINXIP \XIPT.ECHO NSOC ECHOHOST \NS.WKS.Echo))
		    (XIPAPPEND.WORD OXIP \XECHO.OP.REQUEST)
		    (XIPAPPEND.WORD OXIP (SETQ I 1))
		    (XIPAPPEND.STRING OXIP "Random string for echo")
		    (OR INTERVAL (SETQ INTERVAL 1750Q))
		    (OR NTIMES (SETQ NTIMES 1750Q))
		    (SETQ ECHOSTREAM (GETSTREAM (OR ECHOSTREAM T)
						(QUOTE OUTPUT)))
		    (SETQ ECHOXIPLENGTH (fetch XIPLENGTH of OXIP))
		    (SETQ OXIPBASE (fetch XIPCONTENTS of OXIP))
		    (SETQ EVENT (fetch NSOCEVENT of NSOC))
		LP  (SENDXIP NSOC OXIP)
		    (PRIN1 (QUOTE !)
			   ECHOSTREAM)
		    (SETUPTIMER INTERVAL TIMER)
		    (do (COND
			  [(SETQ IXIP (GETXIP NSOC))
			    (COND
			      ((PROG1 (SELECTC (fetch XIPTYPE of IXIP)
					       (\XIPT.ECHO (COND
							     ((OR (NEQ (fetch XIPLENGTH of IXIP)
								       ECHOXIPLENGTH)
								  (NEQ (\GETBASE (SETQ XIPBASE
										   (fetch XIPCONTENTS
										      of IXIP))
										 0)
								       \XECHO.OP.REPLY))
							       (PRIN1 (QUOTE ?)
								      ECHOSTREAM)
							       NIL)
							     ((IEQP (\GETBASE XIPBASE 1)
								    I)
							       (PRIN1 (QUOTE +)
								      ECHOSTREAM))
							     (T (PRIN1 "(late)" ECHOSTREAM)
								NIL)))
					       (\XIPT.ERROR (PRINTERRORXIP IXIP ECHOSTREAM)
							    NIL)
					       (PROGN (PRIN1 (QUOTE ?)
							     ECHOSTREAM)
						      NIL))
				      (RELEASE.XIP IXIP))
				(RETURN]
			  (T (AWAIT.EVENT EVENT TIMER T)))
		       repeatuntil (TIMEREXPIRED? TIMER)
		       finally (COND
				 ((fetch EPTRANSMITTING of OXIP)
				   (PRIN1 "[not yet transmitted; maybe transmitter is off]" 
					  ECHOSTREAM)))
			       (PRIN1 (QUOTE %.)
				      ECHOSTREAM))
		    (COND
		      ((IGREATERP (OR (EQ NTIMES T)
				      (add NTIMES -1))
				  0)
			(\PUTBASE OXIPBASE 1 (add I 1))
			(GO LP])
)

(RPAQ? \DEFAULTECHOSERVER NIL)

(RPAQ? \NS.ECHOUSERSOCKET NIL)
(DECLARE: DONTEVAL@LOAD DOCOPY 
(\NSINIT)
)
(DECLARE: EVAL@COMPILE DONTCOPY 
(FILESLOAD (LOADCOMP)
	   LLETHER)
)
(PUTPROPS LLNS COPYRIGHT ("Xerox Corporation" 1983))
(DECLARE: DONTCOPY
  (FILEMAP (NIL (8391 11375 (\NS.FINDNSADDRESS 8401 . 8781) (\PARSE.NSADDRESSCONSTANT 8783 . 10260) (
\PARSEANUM 10262 . 11373)) (13169 15975 (OPENNSOCKET 13179 . 14552) (CLOSENSOCKET 14554 . 15398) (
NSOCKETEVENT 15400 . 15572) (NSOCKETFROMNUMBER 15574 . 15715) (\FLUSHNSOCQUEUE 15717 . 15973)) (16073 
17644 (\NSINIT 16083 . 17341) (STOPNS 17343 . 17642)) (17645 22788 (\HANDLE.RAW.XIP 17655 . 21536) (
\XIPERROR 21538 . 22265) (\FORWARD.XIP 22267 . 22786)) (22895 26820 (GETXIP 22905 . 23862) (
DISCARDXIPS 23864 . 24130) (SENDXIP 24132 . 25264) (SWAPXIPADDRESSES 25266 . 25922) (\SETXIPCHECKSUM 
25924 . 26477) (\CLEARXIPHEADER 26479 . 26818)) (27052 34648 (\FILLINXIP 27062 . 29329) (
XIPAPPEND.BYTE 29331 . 30051) (XIPAPPEND.WORD 30053 . 31004) (XIPAPPEND.CELL 31006 . 32007) (
XIPAPPEND.STRING 32009 . 33185) (XIPAPPEND.IFSSTRING 33187 . 33569) (XIPAPPEND.INTEGER 33571 . 34646))
 (34673 41819 (\NSGATELISTENER 34683 . 36264) (\HANDLE.NS.ROUTING.INFO 36266 . 38588) (\ROUTE.XIP 
38590 . 40484) (\LOCATE.NSNET 40486 . 41817)) (42694 43586 (XIPTRACE 42704 . 43584)) (43587 47098 (
PRINTXIP 43597 . 45052) (PRINTERRORXIP 45054 . 45576) (PRINTXIPROUTE 45578 . 46399) (PRINTXIPDATA 
46401 . 47096)) (48036 49486 (\PEEKNS 48046 . 48805) (\MAYBEPEEKNS 48807 . 49484)) (49588 50222 (
\PROMISCUOUS.ON 49598 . 49895) (\PROMISCUOUS.OFF 49897 . 50220)) (50387 54286 (\GETMISCNSOCKET 50397
 . 50800) (EXCHANGEXIPS 50802 . 51723) (\LOOKUPPUPNUMBER 51725 . 54142) (RELEASE.XIP 54144 . 54284)) (
55137 57913 (NSNETDAYTIME0 55147 . 56159) (\NS.SETTIME 56161 . 57714) (NSNETDATE 57716 . 57911)) (
59066 60469 (NS.ECHOSERVER 59076 . 60467)) (60783 63117 (NS.ECHOUSER 60793 . 63115)))))
STOP