NIC EhBASIC driver. by Lee Davison |
ChangesThis code provides ARP, ICMP and TCP/IP function enough to be PINGed and to serve the four embedded web pages. It's not fast, taking 2000+ mS for a PING reply and as little as forty seconds to serve a web page, but it does work.
Another version for the 3Com 3C509B series of cards is available.
The code has been tidied to remove some un needed variables and to merge the payload buffers into one. A timer has been implemented to allow the TCP state machine to time out without having to wait for any number of TCP packets to arrive. Lastly the last two IP address digits are now copied from the MAC address of the card, so you don't have to clear the ARP tables every time you try a new card.
This is not a finished product by any means, it is just a proof of concept, and is presented only as a starting point for anyone else.
Things to note.
Lines that start with a colon are completely ignored by the interpreter.
Strings in DATA statements do not need quotes round them as long as they don't contain colons or commas, and do not start with spaces. Strings without quotes start with the first non space character after the DATA keyword or comma.
: ********************************************************************* : generic 8390/NEx000 driver in EhBASIC : supports ARP, ICMP echo, passive TCP/IP & very basic HTTP : changes :03/09/02 : now gets last two digits of the IP address from the card MAC :03/08/21 : now includes TCP timeouts using an onboard timer :03/08/20 : ethernet header and payload buffers merged into ip(i) 10 DIM ph(3) : REM packet header buffer 11 DIM pr(31) : REM NIC card PROM contents 12 DIM ip(1513) : REM packet buffer 15 DIM mi(3) : REM my ip address 16 mi(0)=169 : mi(1)=254 : REM get last digits from MAC address 17 cr$ = CHR$($0D) : lf$ = CHR$($0A) : el$ = cr$+lf$ : 38067 port equates 20 p4 = $08 : REM port 4 data 21 d4 = $09 : REM port 4 direction 22 d6 = $0D : REM port 6 direction : assembly routines to read and write to NIC 30 DOKE $44,$EF20 : REM USR(n) = read from NIC register n 31 rr = $EF00 : REM write to NIC call address : initialise ports 40 POKE p4,PEEK(p4) OR $83 : REM no read, nowrite and reset 41 POKE d4,PEEK(d4) OR $83 : REM port bits to outputs 42 POKE d6,PEEK(d6) OR $1F : REM address bits to outputs 44 FOR w=1 TO 6 : NEXT : REM delay for at least 1.6mS 46 POKE p4,PEEK(p4) AND $7F : REM no reset : vc flags that a potentially valid card is present : vp flags that a potentially valid packet is being processed 50 vc = 0 : REM no valid card found 51 vp = 0 : REM no valid packet received : frequently used values 60 cr = $00 : REM NIC command register 61 dr = $10 : REM NIC data register 62 is = $07 : REM NIC interrupt status register 63 ls = $08 : REM NIC start address low byte 64 hs = $09 : REM NIC start address high byte 65 lc = $0A : REM NIC byte count low byte 66 hc = $0B : REM NIC byte count high byte 67 rc = $0C : REM NIC config Rx 68 tc = $0D : REM NIC config Tx : TCP arrays & variables 70 ts = 1 : REM TCP state = listen 71 DIM rn(3) : REM received TCP sequence number 72 DIM mq(3) : REM our TCP sequence number 73 DIM si(3) : REM senders ip address : ********************************************************************* : test for NIC and initialise if found 100 GOSUB 10000 : REM look for NIC 105 IF vc=0 THEN END : REM no card found 110 GOSUB 10500 : REM initialise NIC 115 INT0 + : REM interrupt on rising edge 120 ON INT0 20000 : REM handle interrupt 125 PRES12 249 : TIMER1 199 : REM set for approx 100mS 130 ON TIMER1 12000 : REM go do countdown : ********************************************************************* : main program loop 200 DO 205 ? : ? "Waiting..." 210 DO : LOOP UNTIL vp : REM wait for valid packet : now decipher packet info 255 IF ip($0C)<>8 THEN ? "Unrecognised packet type" : GOTO 275 260 IF ip($0D)=6 THEN GOSUB 21000 : GOTO 275 : REM ARP packet 265 IF ip($0D) THEN ? "Unknown IP packet type" : GOTO 275 : only type left is known IP type 270 GOSUB 21500 : REM handle known IP packet type : now see if any more packets are in the buffer 275 CALL rr,cr,$22 : REM page 0, no DMA 285 bd = USR($03)+1 : REM get buffer boundary value + 1 290 IF bd=$61 THEN bd = $46 : REM wrap pointer 295 CALL rr,cr,$62 : REM page 1, no DMA 300 cp = USR($07) : REM get buffer current page 305 IF cp=bd THEN vp = 0 : GOTO 995 : REM flag done with last packet : else possibly more data in buffer, so go get and validate packet 310 GOSUB 11500 : REM get the packet from the NIC : if packet valid then don't wait, just do it 315 IF vp THEN 255 : REM if valid then go process it : else just ignore it and check for next 325 GOTO 275 : REM else go check for more packets 995 LOOP 999 END : REM should never get here : ********************************************************************* : try and find an NEx000 type network interface card 09999 REM probe NIC 10000 CALL rr,cr,$20 : REM page 0, no DMA 10005 by = USR($0D) : REM clear the counter 10010 by = USR($0D) : REM get the counter : now if the counter <> 0, then we don't have a NEx000 card, so exit 10015 IF by THEN ? "No card found!" : RETURN : found a card so reset it 10020 CALL rr,is,$80 : REM clear reset bit 10025 IF (USR(is) AND $80) THEN ? "Can't clear reset ack!" : RETURN : it's reset now test the interrupt connection 10030 CALL rr,is,$FF : REM clear all pending interrupts 10035 IF (PEEK(p4) AND $04) THEN ? "Can't clear interrupt!" : RETURN : read the NIC PROM into array : we probably only need the first 6 bytes which : are this card's MAC address 10040 CALL rr,cr,$21 : REM page 0, stop 10045 CALL rr,$0E,$48 : REM 8 byte FIFO, normal operation 10050 CALL rr,lc,$00 : REM set remote byte count low 10055 CALL rr,hc,$00 : REM set remote byte count high 10060 CALL rr,$0F,$00 : REM mask all interrupts off 10065 CALL rr,is,$FF : REM ack all pending interrupts 10070 CALL rr,rc,$20 : REM Rx config to no store & reject (nearly) all 10075 CALL rr,tc,$02 : REM Tx config to internal loopback 10080 CALL rr,lc,$20 : REM set remote byte count low 10085 CALL rr,hc,$00 : REM set remote byte count high 10090 CALL rr,ls,$00 : REM set remote start address low 10095 CALL rr,hs,$00 : REM set remote start address high 10100 CALL rr,cr,$0A : REM remote read 10105 FOR i=0 TO 31 : REM loop 31 times 10110 by = USR(dr) : pr(i) = USR(dr) : REM dummy read then read byte 10115 ? " ";HEX$(pr(i),2); : REM display value 10120 IF (i AND $7)=$7 THEN ? 10125 NEXT 10127 mi(2)=pr(4) : mi(3)=pr(5) : REM IP address last two digits : lets try triggering an interrupt and see if all is well 10130 CALL rr,$0F,$50 : REM allow DMA complete and overwrite warning 10135 CALL rr,lc,$00 : REM set receive byte count low 10140 CALL rr,hc,$00 : REM set receive byte count high 10145 CALL rr,cr,$0A : REM trigger it with remote read : wait a small amount of time, if no interrupt then assumed broken card : note main interrupt handling is not started yet 10150 to = 1000 : REM set timeout count 10155 DO 10160 by = PEEK(p4) AND $04 10165 DEC to 10170 LOOP UNTIL by OR (to=$00) 10175 CALL rr,$0F,$00 : REM mask it off again 10180 IF to=0 THEN ? "No interrupt!" : RETURN 10185 ? "Card OK - IP address 169 . 254 .";mi(2);" .";mi(3) 10190 vc = -1 : REM flag card found 10195 RETURN : ********************************************************************* : initialise the NIC : use National Semiconductors 8390 programming sequence 10499 REM initialise NIC 10500 CALL rr,cr,$21 : REM page 0, stop 10510 CALL rr,$0E,$48 : REM 8 byte FIFO, normal operation 10515 CALL rr,lc,$00 : REM clear remote byte count low 10520 CALL rr,hc,$00 : REM clear remote byte count high : set monitor and loopback mode 10525 CALL rr,rc,$20 : REM Rx config to no store & reject (nearly) all 10530 CALL rr,tc,$02 : REM Tx config to internal loopback : set transmit page and receive ring 10535 CALL rr,$04,$40 : REM set Tx start page 10540 CALL rr,$01,$46 : REM set Rx start page 10545 CALL rr,$03,$60 : REM set boundry 10550 CALL rr,$02,$60 : REM set Rx stop page : clear any pending interrupts 10555 CALL rr,is,USR(is) : REM ack all pending 10560 CALL rr,$0F,$00 : REM mask all interrupts : copy MAC address to the network card 10565 CALL rr,cr,$61 : REM page 1, stop 10570 FOR i=0 TO 5 : REM need to shift in 6 bytes 10575 CALL rr,i+1,pr(i) : REM byte from prom to card 10580 NEXT 10585 FOR i=$08 TO $0F : REM need to shift in 8 bytes 10590 CALL rr,i,$FF : REM set multicast mask byte 10595 NEXT 10600 CALL rr,$07,$46 : REM set current page 10605 CALL rr,cr,$21 : REM page 0, stop 10610 CALL rr,is,$FF : REM ack all interrupts 10615 CALL rr,$0F,$3F : REM allow all interrupts 10620 CALL rr,cr,$22 : REM page 0, no DMA : enable the transmitter 10625 CALL rr,tc,$00 : REM Tx to normal : enable the receiver 10630 CALL rr,rc,$04 : REM Rx to accept broadcast 10635 np = $46 : REM init no packets received 10640 RETURN : ********************************************************************* : get the ethernet header from the NIC - puts it in ph(n) 10999 REM GetHdr 11000 CALL rr,cr,$22 : REM page 0, no DMA 11010 CALL rr,lc,$04 : REM set header length low 11015 CALL rr,hc,$00 : REM set header length high 11020 CALL rr,ls,$00 : REM From this page low 11025 CALL rr,hs,np : REM From this page high 11030 CALL rr,cr,$0A : REM remote read 11035 FOR i=0 TO 3 11040 ph(i) = USR(dr) : REM get byte 11045 NEXT 11050 CALL rr,cr,$22 : REM page 0, no DMA 11060 RETURN : ********************************************************************* : get the packet from the NIC : gets the header and the payload when a good packet is indicated : sets vp true if packet is really valid 11499 REM get packet 11500 vp = -1 : tp = vp : REM flag getting packet & this packet good 11505 CALL rr,cr,$60 : REM page 1, no DMA 11510 cp = USR($07) : REM read current Rx page 11515 IF cp=np THEN tp = 0 : GOTO 11570 : REM if curr = next then exit 11520 GOSUB 11000 : REM else get the header 11525 IF (ph(0) AND $01)=0 THEN : tp = 0 : GOTO 11550 : REM dump bad 11530 GOSUB 11700 : REM else was an OK packet so get it 11535 IF rl>1500 THEN tp = 0 : REM dump packets that are too big 11540 np = ph(1) : REM get next page value 11545 cp = np : REM make current page = next page 11547 IF np=$60 THEN np = $46 11550 DEC cp : REM boundary is always 1 less than next page 11555 IF cp=$45 THEN cp = $60 : REM roll ring back 11560 CALL rr,cr,$22 : REM page 0, no DMA 11565 CALL rr,$03,cp : REM set new boundary 11570 vp = tp : REM set packet status to this packet status 11575 RETURN : ********************************************************************* : gets the payload from the NIC : the ethernet packet and payload is stored in ip(i) 11699 REM BlockInput 11700 rl = ph(2)+ph(3)*256 : REM get length 11705 IF ph(2) AND 1 THEN INC rl : REM make even 11710 IF rl>1500 THEN 11775 : REM dump too big packets 11715 CALL rr,cr,$22 : REM page 0, no DMA 11720 CALL rr,lc,ph(2) : REM size of payload low byte 11725 CALL rr,hc,ph(3) : REM size of payload high byte 11730 CALL rr,ls,$04 : REM + 4 to remove the header from the frame 11735 CALL rr,hs,np : REM set page pointer 11740 CALL rr,cr,$0A : REM page 0, remote read 11745 FOR i=0 TO rl-1 : ip(i) = USR(dr) : NEXT : REM read bytes 11770 CALL rr,cr,$22 : REM page 0, no DMA 11775 RETURN : ********************************************************************* : does the timeout counting down, called on TIMER 1 timeout (100mS) 11999 REM decrement the TCP rimeout counter if <> 0 12000 IF sc THEN DEC sc 12005 RETURN : ********************************************************************* : on NIC interrupt do this. this does most of the work deciding what to : do and acknowledging interrupts 19999 REM NIC interrupt 20000 CR = USR(cr) : REM get current command value 20005 CALL rr,cr,$20 : REM page 0, no DMA 20010 ib = USR(is) AND $7F : REM get interrupt status value 20015 DO 20020 IF (ib AND $10) THEN GOSUB 20500 : REM do overwrite interrupt 20025 IF (ib AND $0A) THEN GOSUB 20200 : REM do tx interrupt 20030 IF (ib AND $40) THEN GOSUB 20300 : REM do DMA interrupt 20035 IF (ib AND $20) THEN GOSUB 20400 : REM do tally counter interrupt 20040 IF (ib AND $05) THEN GOSUB 20100 : REM do rx interrupt 20045 CALL rr,cr,$20 : REM page 0, no DMA 20050 ib = USR(is) AND $7F : REM get interrupt status value 20055 LOOP WHILE ib 20060 CALL rr,cr,CR : REM return command status 20065 RETURN : ********************************************************************* : handle Rx interrupts : if good Rx and no current packet then get new 20100 IF (ib AND $01) AND (vp=0) THEN GOSUB 11500 20105 CALL rr,cr,$20 : REM page 0, no DMA 20110 CALL rr,is,(ib AND $05) : REM ack Rx interrupts 20120 RETURN : ********************************************************************* : handle Tx interrupt 20200 CALL rr,is,(ib AND $0A) : REM ack Tx interrupts :20205 ? "Packet sent" 20210 RETURN : ********************************************************************* : handle DMA interrupt 20300 CALL rr,is,(ib AND $40) : REM ack DMA interrupt :20305 ? "DMA" 20310 RETURN : ********************************************************************* : handle tally counter interrupt 20400 CALL rr,is,(ib AND $20) : REM ack tally counter interrupt :20405 ? "Tally count" 20410 RETURN : ********************************************************************* : handle overwrite interrupt : use National Semiconductors 8390 programming sequence 20500 CALL rr,cr,$21 : REM page 0, stop 20505 FOR w=0 TO 5 : REM wait a bit 20510 NEXT 20515 CALL rr,lc,$00 : REM clear remote byte count low 20520 CALL rr,hc,$00 : REM clear remote byte count high 20525 rs = $26 : REM default to resend 20530 IF (ib AND $04) THEN rs = $22 : REM not Txing so no resend 20535 IF (USR(is) AND $0A) THEN rs = $22 : REM Tx done or error 20540 CALL rr,tc,$02 : REM Tx config to internal loopback 20545 CALL rr,$03,$60 : REM set boundry 20550 CALL rr,cr,$61 : REM page 1, stop 20555 CALL rr,$07,$46 : REM set current page 20560 CALL rr,cr,$22 : REM page 0, no DMA 20565 CALL rr,is,(ib AND $10) : REM ack overwrite interrupt 20570 CALL rr,tc,$00 : REM Tx config to normal 20575 CALL rr,cr,rs : REM resend or start : warn the user that an overwrite occured 20578 ?"!! WARNING !! OVERWRITE INTERRUPT !! WARNING !!" 20580 np = $46 : cp = np : REM set no packets waiting 20590 RETURN : ********************************************************************* : construct a reply to an ARP request aimed at us 20999 REM handle ARP packet : see RFC826 for a description of the ARP packet 21000 IF ip($0F)<>$01 THEN 21265 : REM hardware type - always $01 21005 IF ip($10)<>$08 THEN 21265 : REM hardware protocol high byte 21010 IF ip($11)<>$00 THEN 21265 : REM hardware protocol low byte 21015 IF ip($12)<>$06 THEN 21265 : REM hardware (MAC) address length 21020 IF ip($13)<>$04 THEN 21265 : REM protocol (IP) address length 21025 IF ip($15)<>$01 THEN 21265 : REM type of packet 21030 IF ip($26)<>mi(0) THEN 21265 : REM protocol address 21035 IF ip($27)<>mi(1) THEN 21265 : REM protocol address+1 21040 IF ip($28)<>mi(2) THEN 21265 : REM protocol address+2 21045 IF ip($29)<>mi(3) THEN 21265 : REM protocol address+3 : we have recognised the packet as correct and the target as us : set up the buffer for transmit 21050 CALL rr,cr,$22 : REM page 0, no DMA 21055 CALL rr,$04,$40 : REM load beginning page for transmit buffer 21060 CALL rr,ls,$00 : REM set start address low byte 21065 CALL rr,hs,$40 : REM set start address high byte 21070 xl = $2A : REM ARP reply length 21075 CALL rr,lc,(xl AND $FF) : REM load data byte count low byte 21080 CALL rr,hc,(xl >> 8) : REM load data byte count high byte 21085 CALL rr,cr,$12 : REM do remote write operation 21090 FOR i=6 TO 11 : CALL rr,dr,ip(i) : NEXT : REM dest MAC address 21095 FOR i=0 TO 5 : CALL rr,dr,ip(i) : NEXT : REM source MAC address 21100 CALL rr,dr,$08 : REM ethernet packet type 21105 CALL rr,dr,$06 : REM ethernet packet type 21110 FOR i=$0E TO $14 : CALL rr,dr,ip(i) : NEXT : REM copy from rx pkt 21115 CALL rr,dr,$02 : REM op type is reply 21120 FOR i=0 TO 5 : CALL rr,dr,pr(i) : NEXT : REM our MAC address 21125 FOR i=0 TO 3 : CALL rr,dr,mi(i) : NEXT : REM our IP address 21130 FOR i=$6 TO $B : CALL rr,dr,ip(i) : NEXT : REM dest MAC address 21135 FOR i=$1C TO $1F : CALL rr,dr,ip(i) : NEXT : REM dest IP address : packet set up, now Tx it : ********************************************************************* : Tx ethernet packet, xl is length 21200 CALL rr,cr,$22 : REM page 0, no DMA 21205 IF xl>$3B THEN 21250 : if the packet is runt then fill it out to minimum length 21210 xd = $3C-xl 21215 CALL rr,ls,(xl AND $FF) : REM set start address low byte 21220 CALL rr,hs,$40 : REM set start address high byte 21225 CALL rr,lc,(xd AND $FF) : REM load data byte count low byte 21230 CALL rr,hc,$00 : REM load data byte count high byte 21235 CALL rr,cr,$12 : REM do remote write operation 21240 FOR i=1 TO xd : CALL rr,dr,$00 : NEXT : xl=$3C 21245 CALL rr,cr,$22 : REM page 0, no DMA : now set up Tx count and send the packet 21250 CALL rr,$05,(xl AND $FF) : REM set Tx length low byte 21255 CALL rr,$06,(xl >> 8) : REM set Tx length high byte 21260 CALL rr,cr,$26 : REM Tx packet 21265 RETURN : ********************************************************************* : handle IP ICMP packets 21499 REM handle ICMP packet 21500 IF ip($0E)<>$45 THEN 21565 : REM don't recognise anything else 21505 IF ip($1E)<>mi(0) THEN 21565 : REM is it our ip address 21510 IF ip($1F)<>mi(1) THEN 21565 : REM is it our ip address+1 21515 IF ip($20)<>mi(2) THEN 21565 : REM is it our ip address+2 21520 IF ip($21)<>mi(3) THEN 21565 : REM is it our ip address+3 21525 IF (ip($14) AND $3F) THEN 21565 : REM we don't handle fragments 21530 IF ip($15) THEN 21565 : REM we don't handle fragments 21535 ck = $0 : cl = $14 : ca = $0E : REM for header checksum 21540 GOSUB 21950 : REM do header checksum 21545 IF ck THEN 21565 : REM ignore broken checksum 21550 IF ip($17)=$01 THEN GOSUB 21600 : REM ip_proto is icmp 21555 IF ip($17)=$11 THEN ? "UDP" : REM ip_proto is udp 21560 IF ip($17)=$06 THEN GOSUB 22000 : REM ip_proto is tcp 21565 RETURN : ********************************************************************* : handle ICMP IP echo request packet - this is the bit that goes PING! 21599 REM icmp starts at $22 in the buffer 21600 ip($22) = $00 : REM icmp type (reply) 21605 ip($23) = $00 : REM icmp code 21610 ip($24) = $00 : REM clear checksum high byte 21615 ip($25) = $00 : REM clear checksum low byte 21620 GOSUB 21800 : REM setup the IP header 21625 ck = 0 : REM clear checksum 21630 ca = $22 : REM icmp starts after the IP header 21635 cl = (ip($10)*256+ip($11)) - $14 : REM data length 21640 GOSUB 21950 : REM do checksum 21645 ck = NOT ck : REM ones complement checksum 21650 ip($24) = ck >> 8 : REM save checksum high byte 21655 ip($25) = ck AND $FF : REM save checksum low byte : now transmit the packet : ********************************************************************* : transmit IP packet 21699 REM transmit IP packet 21700 CALL rr,cr,$22 : REM page 0, no DMA 21705 CALL rr,$04,$40 : REM set Tx start page 21710 CALL rr,ls,$00 : REM set start address low 21715 CALL rr,hs,$40 : REM set start address high 21725 xl = ip($10)*256+ip($11) + $0E : REM length is ip length + $0E 21730 CALL rr,lc,(xl AND $FF) : REM set remote byte count low 21735 CALL rr,hc,(xl >> 8) : REM set remote byte coung high 21740 CALL rr,cr,$12 : REM remote write : write data to buffer 21745 FOR i=0 TO xl-1 : CALL rr,dr,ip(i) : NEXT 21765 GOTO 21200 : REM transmit packet & return : ********************************************************************* : swap the sources and destinations (MAC and IP) and compute the : new IP checksum 21799 REM set IP addresses 21800 FOR i=$1A TO $1D : SWAP ip(i),ip(i+$04) : NEXT : swap IP addresses 21810 ip($16) = $80 : REM set time to live 21820 FOR i=0 TO 5 : SWAP ip(i),ip(i+6) : NEXT : swap MAC addresses 21830 ip($18) = $00 : REM clear checksum high byte 21835 ip($19) = $00 : REM clear checksum low byte : calculate the IP header checksum 21840 ck = 0 : REM clear checksum 21845 cl = $14 : REM header length 21850 ca = $0E : REM IP start 21855 GOSUB 21950 : REM do checksum 21860 ck = NOT ck : REM ones complement 21865 ip($18) = ck >> 8 : REM save checksum high byte 21870 ip($19) = ck AND $FF : REM save checksum low byte 21875 RETURN : ********************************************************************* : compute or check the 16 bit checksum on the TCP part of the packet : also gets the total length of the IP packet tl 21900 tl = (ip($10)*256+ip($11)) : REM IP total length 21905 ck = tl - ti + $0E : REM checksum is TCP length 21910 ck = ck + ip($17) : REM add protocol to checksum 21915 cl = 8 : ca = $1A : REM do source and dest IP address 21920 GOSUB 21950 : REM do IP address checksum 21925 cl = tl - ti + $0E : ca = ti : REM TCP length and start 21930 IF ck<0 THEN ck = ck+$10000 : REM correct for -ve result : ********************************************************************* : compute the 16 bit checksum on part of the ip(n) packet : entry is with cl = bytes to checksum and ca = index to the first byte 21949 REM checksum 21950 IF cl=0 THEN 21990 : REM exit if no length to checksum 21955 DO 21960 ck = ck+ip(ca)*256 : INC ca : DEC cl : REM add high byte to sum 21965 IF cl THEN ck = ck+ip(ca) : INC ca : DEC cl : REM add low byte 21975 IF ck>$7FFF THEN ck=ck-$FFFF 21980 LOOP WHILE cl 21985 IF ck<0 THEN DEC ck 21990 RETURN : ********************************************************************* : handle IP TCP packet : tl = total length of IP packet : td = TCP data offset : tf = TCP flags for this packet : ti = TCP start index : ts = TCP state : 1 = listen : 2 = SYN received : 3 = established : 4 = FIN wait 1 : 5 = FIN wait 1 : sp = source port : ep = expected port : destination port MUST be $0080 (http:// only) 21999 REM handle TCP packet 22000 ti = $22 : REM start of TCP packet 22005 GOSUB 21900 : REM get length and do TCP checksum 22010 IF ck THEN 22098 : REM ignore bad packets 22015 sp = ip(ti)*256+ip(ti+1) : REM source port address 22020 IF ip(ti+3)<>$50 THEN 22098 : REM ignore ports <> $50 22025 IF ip(ti+2) THEN 22098 : REM ignore ports > $FF 22060 td = ti+((ip(ti+$0C) AND $F0)>>2) : REM TCP data offset 22065 tf = ip(ti+$0D) AND $3F : REM TCP flags 22070 ON ts GOSUB 22100, 22200, 22300, 22400, 22500 : listn, synrx, estab, wait1, wait2 22098 RETURN : ********************************************************************* : TCP listen state 22099 REM TCP listen 22100 IF (tf AND $04) THEN 22198 : REM ignore RST (correct) 22105 IF (tf AND $10) THEN 22198 : REM ignore ACK (should send RST) 22110 IF (tf AND $02)=0 THEN 22198 : REM ignore not SYN 22115 FOR i=$0 TO $3 : rn(i) = ip(ti+i+$4) : NEXT : REM get sequence no 22120 FOR i=$0 TO $3 : si(i) = ip(i+$1A) : NEXT : REM sender's ip addr 22125 mq(0) = INT(RND(0)*$80) : mq(1) = INT(RND(0)*$80) 22130 mq(2) = $FF : mq(3) = $FF : REM our sequence number : got details, now make SYN ACK 22135 GOSUB 22815 : REM prepare TCP reply 22140 GOSUB 22920 : REM generate ACK for SYN received 22145 GOSUB 22895 : REM generate our own SYN 22150 GOSUB 22845 : REM finalise TCP reply 22155 GOSUB 21800 : REM generate IP header 22160 GOSUB 21700 : REM send the TCP packet along on its way 22165 ts = 2 : sc = 200 : REM change state to SYN received, count 200 22170 ep = sp : REM connected port = source port :*22196 FOR i=0 TO (ph(3)*256+ph(2))-$F : ? " ";HEX$(ip(i),2); : NEXT : ? 22198 RETURN : ********************************************************************* : TCP syn received state 22199 REM TCP syn received, ack sent : we're expecting an ACK of our SYN 22200 IF sc=0 THEN ts = 1 : GOTO 22298 : REM count expired 22205 FOR i=0 TO 3 : IF si(i)<>ip($1A+i) THEN i = 4 22210 NEXT : IF i=5 THEN 22298 : REM check sender's ip addr 22215 IF sp<>ep THEN 22298 : REM ignore packets from wrong port 22220 FOR i=0 TO 3 : IF mq(i)<>ip(ti+$08+i) THEN i = 4 22225 NEXT : IF i=5 THEN 22298 : REM check sender's ack number 22230 IF (tf AND $02) THEN 22298 : REM ignore SYN (should RST & close) 22235 IF (tf AND $10)=0 THEN 22298 : REM not ACK 22240 ts = 3 : sc = 200 : REM change state to established, count 200 22298 RETURN : ********************************************************************* : TCP established state 22299 REM TCP established 22300 IF sc=0 THEN ts = 1 : GOTO 22398 : REM count expired 22305 IF sp<>ep THEN 22398 : REM ignore packets from wrong port 22310 FOR i=0 TO 3 : IF si(i)<>ip($1A+i) THEN i = 4 22315 NEXT : IF i=5 THEN 22398 : REM check sender's ip addr 22320 GOSUB 22800 : IF fg THEN 22398 : REM ck rx seq# 22325 IF (tf AND $04) THEN ts = 1 : sc = 0 : GOTO 22398 : REM reset 22330 IF (tf AND $02) THEN 22398 : REM ignore SYN (should send reset) 22335 IF (tf AND $10)=0 THEN 22398 : REM ignore no ACK 22340 pp = td : GOSUB 22815 : REM set data pointer & prepare TCP reply : now process the data from the block, data starts at pp 22345 DO : td$ = "" : dl = 0 : REM clear data and data length 22350 DO : b$ = CHR$(ip(pp)) : INC dl,pp : REM get byte inc ptr & len 22355 IF (b$<>cr$) AND (b$<>lf$) THEN td$ = td$+b$ 22360 LOOP UNTIL (pp>(tl+$0E)) OR (dl=$FF) OR (b$=cr$) 22365 IF LEFT$(td$,3)="GET" THEN GOSUB 22700 : REM do 'GET' response 22370 LOOP UNTIL (pp>(tl+$0E)) OR (td$="") 22375 GOSUB 22925 : REM generate ACK for data 22380 ip(ti+$0D) = ip(ti+$0D) OR $01 : DEC xd : REM flg FIN & inc space 22385 GOSUB 22845 : GOSUB 21800 : REM finalise TCP & generate IP header 22390 GOSUB 21700 : REM send the TCP packet along on its way 22395 ts = 4 : sc = 200 : REM change state to fin_wait_1, count 200 22398 RETURN : ********************************************************************* : TCP FIN wait 1 state 22399 REM TCP FIN wait 1 22400 IF sc=0 THEN ts = 1 : GOTO 22498 : REM count expired 22405 IF sp<>ep THEN 22498 : REM ignore packets from wrong port 22410 FOR i=0 TO 3 : IF si(i)<>ip($1A+i) THEN i = 4 22415 NEXT : IF i=5 THEN 22498 : REM check sender's ip addr 22420 GOSUB 22800 : IF fg THEN 22498 : REM ck rx seq# 22425 IF (tf AND $04) THEN ts = 1 : sc = 0 : GOTO 22498 : REM reset 22430 IF (tf AND $02) THEN 22498 : REM ignore SYN (should send reset) 22435 IF (tf AND $10)=0 THEN 22498 : REM ignore no ACK 22440 IF (tf AND $01) THEN 22545 : REM ACK and close if FIN 22445 ts = 5 : sc = 200 : REM change state to fin_wait_2, count 200 22498 RETURN : ********************************************************************* : TCP FIN wait 2 state 22499 REM TCP FIN wait 2 22500 IF sc=0 THEN ts = 1 : GOTO 22598 : REM count expired 22505 IF sp<>ep THEN 22598 : REM ignore packets from wrong port 22510 FOR i=0 TO 3 : IF si(i)<>ip($1A+i) THEN i = 4 22515 NEXT : IF i=5 THEN 22598 : REM check sender's ip addr 22520 GOSUB 22800 : IF fg THEN 22598 : REM ck rx seq# 22525 IF (tf AND $04) THEN ts = 1 : sc = 0 : GOTO 22598 : REM reset 22530 IF (tf AND $02) THEN 22598 : REM ignore SYN (should send reset) 22535 IF (tf AND $10)=0 THEN 22598 : REM ignore no ACK 22540 IF (tf AND $01)=0 THEN 22598 : REM exit if no FIN : now ACK the FIN and close 22545 GOSUB 22815 : REM set data pointer & prepare TCP reply 22550 GOSUB 22920 : REM generate ACK for FIN 22555 GOSUB 22845 : REM finalise TCP 22560 GOSUB 21800 : REM generate IP header 22565 GOSUB 21700 : REM send the TCP packet along on its way 22570 ts = 1 : sc = 0 : REM change the state to listen, count 0 22598 RETURN : ********************************************************************* : generate HTTP response 22700 RESTORE 32000 : REM set default page 22705 IF MID$(td$,5,1)<>"/" THEN RESTORE 34040 : GOTO 22720 22710 IF MID$(td$,6,6)="o.html" THEN RESTORE 32010 : GOTO 22720 22712 IF MID$(td$,6,5)="e.gif" THEN RESTORE 35000 : GOTO 22780 22714 IF MID$(td$,6,6)="b.html" THEN RESTORE 32020 : GOTO 22717 22715 IF MID$(td$,6,1)<>" " THEN RESTORE 34040 : GOTO 22720 : if it's b.html then check for user submission 22717 IF MID$(td$,12,1)="?" THEN ? "User submitted "; MID$(td$,13,3) : now push the RESTOREd page into the buffer 22720 DO 22725 READ pg$ 22735 IF pg$="$" THEN pg$ = el$ 22740 pg = SADD(pg$) : REM get string address 22745 FOR i=0 TO LEN(pg$)-1 22750 ip(xl) = PEEK(pg+i) 22755 INC xl : NEXT : REM put characters in the buffer 22760 LOOP UNTIL pg$="</HTML>" 22765 td$ = "" : REM dump any further received data 22770 RETURN 22780 READ pg 22785 DO : ip(xl) = pg : INC xl : READ pg : LOOP UNTIL pg=-1 22790 GOTO 22765 : ********************************************************************* : check TCP sequence 22800 fg = 0 : REM flag not false then check sequence 22805 FOR i=0 TO 3 : fg = fg OR (rn(i) <> ip(ti+$04+i)) : NEXT 22810 RETURN : ********************************************************************* : prepare TCP reply 22815 FOR i=$0 TO $3 : ip(ti+i+$4) = mq(i) : NEXT : REM save seq no. 22820 ip(ti+$0C) = $50 : xd = ti+$14 : REM set length & data start 22825 xl = xd : REM set tx TCP total length 22830 ip(ti+$0D) = $00 : REM clear flags 22835 ip(ti+$12) = $00 : ip(ti+$13) = $00 : REM clear urgent pointer 22840 RETURN : ********************************************************************* : finalise TCP reply 22845 SWAP ip(ti),ip(ti+2) : SWAP ip(ti+1),ip(ti+3) : REM swap ports 22850 ip($10) = (xl-$0E)>>8 : ip($11) = (xl-$0E) AND $FF : REM IP len 22855 ip(ti+$10) = $00 : ip(ti+$11) = $00 : REM clear checksum 22860 GOSUB 21900 : REM do TCP checksum 22865 ck = NOT ck : REM ones complement 22870 ip(ti+$10) = ck>>8 : ip(ti+$11) = ck AND $FF 22875 ip($16) = $3C : REM set time to live 22880 GOTO 22975 : REM generate our next sequence number & return : ********************************************************************* : generate SYN 22895 ip(ti+$0D) = ip(ti+$0D) OR $02 : REM flag SYN 22900 ip(ti+$0C) = ip(ti+$0C)+$10 : REM inc header length for option 22905 ip(xl) = $02 : INC xl : ip(xl) = $04 : INC xl : REM opt 2 len 4 22910 ip(xl) = $02 : INC xl : ip(xl) = $00 : INC xl 22912 xd = xl-1 : REM sequence space for our SYN 22915 RETURN : ********************************************************************* : generate ACK for SYN or FIN received 22920 DEC td : REM increment data space for SYN or FIN : generate ACK for TCP data 22925 GOSUB 22950 : REM add to received sequence number 22927 FOR i=$0 TO $3 : ip(ti+$08+i) = rn(i) : NEXT : REM save ack no. 22930 ip(ti+$0D) = ip(ti+$0D) OR $10 : REM flag ACK 22935 ip(ti+$0E) = $05 : REM set window high byte 22940 ip(ti+$0F) = $00 : REM set window low byte 22945 RETURN : ********************************************************************* : generate next received sequence number 22950 aa = tl-td+$0E : REM calculate TCP data size 22952 rn(3) = rn(3)+(aa AND $FF) : REM add size low byte 22955 IF (rn(3) AND $100) THEN rn(3) = rn(3) AND $FF : INC rn(2) 22957 rn(2) = rn(2)+(aa >> 8) : REM add size high byte 22960 IF (rn(2) AND $100) THEN rn(2) = rn(2) AND $FF : INC rn(1) 22962 IF (rn(1) AND $100) THEN rn(1) = rn(1) AND $FF : INC rn(0) 22965 rn(0) = (rn(0) AND $FF) 22970 RETURN : ********************************************************************* : generate our next sequence number 22975 aa = xl-xd : REM calculate TCP data size 22977 mq(3) = mq(3)+(aa AND $FF) : REM add size low byte 22980 IF (mq(3) AND $100) THEN mq(3) = mq(3) AND $FF : INC mq(2) 22982 mq(2) = mq(2)+(aa >> 8) : REM add size high byte 22985 IF (mq(2) AND $100) THEN mq(2) = mq(2) AND $FF : INC mq(1) 22987 IF (mq(1) AND $100) THEN mq(1) = mq(1) AND $FF : INC mq(0) 22990 mq(0) = (mq(0) AND $FF) 22995 RETURN : ********************************************************************* : default web page, served for "GET / " 32000 DATA "HTTP/1.0 200 OK",$,"Content-Type: text/html",$,$ 32001 DATA "<HTML><HEAD><TITLE>Mini WEB Server</TITLE></HEAD><BODY BGC" 32002 DATA "OLOR=#CC6502 TEXT=WHITE><TABLE ALIGN=CENTER WIDTH=80% HEIG" 32003 DATA "HT=90%><TR><TD VALIGN=CENTER><FONT SIZE=+1>Mini WEB Server" 32004 DATA " </FONT>- <A HREF=b.html>The button page</A> - <A HREF=o.h" 32005 DATA "tml>The other page</A><P><FONT SIZE=+4><B>Welcome</B></FON" 32006 DATA "T><FONT FACE=Courier> - to the default page</FONT><P><A HR" 32007 DATA "EF=http://forum.6502.org/viewtopic.php?f=5&t=3024> e-mail me <IMG SRC" 32008 DATA "=e.gif BORDER=0 ALT=e-mail></A></TABLE></BODY>",</HTML> : ********************************************************************* : other web page, served for "GET /o.html" - note! case sensetive 32010 DATA "HTTP/1.0 200 OK",$,"Content-Type: text/html",$,$ 32011 DATA "<HTML><HEAD><TITLE>Mini WEB Server</TITLE></HEAD><BODY BGC" 32012 DATA "OLOR=#65CC02 TEXT=WHITE><TABLE ALIGN=CENTER WIDTH=80% HEIG" 32013 DATA "HT=90%><TR><TD VALIGN=CENTER><FONT SIZE=+1>Mini WEB Server" 32014 DATA " </FONT>- <A HREF=>The home page</A> - <A HREF=b.html>The " 32015 DATA "button page</A><P><FONT SIZE=+4><B>Welcome</B></FONT><FONT" 32016 DATA " FACE=Courier> - to the other page</FONT><P><A HREF=mailto" 32017 DATA ":leeedavison@lycos.co.uk> e-mail me <IMG SRC=e.gif BO" 32018 DATA "RDER=0 ALT=e-mail></A></TABLE></BODY>",</HTML> : ********************************************************************* : the button page, served for "GET /b.html" - note! case sensetive 32020 DATA "HTTP/1.0 200 OK",$,"Content-Type: text/html",$,$ 32021 DATA "<HTML><HEAD><TITLE>Mini WEB Server</TITLE></HEAD><BODY BGC" 32022 DATA "OLOR=#065C02 TEXT=WHITE><TABLE ALIGN=CENTER WIDTH=90% HEIG" 32023 DATA "HT=90%><TR><TD VALIGN=CENTER><FONT SIZE=+1>Mini WEB Server" 32024 DATA " </FONT>- <A HREF=>The home page</A> - <A HREF=o.html>The " 32025 DATA "other page</A><P><FONT SIZE=+4><B>Welcome</B></FONT><FONT " 32026 DATA "FACE=Courier> - to the button page</FONT><P><A HREF=mailto" 32027 DATA ":leeedavison@lycos.co.uk> e-mail me <IMG SRC=e.gif BO" 32028 DATA "RDER=0 ALT=e-mail></A><TD WIDTH=20% ALIGN=CENTER>Are you e" 32029 DATA "asily confused?<FORM METHOD=GET ACTION=b.html><PRE>yes <IN" 32030 DATA "PUT TYPE=RADIO NAME=4 VALUE=0>",$,"no <INPUT TYPE=RADIO N" 32031 DATA "AME=4 VALUE=1>",$,"fish<INPUT TYPE=RADIO NAME=4 VALUE=2 CH" 32032 DATA "ECKED></PRE><INPUT TYPE=SUBMIT VALUE=Submit></FORM></TABLE" 32033 DATA "></BODY>",</HTML> : ********************************************************************* : error 404, served for everything else 34040 DATA "HTTP/1.0 200 OK",$,"Content-Type: text/html",$,$ 34041 DATA "<HTML><HEAD><TITLE>Error 404</TITLE></HEAD><BODY BGCOLOR=#" 34042 DATA "CC0265 TEXT=WHITE><TABLE ALIGN=CENTER WIDTH=80% HEIGHT=90%" 34043 DATA "><TR><TD VALIGN=CENTER><FONT SIZE=+1>Mini WEB Server </FON" 34044 DATA "T>- <A HREF=>The home page</A><P><FONT SIZE=+4><B>Error 40" 34045 DATA "4</B></FONT><FONT FACE=Courier> - File not found</FONT><P>" 34046 DATA "<A HREF=http://forum.6502.org/viewtopic.php?f=5&t=3024> e-mail me <IM" 34047 DATA "G SRC=e.gif BORDER=0 ALT=e-mail></A></TABLE></BODY>" 34048 DATA </HTML> : ********************************************************************* : small image, served for "GET /email.gif" - note! case sensetive 35000 DATA $48,$54,$54,$50,$2F,$31,$2E,$30,$20,$32,$30,$30,$20,$4F,$4B 35001 DATA $0D,$0A,$43,$6F,$6E,$74,$65,$6E,$74,$2D,$54,$79,$70,$65,$3A 35002 DATA $20,$69,$6D,$61,$67,$65,$2F,$67,$69,$66,$0D,$0A,$0D,$0A 35003 DATA $47,$49,$46,$38,$39,$61,$10,$00,$10,$00,$C4,$00,$00,$F7,$00 35004 DATA $5F,$33,$03,$9A,$33,$03,$CA,$03,$03,$83,$5F,$5F,$F7,$33,$63 35005 DATA $FA,$63,$9B,$FB,$63,$CB,$FB,$03,$9B,$CB,$63,$FA,$FA,$FA,$FA 35006 DATA $CB,$97,$00,$00,$CB,$03,$03,$FA,$FA,$FA,$63,$63,$63,$03,$03 35007 DATA $03,$FF,$FF,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 35008 DATA $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 35009 DATA $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 35010 DATA $00,$00,$00,$00,$21,$F9,$04,$01,$00,$00,$10,$00,$2C,$00,$00 35011 DATA $00,$00,$10,$00,$10,$00,$00,$05,$69,$20,$24,$8E,$C6,$91,$24 35012 DATA $63,$9A,$96,$49,$11,$18,$AA,$28,$40,$85,$59,$40,$46,$A0,$3A 35013 DATA $8E,$20,$20,$07,$01,$6F,$38,$7C,$38,$1A,$3F,$84,$40,$C1,$6C 35014 DATA $36,$8D,$C8,$02,$62,$E0,$64,$02,$18,$0A,$E8,$60,$BB,$AD,$32 35015 DATA $16,$D9,$63,$A3,$51,$2D,$43,$C9,$E5,$EA,$B9,$2C,$28,$B8,$A9 35016 DATA $D0,$B4,$42,$70,$82,$3B,$E4,$F3,$7A,$F8,$C1,$EF,$F3,$05,$26 35017 DATA $5B,$7C,$2A,$2F,$10,$02,$25,$37,$03,$31,$10,$04,$01,$05,$06 35018 DATA $06,$37,$8B,$23,$01,$03,$6D,$31,$21,$00,$3B,-1
Last page update: 7th September, 2003. | e-mail me |