;;;-*-MIDAS-*-;;; .TYO6 .IFNM1 .TYO 40 .TYO6 .IFNM2 PRINTX/ included in this assembly. / IFNDEF CALL,CALL==: ; More efficient than macro. IFNDEF RET,RET==: IFNDEF NOP,NOP=: ; What the hell. IFNDEF JCRY0,JCRY0=: ;Jump on Carry from bit 0 (and clear flag) IFNDEF SYSCAL,{ DEFINE SYSCAL A,B .CALL [SETZ ? SIXBIT/A/ ? B ((SETZ))] TERMIN } IFNDEF PUSHER,{ DEFINE PUSHER AC,LIST IRP LOC,,[LIST] PUSH AC,LOC TERMIN TERMIN } IFNDEF POPPER,{ DEFINE POPER AC,LIST IRP LOC,,[LIST] POP AC,LOC TERMIN TERMIN } ;;; IDGEN - Generate a "unique" ID number. ;;; T/ address of counter ;;; Returns value in A. DEFINE IDGEN AC,CNTR SKIPN MYUIND ;Find my job index. .SUSET [.RUIND,,MYUIND] AOS CNTR ;Make up an ID for this query. MOVE T,CNTR .PDTIME TT, DPB T,[.BP 000777,AC] DPB TT,[.BP 777000,AC] TERMIN SUBTTL IP/UDP Defs. IP%VER==740000,, ; 0 IP Version # (= 4) IP%IHL==036000,, ; 0 IP Header Length in 32-bit wds - at least 5 IP%TOS==001774,, ; 0 Type Of Service IP%TOL==000003,,777760 ; 0 Total Length in octets (including header) IP%ID== 777774,, ; 1 Identification IP%FLG== 3,,400000 ; 1 Flags IP%FDF== 1,,0 ; Don't-Fragment flag IP%FMF== 400000 ; More-Fragments flag IP%FRG== 0,,377760 ; 1 Fragment Offset IP%TTL==776000,, ; 2 Time To Live IP%PTC== 1774,, ; 2 Protocol IP%CKS== 3,,777760 ; 2 Header Checksum IP%SRC==777777,,777760 ; 3 Source Address IP%DST==777777,,777760 ; 4 Destination Address ; 5 Start of options IP$VER==<.BP IP%VER,0> IP$IHL==<.BP IP%IHL,0> IP$TOS==<.BP IP%TOS,0> IP$TOL==<.BP IP%TOL,0> IP$ID== <.BP IP%ID, 1> IP$FLG==<.BP IP%FLG,1> IP$FRG==<.BP IP%FRG,1> IP$TTL==<.BP IP%TTL,2> IP$PTC==<.BP IP%PTC,2> %PTCIC==:1 ; Protocol ICMP %PTCTC==:6. ; Protocol TCP %PTCUD==:17. ; Protocol UDP IP$CKS==<.BP IP%CKS,2> IP$SRC==<.BP IP%SRC,3> IP$DST==<.BP IP%DST,4> ;;; USER DATAGRAM PROTOCOL $UDPHL==2 ;Length of a UDP header. $UDPH==5 ;Minimum buffer offset to UDP header. $UDPD==$UDPH+$UDPHL ;Buffer offset to UDP data. ; UDP fields UD$SRC==<242000,,0> ; 0 wd 1 Source port UD$DST==<042000,,0> ; 0 wd 2 Dest port UD$LEN==<242000,,1> ; 1 wd 1 # octets in data UD$CKS==<042000,,1> ; 1 wd 2 UDP checksum UD$DAT==<441000,,2> ; 2 Data - actually an ILDB pointer! ;;; IPQ dev OPEN control/mode bits %IQSYS==100 ; Set up System Queue (0 or 1) %IQSOU==200 ; System Queue 1 if set, otherwise 0 %IQUDP==400 ; Set up random queue for UDP (port # in FN1) ; .CALL IPKIOT - Internet Protocol Packet Transfer. ; Arg 1 is channel (must be open on IPQ:, specifies queue #) ; Arg 2 is address of buffer ; Arg 3 is count of words ; Val 1 is count of words read into user space (if any) ; Control bits specify function. If none, "read" is assumed. ; Get datagram from: %IPIUS==100 ; 1 = Get datagram from user space, not from a queue %IPNOC==200 ; Global input no-check flag, suppresses normal check. ; For User Space, "check" means verify, set cksum. ; For Input Queue, "check" means verify IP header. ; For SysIn Queue, "check" means verify IP hdr. ; For SysOut Queue, means nothing. %IPNOH==400 ; Don't Hang waiting for datagram (Queues only) %IPIQK==1000 ; Keep on queue, don't remove (only for %IPOUS) ; Put datagram to: %IPOUS==0 ; User space %IPOUT==1 ; Output to network (bypasses SysOut queue) %IPOFL==2 ; Flush it %IPORV==3 ; Re-vector to input queues past this one ;;; PKTDPB macro for plunking down into a field (index packet off W). DEFINE PKTDPB PTR,-VAL MOVE T,VAL MOVE TT,[PTR (W)] DPB T,TT TERMIN ;;; DPWIDE macro deposits 16 bit quantity down 8-bit Bp. DEFINE DPWIDE PTR,-VAL MOVE T,VAL SETZ TT, LSHC T,-8. LSH TT,-<36.-8.> IDPB T,PTR IDPB TT,PTR TERMIN ;;; LBWIDE macro reads 16 bit quantity from an 8-bit Bp. DEFINE LBWIDE AC,-PTR SETZ AC, ILDB T,PTR LSH T,8. ILDB TT,PTR ADD T,TT MOVE AC,T TERMIN SUBTTL IP/UDP Routines ;;; These routines require ACs: W, A-E, smashable T,TT, and P. ;;; Args passed in ACs, code is pure, etc. etc. etc. .SCALAR MYUIND ;Our ITS job number. .SCALAR PKTID ;Packet number we've sent. .SCALAR LOCPRT ;Local port number where we listen. .SCALAR UDLENG ;Length of data user put in datagram. ;;; UDPOPN - Open a UDP queue. ;;; A/ channel number UDPOPN: PUSH P,C .GENSYM C, ANDI C,177777 MOVEM C,LOCPRT ;Remember local port, and open IPQ on it. SYSCAL OPEN,[%CLBIT,,%IQUDP ? A ? [SIXBIT /IPQ/] ? C ] CAIA AOS -1(P) POP P,C RET ;;; Someday it will be useful to have a routine which ;;; sends a packet and waits for a response, re-sending ;;; the packet if no response comes in reasonable time. ;;; UDPSND and UDPRCV - Trivial UDP I/O functions. ;;; W/ packet addr ;;; A/ UDP channel number ;;; B/ bytes in the packet ;;; ;;; UDPRCV returns words received in E. UDPSND: PUSHER P,[B,C] IDIVI B,4. SKIPE B+1 AOS B SYSCAL IPKIOT,[%CLBIT,,%IPIUS+%IPOUT ? A ? W ? B ] CAIA AOS -2(P) POPPER P,[C,B] RET UDPRCV: SYSCAL IPKIOT,[A ? W ? B ? %CLOUT,,E] CAIA AOS (P) RET ;;; MAKPKT - Make a packet (put IP and UDP headers on it). ;;; W/ packet addr ;;; A/ foreign host ;;; B/ foreign port ;;; C/ length of data stuffed into it ;;; Returns with C updated to total packet length. MAKPKT: PUSHER P,[A,D,W] MOVEM C,UDLENG IPHDR: PKTDPB IP$VER,[4] ;Version 4 IP header (RFC791). PKTDPB IP$IHL,[5] ;Usual length of IP packet header. PKTDPB IP$TOS,[0] ;Default type of unreliable service. PKTDPB IP$PTC,[%PTCUD] ;Protocol is UDP. IDGEN D,PKTID ;Gensym a packet ID number. PKTDPB IP$ID,D ;Stuff it in. IFN 0, PKTDPB IP$FLG,[3] ;No fragmentation allowed. PKTDPB IP$TTL,[30.] ;Half-minute lifetime. PUSHER P,[A,B] SYSCAL NETHST,[%CLIMM,,-1 ? %CLOUT,,T ? %CLOUT,,A] .LOSE %LSFIL LSHC A,-6 ;Standardize our ARPAnet host number. LSH B,-<2+8.> ;Put 10 bits spacing between host/imp #s. LSHC A,<2+8.+6> TLO A,(12_24.) ;Add ARPA network number. MOVE T,A POPPER P,[B,A] LSH T,<36.-32.> ;Get our own host address. MOVEM T,IP$SRC(W) ;Stuff it in. MOVE T,A ;Get destination host address. LSH T,<36.-32.> ;Stuff it in. MOVEM T,IP$DST(W) ADDI C,20. ;Update count to include 5 word IP header. ADDI C,8. ;Update our count to include 2 word UDP header. PKTDPB IP$TOL,C ;Stuff it in. CALL IPCKSM ;Compute the header checksum. PKTDPB IP$CKS,A ;Stuff it in. UDPHDR: ADDI W,$UDPH ;Make ptr to UDP header. PKTDPB UD$SRC,LOCPRT ;Stuff in the source port. PKTDPB UD$DST,B ;Stuff in the destination port. MOVE D,UDLENG ADDI D,8. PKTDPB UD$LEN,D ;Stuff in the user datagram length. SUBI W,$UDPH ;Pointer to entire packet. CALL UDCKSM ;Compute UDP checksum from there. ADDI W,$UDPH ;Now point back into UDP datagram. PKTDPB UD$CKS,A ;Stuff it in. POPPER P,[W,D,A] RET ;;; IPCKSM - Compute IP packet checksum (stolen from ITS INET module). ;;; W/ addr of IP packet ;;; Returns checksum in A. ;;; Does not handle headers with options IPCKSM: PUSH P,B SETZ A, ;Compute header checksum in A. MOVE B,IP$CKS(W) ;Get 3rd word ANDCM B,[IP%CKS] ;Mask out the checksum field JFCL 17,.+1 ;Clear flags ADD B,IP$VER(W) ;Add 1st wd JCRY0 [AOJA A,.+1] ADD B,IP$ID(W) ;Add 2nd JCRY0 [AOJA A,.+1] ADD B,IP$SRC(W) ;Add 4th JCRY0 [AOJA A,.+1] ADD B,IP$DST(W) ;Add 5th JCRY0 [AOJA A,.+1] IPCKS2: LSHC A,16. ;Get high 2 bytes (plus carries) in A LSH B,-<16.+4> ;Get low 2 bytes in B IPCKS3: ADDI A,(B) ;Get total sum CAILE A,177777 ;Fits? JRST [ LDB B,[202400,,A] ;No, must get overflow bits ANDI A,177777 ;then clear them JRST IPCKS3] ;and add in at low end. ANDCAI A,177777 ;Return ones complement POP P,B RET ;;; UDCKSM - UDP checksum (stolen from SYSNET;IPLIST) ;;; W/ addr of IP packet ;;; Returns checksum in A. CARMSK==<-1,,600000> UDCKSM: PUSHER P,[B,C,D,E] MOVEI D,(W) LDB A,[IP$SRC (D)] ;Source addr LDB B,[IP$DST (D)] ;Dest addr ADD A,B LDB B,[IP$PTC (D)] ;Protocol ADDI A,(B) LDB B,[IP$TOL (D)] ;Get total length in octets LDB C,[IP$IHL (D)] ;Find IP header length in 32-bit wds ADDI D,(C) ;Change pointer to UDP seg LSH C,2 ;mult by 4 to get # octets SUBI B,(C) ;Find # octets of IP data (TCP segment) CAIL B, ;If negative, skip this one. ADDI A,(B) ;; Done with pseudo header (not folded yet, though). ;; B has # octets in the UDP segment. ;; D now points to the UDP segment. LDB C,[UD$SRC (D)] ADDI A,(C) LDB C,[UD$DST (D)] ADDI A,(C) LDB C,[UD$LEN (D)] ADDI A,(C) MOVEI C,-<2*4>(B) ;Get # bytes of remaining data in C LSHC A,-16. LSH B,-<16.+4> ADDI A,(B) ;Now have it folded up. JUMPLE C,UDPCK7 MOVEI E,2(D) HRLI E,442000 ;Set up 16-bit byte ptr LSHC C,-1 JUMPLE C,UDPCK6 UDPCK5: ILDB B,E ADDI A,(B) SOJG C,UDPCK5 UDPCK6: JUMPL D,[ ;Jump if odd byte left. ILDB B,E ;get it ANDCMI B,377 ;mask off low (unused) byte. ADDI A,(B) JRST .+1] UDPCK7: TDNE A,[CARMSK] ;If any carries, add them in. JRST [ LDB B,[.BP CARMSK,A] TDZ A,[CARMSK] ADD A,B JRST UDPCK7] ANDCAI A,177777 ;Complement sum and mask off. UDCKS9: POPPER P,[E,D,C,B] RET