; 32 5-Nov-85 Phil Accept zero checksums ; 17 26-Aug-85 Phil Have PPKT do DOBE and end ; 15 18-Aug-85 Phil Use UPKT in UGET1, so PPKT can be called ; 11 2-Aug-85 Phil Only check local port in UCHECK SEARCH UDPUNV,ANAUNV,PROLOG TTITLE (UDPUDP,UDPUDP,< - Internet User Data Prorocol>) SUBTTL June 1985, Phil Budne@BU/DSG ; Copyright (C) 1985 Philip L. Budne ; Some Code from TCPTCP, IPIPIP, ; COPYRIGHT (C) DIGITAL EQUIPMENT CORPORATION 1982, 1984. ; and VAF's UDPLIB, Copyright (C) 1984 Vincent A. Fuller UCB==TCB ; Pointer to UCB (P5) PKT==PKT ; Pointer to Packet (P4) UPKT==TPKT ; Pointer to UDP Packet (P3) SIZE==P2 ;Parameters UCBHSZ==^D17 ; Size of hash table UCBLIM==^D10 ; Max packets to enqueue before dumping ;Externs EXTERN UDPIPQ,UDPON,UDPTIM,UDPFLG,UDPPCL,UDPSID,UDPIFG,UDPBSZ,UDPBFD EXTERN UCBH,UCBHUC,UCBHLK,UCBMAX,UCBCNT .UDPFM==:21 ; UDP protocol format number CKSMSK==177777 ; Mask for checksum ; UDP PACKET HEADER DEFSTR PUDPSP,0,15,16 ; Source port DEFSTR PUDPDP,0,31,16 ; Dest port DEFSTR PUDPLN,1,15,16 ; UDP length DEFSTR PUDPCK,1,31,16 ; UDP checksum UDPHLN==2 ; UDP header length IPHLN==/4 ; IP header length SUBTTL INTERNET INTERFACE FOR UDP SWAPCD ;UDPINI ;Initialize UDP module. ; CALL UDPINI (From NETINI) ;Ret+1: Always. UDP ready to run. UDPINI::NOSKED MOVEI T1,QSZ ; Size of a queue head CALL GETBLK ; Get that amount of free storage JUMPE T1,UDPINX ; Lose MOVEM T1,UDPIPQ ; That is the UDP input queue CALL INITQ ; Initialize it CALL UCBINI ; Initalize UCB Hash table MOVE T1,INTXPW ; Get packet size SUBI T1,PKTELI-1+IPHLN ; Get max UDP data size MOVEM T1,UDPBSZ ; Save buffer size SETOM UDPIFG ; Flag UDP initialized SETOM UDPON ; UDP ready UDPINX: OKSKED RET ;UDPCHK ;Check Routine for UDP Tells when to run next ;T1/ A TODCLK ; CALL UDPCHK ;Ret+1: Always. T1 has minimum of input T1 and when we should run next. UDPCHK::CAMLE T1,UDPTIM ; Check against our next timeout MOVE T1,UDPTIM ; That is sooner RET ;UDPICM ;Handle an ICMP message for UDP UDPICM::RET ; Dummy ;UDPPRC Top level UDP Processing routine. Called From Internet Fork ;CALL UDPPRC ;Ret+1: Always UDPPRC::SETZM UDPFLG ; Clear run request flag SKIPN UDPON ; UDP on? RET ; No - refuse to process CALL UDPROC ; Process any msgs which are waiting RET ;UDPROC ;Process the input packet queue. ;Packets have been queued at interrupt level. ; CALL UDPROC ;Ret+1: always. UDPROC: SAVEAC STACKL <,PCHECK> CHKADL ; Room for args to CHKADD ; Top of main loop. Get next packet to be processed. UDPRO0: MOVE T1,UDPIPQ ; Get pointer to input queue head LOAD PKT,QNEXT,(T1) ; Get pointer to first thing on queue CAIN PKT,0(T1) ; If that is the head itself JRST UDPROX ; Get out because it is empty (need OKSKED) SETSEC PKT,INTSEC ; Make extended address MOVE T1,PKT ; What to dequeue CALL DQ ; Remove from input queue SETZ UCB, ; May be a bad packet ;;; MOVX T1,PT%TDI ; TCP received packet ;;; TDNE T1,INTTRC ; Want trace? ;;; CALL PRNPKT ; Yes LOAD T1,PIDO,(PKT) ; Internet Data Offset XMOVEI UPKT,PKTELI(PKT) ; Pointer to Internet packet ADD UPKT,T1 ; Pointer to UDP packet LOAD T1,PUDPCK,(UPKT) ; get packet checksum MOVEM T1,PCHECK ; save it SETZRO PUDPCK,(UPKT) ; zero field JUMPE T1,UDPRO2 ; [32] Rcvd checksum was zero? Accept it!! CALL UDPCKS ; Compute checksum function MOVE T2,PCHECK ; get recieved checksum back JFCL ; ** Patch to SKIPA to disable checksums ** CAMN T1,T2 ; Match? JRST UDPRO2 ; Jump if good ; Packet has bad checksum. Flush it. AOS BADPCT ; Count bad packets ;;; MOVX T1,PT%XX5 ; Code for "Flushed by IP" ;;; TDNE T1,INTTRC ; Want trace? ;;; CALL PRNPKT ; Yes ;;; MOVX T1,PT%TKC ; TCP Killed due to bad checksum ;;; TDNE T1,INTTRC ; Want trace? ;;; CALL PRNPKT ; Yes CALL RETPKT ; Return the packet storage JRST UDPRO0 ; And hope for better luck next Pkt ; Packet is OK to process ... UDPRO2: ; Now setup for a call to UCHECK which looks up the UCB addressed ; by the pkt. If it is found, UCHECK calls UINPUT with said UCB locked. MOVEI PARAMS,ARGBLK ; Arg area on stack (ref. via sec. 0) LOAD T1,PIDH,(PKT) ; Destination Host MOVEM T1,LH LOAD T2,PUDPDP,(UPKT) ; Destination port MOVEM T2,LP LOAD T3,PISH,(PKT) ; Source Host JUMPE T3,UDPROF ; Toss packet if null MOVEM T3,FH LOAD T4,PUDPSP,(UPKT) ; Source Port JUMPE T1,UDPROF ; Toss packet if null MOVEM T4,FP SETZM JCN ; No JCN. Call is from IP. SETOM WILDOK ; Wild UCB (Listen) is OK for match XMOVEI T2,UINPUT ; Function to call if found MOVEM T2,FN SETZM ARG1 ; No ARG1 SETZM ARG2 ; or ARG2 MOVE T1,PARAMS ; Arg block for UCHECK CALL UCHECK ; Check the address of the packet CAMN T1,[-1] ; Packet disposed of successfully? JRST UDPRO0 ; Yes. Do another one. UDPROF: ;;; MOVX T1,PT%XX5 ; Code for "Flushed by IP" ;;; TDNE T1,INTTRC ; Want trace? ;;; CALL PRNPKT ; Yes ;;; MOVX T1,PT%TID ; TCP done with packet ;;; TDNE T1,INTTRC ; Want trace? ;;; CALL PRNPKT ; Yes CALL RETPKT ; Give back the storage JRST UDPRO0 ; And process some more packets UDPROX: ; Here when packet queue completely processed. CHKADR RET ;UINPUT ;Called via UCHECK with a new packet ; UCB/ (locked) ; PKT UINPUT: HRROI T1,0 ; Get error code?! (never seen by user) MOVE T2,UCBCTR(UCB) ; Get current packet count CAIL T2,UCBLIM ; Above limit? IFSKP. AOS UCBCTR(UCB) ; Bump count of packets MOVE T1,PKT ; Get packet XMOVEI T2,UCBINQ(UCB) ; Get input queue header CALL NQ ; eNQueue it AOS IPPKCT ; Count as Processed by IP LOAD T1,UCBWAI,(UCB) ; Get wait bit SKIPN T2 ; Queue now empty? IFSKP. CALL SETWTB ; Yes, flag non-empty LOAD T1,UCBICD,(UCB) ; Get PSI chan LOAD T2,UCBIFD,(UCB) ; Get PSI fork CAIE T1,77 ; Null chan? SKIPN T2 ; Real fork? TRNA ; Nope CALL PSIRQ ; Looks Good!! ENDIF. SETO T1, ; Get return value ENDIF. RET ; And return ;UCHECK ;Lookup up a connection and maybe create a new one. ;If the desired (possibly wild) connection is found, the argument ;function is called with the UCB locked. If no UCB is found, the value ;of UCHECK is -1,,errorcode. Otherwise the value is that of the ;function called, which may also be an error value. ; T1/ (Extended) Pointer to argument block defined by CHKADL ; NOINT ; CALL UCHECK ;Ret+1: always. Value in T1, UCB set up. ELP+^D13. Illegal port (LP=0) ; (net) EFP+^D7. No UCB matches ; (JSYS) ELT+^D4. No storage, wait bit, too many connections UCHECK: STACKL CHKADL () ; PARAMS & other LOCALs MOVEM T1,PARAMS ; Save pointer to parameters HRROI T1,ELP+^D13 ; "Illegal port" (TCPXX8 -- illegal local spec) SKIPN LP EXIT UCHECX ; Should never have to lookup wild LP ; Get hash index to the UCB Hash table CALL UHLOCK ; Get exclusive access to UCB hash table MOVE T1,LP ; Local port is what is hashed on LSH T1,-3 ADDI T1,^D23 ; Hash LP into a UCBH index IMUL T1,LP IDIVI T1,UCBHSZ ; Size of the hash table ADD T2,UCBH ; (Ext) Location within UCBH MOVEM T2,UCBX ; Save the (ext) pointer to q head ; Scan the UCB queue which has its head in the slot at UCBX MOVE UCB,UCBX ; Initize the scan pointer SETZM WILD1 ; No Wild match found yet DO. LOAD UCB,QNEXT,<+UCBQ(UCB)> ; Get next (first) thing on input Q SETSEC UCB,INTSEC ; Make extended address CAMN UCB,UCBX ; Points back to head? EXIT. ; Yes. Scan done. LOAD T1,UCBLP,(UCB) ; Get the Local Port from this UCB CAME T1,LP ; Does it match what we are looking for? LOOP. ; No. Try next UCB IFN 0,< LOAD UCB.FH,UCBFH,(UCB) ; Get foreign host LOAD UCB.FP,UCBFP,(UCB) ; and foreign port CAMN UCB.FH,FH ; Compare these with what CAME UCB.FP,FP ; is being sought IFSKP. ; Exact match. EXIT. ; Just break loop ELSE. ; Not exact, check wild SKIPN WILD1 ; Continue scan if already have a wild match SKIPN WILDOK ; Caller says OK to use wild UCB? LOOP. ; No. Keep looking for exact match. IFN. UCB.FH ; UCB has wild foreign host CAME UCB.FH,FH ; or exact match means ok. LOOP. ; No. Resume scan. ENDIF. IFN. UCB.FP ; Wild foreign port in UCB? CAME UCB.FP,FP ; or exact match? LOOP. ; No good. ENDIF. MOVEM UCB,WILD1 ; Save the location of the wild UCB LOOP. ; Continue looking for exact match. ENDIF. ; End wild/exact > ;IFN 0 OD. ; End of search loop ; End of scan. UCB has the UCB to use or points at queue head (UCBX) ; if none found. WILD1 is 0 or pointer to a wild UCB. CHKAD6: CAME UCB,UCBX ; No exact match? IFSKP. SKIPN WILD1 ; Have a wild match? IFSKP. ; yes, bind it ;;; MOVE T1,FH ; Get the desired foreign host ;;; MOVE T2,FP ; and foreign port ;;; MOVE T3,LH ; and local host MOVE UCB,WILD1 ; This is the UCB to work with ;;; STOR T1,UCBFH,(UCB) ; Store in the wild UCB ;;; STOR T2,UCBFP,(UCB) ;;; STOR T3,UCBLH,(UCB) ELSE. ; No match, no wild SKIPN JCN ; JSYS call? IFSKP. ; create UCB MOVE T1,PARAMS ; Argument block address MOVE T2,UCBX ; (Ext) Where to enqueue the new UCB CALL NEWUCB ; Create and initialize it. IFE. UCB ; Failed? MOVEI T1,UCBHLK ; Ran out of free storage. CALL UUNLCK ; Unlock UCBH HRROI T1,ELT+^D4 ; (TCPX20 max connections exceeded) EXIT UCHECX ; Report the error to the caller ENDIF. ; end of UCB alloc failed ENDIF. ; end of create UCB ENDIF. ; end no wild ENDIF. ; end no match ; UCB has the UCB to use or is equal to UCBX if not. ; If a UCB was found/created, lock it and call the argument function. AOS UCBHUC ; Indicate UCBH has a reader CALL UUNLCK ; Unlock UCBH with use count gt 0 HRROI T1,EFP+^D7 ; Connection error or rejected -- TCPX20 CAMN UCB,UCBX ; Did we locate a UCB? IFSKP. ; Yes XMOVEI T1,UCBLCK(UCB) ; Pointer to the UCB Lock MOVE T2,FN ; Function to be called MOVE T3,JCN ; Argument for the function MOVE T4,ARG1 ; The argument passed through CALL LCKCAL ; Lock the lock and call the function ENDIF. ; UCB was found SOS UCBHUC ; Indicate UCBH may change now UCHECX: CHKADR ; Restore RET SUBTTL UCB HASH TABLE MANAGEMENT ;UCBINI ;Initialize the UCB Hash Table. ; CALL UCBINI ;Ret+1: Always UCBINI: LOCAL MOVEI T1,UCBHSZ*QSZ ; Size of the UCB Hash table CALL GETBLK ; Qs must point to things in same section! JUMPE T1,UCBINX ; No space MOVEM T1,UCBH ; (Ext) Loc of hash table. IF1 > MOVSI UCBX,-UCBHSZ ; Set to scan UCBH (assumes QSZ==1) UCBIN1: HRRZ T1,UCBX ; Index within UCBH table ADD T1,UCBH ; Pointer to table base CALL INITQ ; Initialize as a queue AOBJN UCBX,UCBIN1 ; Loop over all slots SETZM UCBHUC ; Clear the use count XMOVEI T1,UCBHLK ; Pointer to the lock on UCBH CALL CLRLCK ; Initialize it UCBINX: RESTORE RET ; Routine to get unique access to the UCB Hash table. This means having ; it locked with the UCBH Use Count = 0. UHLOCK: XMOVEI T1,UCBHLK ; Pointer to the UCBH Lock CALL SETLCK ; Test and set the lock SKIPG UCBHUC ; UCBH Use Count. Any readers? RET ; OK we have sole access XMOVEI T1,UCBHLK ; Pointer to the lock CALL UNLCK ; Unlock it. MOVEI T1,UCBHUC ; Pointer to the use count CALL DISE ; Wait for it to go to zero JRST UHLOCK ; and try again. ; Hash table unlock routine UUNLCK: MOVEI T1,UCBHLK ; Pointer to the UCBH lock CALL UNLCK ; Unlock the lock RET ; and return to caller ;NEWUCB ;Initialize a new connection block. ;T1/ PARAMS ; (Ext) address of parameter block ;T2/ UCBX ; (Ext) Adr of UCB Hash table entry ; CALL NEWUCB ;Ret+1: always. UCB points to the UCB or is 0 if no space, ; too many conn, no wait bits NEWUCB: CHKADL (UCBX) MOVEM T1,PARAMS ; Argument block address MOVEM T2,UCBX ; Where to enqueue new UCB MOVE T2,UCBCNT ; Current number of connections CAML T2,UCBMAX ; Test against max we support at once JRST NEWUCE ; No room for another. MOVX T1,UCBSIZ ; Size of a connection block CALL GETBLK ; Get a block of free storage JUMPE T1,NEWUCE ; None available. Fail. MOVEM T1,UCB ; Put (ext) adr in standard place MOVX T2,UCBSIZ ; Size again for CLRBLK CALL CLRBLK CALL ASNWTB ; Assign a wait bit index for input JUMPL T1,NEWUCZ ; Jump if we didn't get the bit. STOR T1,UCBWAI,(UCB) ; Set into TCB CALL CLRWTB ; Initialize to zero state (empty queue) SKIPN JCN ; Call from JSYS (always?) IFSKP. MOVE T1,JOBNO ; Get current job STOR T1,UCBJOB,(UCB) ; Save in UCB MOVE T1,FORKX ; Get current fork STOR T1,UCBFRK,(UCB) ; Save MOVEI T1,77 ; Null PSI chan STOR T1,UCBIFD,(UCB) ; Save ENDIF. MOVE T1,LH ; Set the local host STOR T1,UCBLH,(UCB) MOVE T2,LP ; Set the local port STOR T2,UCBLP,(UCB) MOVE T3,FH ; Set the foreign host STOR T3,UCBFH,(UCB) MOVE T4,FP ; Set the foreign port STOR T4,UCBFP,(UCB) XMOVEI T1,UCBINQ(UCB) ; UCB Input queue CALL INITQ ; Initialize it. XMOVEI T1,UCBLCK(UCB) ; Pointer to the UCB lock CALL CLRLCK ; Clear it. XMOVEI T1,UCBQ(UCB) ; (Ext) Pointer to the UCB just initialized MOVE T2,UCBX ; (Ext) Adr of UCB Hash table entry (of Q's) CALL NQ ; Place it on the right queue AOS UCBCNT ; Count as another connection EXIT NEWUCX NEWUCZ: MOVE T1,UCB ; Pointer to the connection block CALL RETBLK ; Give back that storage NEWUCE: SETZ UCB, ; Tell caller the bad news. NEWUCX: CHKADR RET ;RELUCB ;Release resources held by UCB (in T1) RELUCB:: SAVEAC MOVE UCB,T1 ; Get UCB XMOVEI T1,UCBHLK ; Get lock pointer XMOVEI T2,DQUCB ; Call helper -- remove from hash table CALL LCKCAL ; Call helper while locked DO. LOAD T1,QNEXT,<+UCBINQ(UCB)> ; Get first thing on input Q CAIN T1,UCBINQ(UCB) ; Is that the head itself? EXIT. ; Yes. The queue is now empty. SETSEC T1,INTSEC ; Make extended address CALL DQ ; Remove from the Retransmission queue SETZRO PPROG,(T1) ; Program level now has no claim on PKT JN PINTL,(T1),TOP. ; Jump if INTRBF will return the space MOVE PKT,T1 ; Put pointer in right place for RETPKT CALL RETPKT LOOP. OD. LOAD T1,UCBWAI,(UCB) ; Get wait bit CALL RELWTB ; Release it XMOVEI T1,UCBLCK(UCB) ; Pointer to the lock CALL RELLCK ; Delete that MOVE T1,UCB CALL UDPBFD ; Release buffers MOVE T1,UCB CALL RETBLK ; Return the storage SOS UCBCNT ; Now one less connection RET ;Called with UCB hash table locked DQUCB: MOVEI T1,UCBHUC ; Get hash table reader count address SKIPE (T1) ; Any readers? CALL DISE ; Yes, wait for them to go away MOVE T1,UCB ; Get UCB CALL DQ ; Dequeue from hash table RET SUBTTL OPEN a connection ;UOPEN ; T1/ PROTO UCB ; CALL UOPEN ;returns BBN error or new (real/open) UCB ;proto UCB *ALWAYS* gets zapped! UOPEN:: SAVEAC STACKL <,PUCB> CHKADL ; Generate access to argblock MOVE UCB,T1 ; Get UCB in normal place MOVEM UCB,PUCB ; Save proto UCB MOVEI PARAMS,ARGBLK ; Arg area on stack (ref. via sec. 0) LOAD T1,UCBLH,(UCB) ; Local Host JUMPE T1,UOPEN9 ; SHOULD NEVER HAPPEN MOVEM T1,LH ; Store LOAD T1,UCBLP,(UCB) ; Local port JUMPE T1,UOPEN9 ; SHOULD NEVER HAPPEN MOVEM T1,LP ; Store LOAD T1,UCBFH,(UCB) ; 4n Host MOVEM T1,FH ; Store LOAD T1,UCBFP,(UCB) ; 4n Port MOVEM T1,FP ; Store SETOM JCN ; Flag call is from JSYS SETZM WILDOK ; No wild matches please XMOVEI T2,UOPEN1 ; Function to call if found MOVEM T2,FN ; Save MOVEM UCB,ARG1 ; Pass proto UCB as ARG1 SETZM ARG2 ; No ARG2 MOVE T1,PARAMS ; Arg block for UCHECK CALL UCHECK ; Search or Create JRST UOPENX ;Here with bad local port/host UOPEN9: MOVE T1,PUCB ; Get proto UCB CALL RETBLK ; Dispose of it HRROI T1,ELP+^D13 ; 'Unable to decode local' (TCPXX8) UOPENX: CHKADR ; Undo argblock RET ;UOPEN1 ;Called from UOPEN via UCHECK ; Here with real UCB locked, JCN in T1, ARG1 (proto) in T2 ; *ALWAYS* zaps proto UOPEN1: STACKL MOVEM T2,PUCB ; Save proto UCB TMNN UCBOPN,(UCB) ; Already open?? IFSKP. MOVE T1,PUCB ; Get proto pointer CALL RETBLK ; Dispose of it HRROI T1,ELT+^D6 ; Connection already exists (TCPX19) RET ; NO!! Someone has local port assigned ENDIF. ;;; Copy proto UCB into real UCB SETONE UCBOPN,(UCB) ; Declare we are a real (open) UCB MOVE T2,PUCB ; Get proto addr MOVE T3,UCB ;get real UCB address DO. ;prototype to real UCB copying routine SKIPN (T3) ;is real UCB word not set? SKIPN T4,(T2) ;yes and prototype UCB word set? SKIPA ;real set or prototype not set MOVEM T4,(T3) ;set it in the real UCB if non zero AOS T4,T3 ;bump real offset and copy SUB T4,UCB ;subtract UCB base address CAIGE T4,UCBSIZ ;are we done yet? AOJA T2,TOP. ;no so bump proto offset and continue OD. MOVE T1,PUCB ; Get proto pointer CALL RETBLK ; Dispose of it MOVE T1,UCB ; Return new UCB RESTORE RET SUBTTL UDP I/O OPERATIONS ;UGET - Get data from IP buffer into JFN buffer ; T1/ UCB UGET:: MOVE T3,T1 ; Copy args XMOVEI T1,UCBLCK(T1) ; Lock address XMOVEI T2,UGET1 ; Helper address CALL LCKCAL RET ;UGET1 ; T1/ UCB (locked) ;Returns ; T1/ Data length (octets) UGET1: SAVEAC STACKL MOVE UCB,T1 ; Get UCB addr SKIPE UCBCTR(UCB) ; Anything there? IFSKP. LOAD T1,UCBWAI,(UCB) ; Get wait bit number CALL CLRWTB ; Clear it SETZ T1, ; Say nothing there JRST UGETZ ; Return ENDIF. LOAD T1,QNEXT,<+UCBINQ(UCB)> ; Get first thing on input Q SETSEC T1,INTSEC ; get extended address MOVE PKT,T1 ; Save packet addr CALL DQ ; Remove from input Q SOS UCBCTR(UCB) ; one less in queue XMOVEI UPKT,PKTELI(PKT) ; Pointer to Internet packet LOAD T3,PIDO,(PKT) ; Internet Data Offset ADD UPKT,T3 ; Pointer to UDP packet LOAD T1,PISH,(PKT) ; Get source host STOR T1,UCLFH,(UCB) ; Save as last 4n host LOAD T1,PUDPSP,(UPKT) ; Load source port STOR T1,UCLFP,(UCB) ; Save as last 4n port LOAD T1,PUDPLN,(UPKT) ; Get UDP length field SUBI T1,UDPHLN*4 ; less UDP header MOVEM T1,LENG ; Save (octets) ADDI T1,3 ; Add bytes/word - 1 LSH T1,-2 ; Divide by bytes/word CAMLE T1,UDPBSZ ; Will it fit in a buffer? MOVE T1,UDPBSZ ; NO!? must truncate MOVE T2,UPKT ; Get address of UDP packet ADDI T2,UDPHLN ; Get address of UDP data MOVE T3,UCBIBF(UCB) ; Get dest buffer CALL XBLTA ; Transfer data CALL RETPKT ; Return packet MOVE T1,LENG ; Get length back (octets) UGETZ: RESTORE RET ; UBPUT -- block put -- worker for UOU MTOPR% function ; T1/ UCB ; CALL UBPUT ; Returns 0 for success UBPUT:: MOVE T3,T1 ; Copy args XMOVEI T1,UCBLCK(T1) ; Lock address XMOVEI T2,UBPUT1 ; Helper address CALL LCKCAL RET UBPUT1: SAVEAC ; Save ACs we normally use LOCAL ; 4n host and port MOVE UCB,T1 ; Get UCB in canonical place LOAD FH,UCBFH,(UCB) ; Get default 4n host MOVEI T1,.UDADR ; Get block offset CALL GETWRD ; Get new addr from block SKIPE T2,FH ; None there - default ok? SKIPN FH,T2 ; Copy new value JRST UBPOK ; must have host LOAD FP,UCBFP,(UCB) ; Get default 4n port MOVEI T1,.UDPRT ; Get block offset CALL GETWRD ; Try to read MTOPR block SKIPE T2,FP ; None there - default ok? SKIPN FP,T2 ; Use new value if non zero JRST UBPOK ; must have port MOVEI T1,.UDSIZ ; Get number of octets CALL GETWRD ; from MTOPR block JRST UBPOK ; Sigh SKIPG SIZE,T2 ; Save JRST UBPOK ; .LE. 0 ?? MOVE T1,UDPBSZ ; Get max data size in words LSH T1,2 ; Get in octets CAMLE SIZE,T1 ; Will it fit? MOVE SIZE,T1 ; No, truncate CALL USET ; Set up IP buffer JRST UBPX ; LOSS! STOR FH,PIDH,(PKT) ; Store 4n host STOR FP,PUDPDP,(UPKT) ; Store 4n port MOVEI T1,.UDBUF ; Get buffer addr CALL GETWRD ; from MTOPR block into T2 JRST UBPOK ; MUST have buffer MOVEI T1,3(SIZE) ; Get rounded word count LSH T1,-2 XMOVEI T3,UDPHLN(UPKT) ; get dest CALL BLTUM1 ; Copy from user with default section CALL UDPCKS ; Get checksum STOR T1,PUDPCK,(UPKT) ; store UDP checksum CALL SNDGAT ; Send packet off!! MOVE T1,SIZE ; Get octets sent JRST UBPR ; return it. UBPOK: TDZA T1,T1 ; Happy return UBPX: SETO T1, ; Sad return UBPR: RESTORE RET ; UPUT -- Send JFN buffer ; T1/ UCB ; T2/ octet count in current buffer ; CALL UPUT ; Returns 0 for successs, else was unable to get IP buffer... ; Data is assumed to fit in one packet UPUT:: DMOVE T3,T1 ; Copy args XMOVEI T1,UCBLCK(T1) ; Lock address XMOVEI T2,UPUT1 ; Helper address CALL LCKCAL RET UPUT1: SAVEAC ; Save ACs we normally use MOVE UCB,T1 ; Get UCB in canonical place MOVE SIZE,T2 ; Save count TMNN UCBFH,(UCB) ; test for 4n host JRST UPUTOK ; nothing we can do TMNN UCBFP,(UCB) ; test 4n port JRST UPUTOK ; no place to dock CALL USET ; Setup for send.. get PKT, UPKT JRST UPUTX ; Could not get buffer LOAD T1,UCBFH,(UCB) ; Get Dest address STOR T1,PIDH,(PKT) ; store LOAD T1,UCBFP,(UCB) ; Get dest port STOR T1,PUDPDP,(UPKT) ; store MOVEI T1,3(SIZE) ; Get octets rounded LSH T1,-2 ; to words MOVE T2,UCBOBF(UCB) ; get output pointer XMOVEI T3,UDPHLN(UPKT) ; get dest CALL XBLTA ; copy CALL UDPCKS ; Get checksum STOR T1,PUDPCK,(UPKT) ; store UDP checksum CALL SNDGAT ; Send packet off!! UPUTOK: TDZA T1,T1 ; Happy return UPUTX: SETO T1, ; Sad return RET ;USET - Set up for send, get IP buffer & fill stuff in ; ; SIZE/ number of octets ; UCB/ locked UCB ; CALL USET ; ; ; ; PKT/ pointer to IP packet ; UPKT/ pointer to UDP packet USET: MOVEI T1,3(SIZE) ; round count LSH T1,-2 ; to words ADDI T1,PKTELI+UDPHLN+IPHLN ; add words for headers (Packet,IP,UDP) CALL GETBLK ; get block SKIPG PKT,T1 ; move to PKT RET ; no storage. MOVEI T2,PKTELI+IPHLN ; clear packet and IP headers CALL CLRBLK MOVEI T1,.INTVR STOR T1,PIVER,(PKT) ; Store protocol version number MOVEI T1,IPHLN ; # words in IP header STOR T1,PIDO,(PKT) ; Set as data offset SETO T3, ; Get maximum STOR T3,PITTL,(PKT) ; Set Time to Live MOVEI T3,.UDPFM ; UDP format STOR T3,PIPRO,(PKT) ; Set into protocol field LOAD T1,UCBLH,(UCB) ; Get Source address STOR T1,PISH,(PKT) ; store XMOVEI UPKT,PKTELI+IPHLN(PKT) ; point to UDP packet LOAD T1,UCBLP,(UCB) ; Get source port STOR T1,PUDPSP,(UPKT) ; store MOVEI T1,(SIZE) ; get data bytes + UDP header STOR T1,PUDPLN,(UPKT) ; store UDP length ADDI T1,IPHLN*4 ; add octets count for IP header STOR T1,PIPL,(PKT) ; Set IP packet length RETSKP ; Happy return SUBTTL UDP CHECKSUM ; This code adapted from Vince Fuller's UDPLIB ; ; Copyright (C) 1984 Vincent A. Fuller ; ; This software, in source and binary form, is distributed free of ; charge. The binary form of this software may be incorporated into ; public-domain software and the source may be used for reference ; purposes. Copies may be made of the source provided this copyright ; notice is included. Wholesale copying of the routines in this ; software or usage of this software in proprietary product without ; prior permission is prohibited. ; UPKT/ Pointer to UDP packet ; CALL UDPCKS ; T1/ Checksum UDPCKS: MOVEI T1,.UDPFM ; Start sum with protocol (constant) LOAD T3,PUDPLN,(UPKT) ; Get UDP length ADD T1,T3 ; First part of checksum PUSH P,T3 ; save octet count of packet LSH T3,-1 ; make count of 16-bit bytes ADDI T3,4 ; add on 4 bytes of pseudo-header MOVE T2,[POINT 16,-2(UPKT)] ; 16 bit bytes starting at Source Host DO. ILDB T4,T2 ; get a byte ADD T1,T4 ; add it in SOJG T3,TOP. ; loop for all bytes OD. POP P,T3 ; get back length value IFXN. T3,1 ; was it an odd number? ILDB T4,T2 ; get one more byte, then ANDI T4,177400 ; but only 8 bits ADD T1,T4 ; and add this one in ENDIF. DO. TDNN T1,[^-CKSMSK] ; any carry bits on? EXIT. ; nope LDB T4,[POINTR T1,<^-CKSMSK>] ; get carry bits ANDI T1,CKSMSK ; flush from the sum ADD T1,T4 ; fold into sum LOOP. ; loop until mo more carrys OD. CAIE T1,CKSMSK ; Would complement make a zero? XORI T1,CKSMSK ; No - complement RET ; Call from UPUT/UBPUT/UGET ; UPKT/ Pointer to UDP packet ; CALL PPKT ; ; Crushes nothing! PPKT: SAVEAC LOAD T4,PUDPLN,(UPKT) ; Get UDP length ADDI T4,8 ; add on 8 octets of pseudo-header MOVN T4,T4 ; Make AOBJN MOVSI T4,(T4) HRRI T4,1 ; Start at one.. MOVE Q1,[POINT 8,-2(UPKT)] ; 8 bit bytes starting at Source Host MOVEI T1,.PRIOU ; Output designator DO. ILDB T2,Q1 ; get a byte MOVEI T3,10 ; print in octal NOUT ; output TRN ; ?? HRROI T2,[ASCIZ " . "] ; delimit SETZ T3, ; clear for SOUT TRNN T4,^B11 ; Output 4 bytes yet?? HRROI T2,[BYTE (7) "M"-100, "J"-100] ; yes, do crlf SOUT ; print . or CRLF AOBJN T4,TOP. ; loop! OD. HRROI T2,[BYTE (7) "M"-100, "J"-100] SOUT MOVEI T1,.PRIOU ;[17] DOBE ;[17] wait for terminal output! RET TNXEND END ;* Local Modes: * ;* Comment Begin:"; " * ;* End: *