jb flags2.TCP_SOCK, :lastackTcp2 ; checkk which tcp conn
; is current
mov tcp1State, w
call @DeleteSocket1 ; delete the tcp conn. socket
jmp :dumpy
:lastackTcp2 mov tcp2State, w
call @DeleteSocket2 ; delete the tcp conn. socket
:dumpy _bank NIC_BANK ; needed for NICDumpRxFrame, we came from
; an upper bank
jmp @NICDumpRxFrame
:CLOSED call @NICDumpRxFrame
jmp @TCPSendReset ; we shouldn't receive packets
; while closed
:LISTEN call @NICDumpRxFrame ; discard received packet
jb flags2.TCP_SOCK, :listen2Check
bank TCB1_BANK
snb tcb1Flags.TCP_FLAG_RST ; check for an RST
retp ; ignore a packet with RST
snb tcb1Flags.TCP_FLAG_ACK ; check for an ACK
jmp @TCPSendReset ; bad ACK, send a RST
jmp :contListen
:listen2Check bank TCB2_BANK
snb tcb2Flags.TCP_FLAG_RST ; check for an RST
retp ; ignore a packet with RST
snb tcb2Flags.TCP_FLAG_ACK ; check for an ACK
jmp @TCPSendReset ; bad ACK, send a RST
:contListen call @TCPCopySeqToNxt
call @TCPSendSynAck
bank TCP_BANK
mov w, #TCP_ST_SYNRCVED ; change state
sb flags2.TCP_SOCK
mov tcp1State, w
snb flags2.TCP_SOCK
mov tcp2State, w
retp
:SYNSENT call @NICDumpRxFrame
jb flags2.TCP_SOCK, :synsentCheck2
bank TCB1_BANK
jnb tcb1Flags.TCP_FLAG_ACK, :noAck ; is the ACK bit set?
jb tcb1Flags.TCP_FLAG_RST, :rst ; is the reset bit set?
jnb tcb1Flags.TCP_FLAG_SYN, :noAck ; if SYN bit not set,
; ignore packet
jmp :contSynsent
:synsentCheck2 bank TCB2_BANK
jnb tcb2Flags.TCP_FLAG_ACK, :noAck ; is the ACK bit set?
jb tcb2Flags.TCP_FLAG_RST, :rst ; is the reset bit set?
jnb tcb2Flags.TCP_FLAG_SYN, :noAck ; if SYN bit not set,
; ignore packet
:contSynsent bank TCP_BANK
mov w, #TCP_ST_ESTABED ; the connection is now estabished
sb flags2.TCP_SOCK
mov tcp1State, w
snb flags2.TCP_SOCK
mov tcp2State, w
bank IP_BANK
clr ipLengthMSB ; set the received data length to 1
mov ipLengthLSB, #1 ; "
call @TCPAckUpdate
jmp @TCPSendAck
:rst bank TCP_BANK
mov w, #TCP_ST_CLOSED ; close the TCP
sb flags2.TCP_SOCK
mov tcp1State, w
snb flags2.TCP_SOCK
mov tcp2State, w
retp
; the peer wants us to raise the precedence. We can't.
; We are not happy about not being Acked. Send a Reset.
:noAck jmp @TCPSendReset
ORG $800 ; Page4
TCPRxHeader jmp _TCPRxHeader
TCPStartPktOut jmp _TCPStartPktOut
TCPTxByte jmp _TCPTxByte
TCPReTransmit jmp _TCPReTransmit
Compare4Inc jmp _Compare4Inc
TCPAppTxDone jmp _TCPAppTxDone
; ******************************************************************************
NICReadAgain_4
; Shortform for calling NICReadAgain(), which is in Page1 (This is in Page4)
; ******************************************************************************
jmp @NICReadAgain
; ******************************************************************************
NICWriteAgain_4
; Shortform for calling NICWriteAgain(), which is in Page1 (This is in Page4)
; ******************************************************************************
jmp @NICWriteAgain
; ******************************************************************************
NICDumpRxFrame_4
; Shortform for calling NICDumpRxFrame(), which is in Page1 (This is in Page4)
; ******************************************************************************
jmp @NICDumpRxFrame
; ******************************************************************************
TCPAddRcvNxt
; Add an 16-bit number to RCV.NXT
; INPUT: {ipLengthMSB,ipLengthLSB} = number to add
; OUTPUT: {tcb1RcvNxt1-4,tcb2RcvNxt1-4}
; ******************************************************************************
; check for which tcp connection to add
sb flags2.TCP_SOCK
mov globTemp1, #tcb1RcvNxt1 ; make pointer to TCB1_BANK
snb flags2.TCP_SOCK
mov globTemp1, #tcb2RcvNxt1 ; make pointer to TCB2_BANK
bank IP_BANK
mov w, ipLengthLSB
mov globTemp2, w ; store ipLengthLSB in globTemp2
mov fsr, globTemp1 ; point to TCB variable
add indf, globTemp2 ; add ipLengthLSB to tcbRcvNxt1
bank IP_BANK
mov w, ipLengthMSB
snc
mov w, ++ipLengthMSB
mov globTemp2, w ; store in globTemp2
dec globTemp1
mov fsr, globTemp1 ; point to TCB variable
add indf, globTemp2 ; add to tcb1(2)RcvNxt2
sc
retp
dec fsr
incsz indf ; tcb1(2)RcvNxt3
retp
dec fsr
inc indf ; tcb1(2)RcvNxt4
retp
; ******************************************************************************
TCPIncRcvNxt
; Increment RCV.NXT by one
; INPUT: none
; OUTPUT: {tcb1RcvNxt1-4,tcb2RcvNxt1-4}
; ******************************************************************************
; set pointer to correct TCB (TCB1_BANK for tcp1,
; TCB2_BANK for tcp2)
mov globTemp1, #(tcb1RcvNxt1-TCB1_BANK)
call @SetTCBPointer
incsz indf ; 1
retp
dec fsr ; 2
incsz indf
retp
dec fsr ; 3
incsz indf
retp
dec fsr ; 4
inc indf
retp
; ******************************************************************************
TCPIncSndUna
; Increment SND.UNA by one
; INPUT: none
; OUTPUT: {tcb1SndUna1-4,tcb2SndUna1-4}
; ******************************************************************************
; set pointer to correct TCB (TCB1_BANK for tcp1,
; TCB2_BANK for tcp2)
mov globTemp1, #(tcb1SndUna1-TCB1_BANK)
call @SetTCBPointer
incsz indf ; 1
retp
dec fsr ; 2
incsz indf
retp
dec fsr ; 3
incsz indf
retp
dec fsr ; 4
inc indf
retp
; ******************************************************************************
TCPCopySeqToNxt
; Copy {tcpTmpSeq4-1} -> {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1}
; INPUT: {tcpTmpSeq4-1}
; OUTPUT: {tcb1RcvNxt4-1,tcb2RcvNxt4-1}
; ******************************************************************************
sb flags2.TCP_SOCK
mov globTemp1, #tcb1RcvNxt4 ; make pointer to TCB1_BANK
snb flags2.TCP_SOCK
mov globTemp1, #tcb2RcvNxt4 ; make pointer to TCB2_BANK
mov globTemp3, #tcpTmpSeq4 ; make pointer to TCP BANK
call @Copy4Inc ; copy 4 TCP variables to TCB
retp ; by incrementing the pointers
; ******************************************************************************
TCPCopyAckToUna
; Copy {tcpTmpAck4-1} -> {tcb1SndUna4-1} or {tcb2SndUna4-1}
; INPUT: {tcpTmpAck4-1}
; OUTPUT: {tcb1SndUna4-1,{tcb2SndUna4-1}}
; ******************************************************************************
sb flags2.TCP_SOCK
mov globTemp1, #tcb1SndUna4 ; make pointer to TCB1_BANK
snb flags2.TCP_SOCK
mov globTemp1, #tcb2SndUna4 ; make pointer to TCB2_BANK
mov globTemp3, #tcpTmpAck4 ; make pointer to TCP BANK
call @Copy4Inc ; copy 4 TCP variables to TCB
retp
; ******************************************************************************
TCPAckUpdate
; Update SND.UNA and RCV.NXT
; INPUT: {tcpTmpAck4-1}
; {tcpTmpSeq4-1}
; {ipLengthMSB,ipLengthLSB} = length of received TCP Data
; OUTPUT: {tcpSndUna4-1}
; {tcpRcvNxt4-1}
; ******************************************************************************
call @TCPCopyAckToUna ; set SND.UNA = SEG.ACK
call @TCPCopySeqToNxt ; set RCV.NXT = SEG.SEQ
jmp @TCPAddRcvNxt ; add the length of the received
; packet to the ACK
; ******************************************************************************
TCPCmpNxtSeq
; Check if RCV.NXT == SEG.SEQ
; INPUT: {tcpTmpSeq4-1} = SEG.SEQ
; {tcb1RcvNxt4-1} = RCV.NXT or {tcb2RcvNxt4-1} = RCV.NXT
; OUTPUT: z is set if RCV.NXT == SEG.SEQ
; ******************************************************************************
sb flags2.TCP_SOCK
mov globTemp1, #tcb1RcvNxt1 ; make pointer to TCB1_BANK
snb flags2.TCP_SOCK
mov globTemp1, #tcb2RcvNxt1 ; make pointer to TCB2_BANK
mov globTemp3, #tcpTmpSeq1 ; make pointer to TCP BANK
bank IP_BANK
mov counter1, #4 ; load the counter
:loop
mov fsr, globTemp3 ; move tcp pointer to fsr
mov w, indf ; move tcp var in w
mov globTemp2, w ; store tcp var in global2
mov fsr, globTemp1 ; move tcb pointer to fsr
mov w, indf ; move tcb var into w
xor w, globTemp2 ; xor tcp var with tcb var
jnz :CmpEnd ; test if equal
dec globTemp1 ; dec pointer to tcb
dec globTemp3 ; dec pointer to tcp
_bank IP_BANK ; check loop counter until
; finished
dec counter1
sz
jmp :loop
:CmpEnd retp
; ******************************************************************************
TCPSendEmptyPkt
; Constructs and sends a TCP packet containing no Data
; INPUT: {remoteIP0-3} = Destination IP addr for TCP pkt
; {tcb1SndUna4-1} or {tcb2SndUna4-1} = sequence number
; {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
; tcb1Flags or tcb2Flags = code flags
; {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
; or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
; {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
; or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT:
; ******************************************************************************
call @TCPCheckSumInit
bank TCP_BANK
clr tcpLengthMSB
clr tcpLengthLSB
call TCPStartPktOut
call @NICSendTxFrame
bank TIMER_BANK
; clear correct tcp connection's re-tx counters
jb flags2.TCP_SOCK, :clrTcp2timer
; tcp conn1
clr tcp1TimerMSB
clr tcp1TimerLSB
retp
; tcp conn2
:clrTcp2timer clr tcp2TimerMSB
clr tcp2TimerLSB
retp
; ******************************************************************************
TCPSendReset
; Send a reset packet with <SEQ=SEG.ACK><CTL=RST> and Discard the received
; packet
; INPUT: {remoteIP0-3} = Destination IP addr for TCP pkt
; {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
; {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
; or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
; {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
; or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT:
; ******************************************************************************
; point to correct tcb for current tcp connection
mov globTemp1, #(tcb1Flags-TCB1_BANK)
call @SetTCBPointer
mov indf, #(1<<TCP_FLAG_RST)
call @TCPCopyAckToUna ; copy the acknowledgement number.
call @TCPSendEmptyPkt
jmp NICDumpRxFrame_4 ; discard the received pkt
; ******************************************************************************
TCPSendSyn
; Send a SYN packet
; INPUT: {remoteIP0-3} = Destination IP addr for TCP pkt
; {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
; {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
; or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
; {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
; or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT: {tcpSndUna4-1} = new sequence number
; ******************************************************************************
; point to correct tcb for current tcp connection
mov globTemp1, #(tcb1Flags-TCB1_BANK)
call @SetTCBPointer
mov indf, #(1<<TCP_FLAG_SYN)
jmp TCPSendISN
; ******************************************************************************
TCPSendISN
; Send the TCP initial sequence number
; INPUT: {remoteIP0-3} = Destination IP addr for TCP pkt
; {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
; {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
; or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
; {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
; or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT: {tcpSndUna4-1} = new sequence number
; ******************************************************************************
; obtain a random number for starting sequence number
bank NIC_BANK
mov w, nicCurrPktPtr
xor w, nicRemoteEth0
bank IP_BANK
xor w, ipIdentLSB
mov globTemp2, w ; store
; point to the correct tcb for current tcp connection
mov globTemp1, #(tcb1SndUna4-TCB1_BANK)
call @SetTCBPointer
mov w, globTemp2 ; restore
mov indf, w ; 1
inc fsr
mov indf, w ; 2
inc fsr
mov indf, w ; 3
inc fsr
mov indf, w ; 4
call @TCPIncRcvNxt
call @TCPSendEmptyPkt
jmp @TCPIncSndUna
; ******************************************************************************
TCPSendSynAck
; Send an SYN-ACK packet with <SEQ=SND.NXT><ACK=RCV.NXT><CTL=SYN>
; INPUT: {remoteIP0-3} = Destination IP addr for TCP pkt
; {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
; {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
; or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
; {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
; or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT: {tcpSndUna4-1} = new sequence number
; ******************************************************************************
; point to correct tcb for current tcp connection
mov globTemp1, #(tcb1Flags-TCB1_BANK)
call @SetTCBPointer
mov indf, #((1<<TCP_FLAG_SYN)|(1<<TCP_FLAG_ACK))
jmp @TCPSendISN
; ******************************************************************************
TCPSendAck
; Send an ACK packet with <SEQ=SND.NXT><ACK=RCV.NXT><CTL=ACK> and Discard the
; received packet
; INPUT: {remoteIP0-3} = Destination IP addr for TCP pkt
; {tcb1SndUna4-1} or {tcb2SndUna4-1} = sequence number
; {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
; {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
; or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
; {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
; or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT:
; ******************************************************************************
; point to correct tcb for current tcp connection
mov globTemp1, #(tcb1Flags-TCB1_BANK)
call @SetTCBPointer
mov indf, #(1<<TCP_FLAG_ACK)
call @TCPSendEmptyPkt
jmp NICDumpRxFrame_4 ; discard the received pkt
; ******************************************************************************
TCPSendFin
; Send a FIN packet and discard the received packet
; INPUT: {remoteIP0-3} = Destination IP addr for TCP pkt
; {tcb1SndUna4-1} or {tcb2SndUna4-1} = sequence number
; {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
; tcb1Flags or tcb2Flags = code flags
; {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
; or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
; {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
; or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT:
; ******************************************************************************
; point to correct tcb for current tcp connection
mov globTemp1, #(tcb1Flags-TCB1_BANK)
call @SetTCBPointer
mov indf, #(1<<TCP_FLAG_FIN)|(1<<TCP_FLAG_ACK)
call @TCPSendEmptyPkt
jmp NICDumpRxFrame_4 ; discard the received pkt
; ******************************************************************************
TCPCheckSumInit
; Clear TCP checksum value to prepare for new checksum calculation
; INPUT: none
; OUTPUT: {tcpCheckSumMSB,tcpCheckSumLSB}
; ******************************************************************************
bank TCP_BANK
clr tcpCheckSumMSB
clr tcpCheckSumLSB
clrb flags.TCP_CHKSUM_LSB ; next byte is MSB
retp
; ******************************************************************************
TCPCheckSumAcc
; Accumulate the TCP checksum. Checksum is computed by Doing the one's
; complement of the one's complement sum of 16-bit numbers
; INPUT: w = byte to accumulate
; flags.TCP_CHKSUM_LSB = set if processing LSB, clear if processing MSB
; OUTPUT: {tcpCheckSumMSB,tcpCheckSumLSB}
; ******************************************************************************
bank TCP_BANK
jnb flags.TCP_CHKSUM_LSB, :msb ; are we processing an MSB?
:lsb add tcpCheckSumLSB, w ; add it to the checksum
sc ; was there a carry?
jmp :done
inc tcpCheckSumMSB ; yes
snz
inc tcpCheckSumLSB
jmp :done
:msb add tcpCheckSumMSB, w ; add it to the checksum
sc ; was there a carry?
jmp :done
inc tcpCheckSumLSB ; yes, this time it is
; added to the LSB
snz
inc tcpCheckSumMSB
:done xor flags, #(1<<TCP_CHKSUM_LSB)
retp
; ******************************************************************************
TCPCheckSumAddHdr
; Add to the TCP checksum, the pseudo-header fields
; INPUT: {myIP0-3} = source IP addr
; {remoteIP0-3} = Destination IP addr
; {tcpLengthMSB,tcpLengthLSB} = length of TCP header and Data
; OUTPUT: {tcpCheckSumMSB,tcpCheckSumLSB}
; ******************************************************************************
bank TCP_BANK
; <TCP_length>
mov w, tcpLengthMSB
call TCPCheckSumAcc
mov w, tcpLengthLSB
call TCPCheckSumAcc
; <zero>,<protocol>
mov w, #0
call TCPCheckSumAcc
mov w, #6
call TCPCheckSumAcc
; <source_IP>
bank IP_BANK
mov w, myIP3
call TCPCheckSumAcc
bank IP_BANK
mov w, myIP2
call TCPCheckSumAcc
bank IP_BANK
mov w, myIP1
call TCPCheckSumAcc
bank IP_BANK
mov w, myIP0
call TCPCheckSumAcc
; <destination_IP>
bank IP_BANK
mov w, remoteIP3
call TCPCheckSumAcc
bank IP_BANK
mov w, remoteIP2
call TCPCheckSumAcc
bank IP_BANK
mov w, remoteIP1
call TCPCheckSumAcc
bank IP_BANK
mov w, remoteIP0
call TCPCheckSumAcc
retp
; ******************************************************************************
_TCPTxByte
; Transmit a TCP byte accumulating the checksum each time
; INPUT: w = byte to send
; OUTPUT: none
; ******************************************************************************
mov globTemp1, w
call @TCPCheckSumAcc
mov w, globTemp1
call NICWriteAgain_4
retp
; ******************************************************************************
_TCPStartPktOut
; Constructs the TCP and IP headers
; INPUT: {remoteIP0-3} = Destination IP addr for TCP pkt
; {tcpLengthMSB,tcpLengthLSB} = length of TCP Data (just Data)
; {tcpCheckSumMSB,tcpCheckSumLSB} = TCP checksum computed over just Data
; {tcb1SndUna4-1} or {tcb2SndUna4-1} = sequence number
; {tcb1RcvNxt4-1} or {tcb2RcvNxt4-1} = acknowledgement number
; tcb1Flags or tcb2Flags = code flags
; {tcb1LocalPortMSB,tcb1LocalPortLSB} = TCP Source Port
; or {tcb2LocalPortMSB,tcb2LocalPortLSB} = TCP Source Port
; {tcb1RemotePortMSB,tcb1RemotePortLSB} = TCP Destination Port
; or {tcb2RemotePortMSB,tcb2RemotePortLSB} = TCP Destination Port
; OUTPUT:
; ******************************************************************************
; tcpLength += <TCP header length>
_bank TCP_BANK
mov w, #(TCP_HDR_LENGTH<<2) ; add in size of TCP hdr (20)
add tcpLengthLSB, w
snc
inc tcpLengthMSB ; tcpLength now is the length of
; TCP hdr and Data
; IP <total_length> = tcpLength + <IP header length>
mov w, #20 ; add in size of IP hdr (20)
add w, tcpLengthLSB
bank IP_BANK
mov ipLengthLSB, w
bank TCP_BANK
mov w, tcpLengthMSB
bank IP_BANK
mov ipLengthMSB, w
snc
inc ipLengthMSB
; update IP <identifier>
inc ipIdentLSB
snz
inc ipIdentMSB
; set IP <protocol> for TCP
mov ipProtocol, #6
; We should rather load remoteIP with tcp socketIP here, but Due
; to limited code space it is Done in IPGenCheckSum.
; compute IP <header_checksum>
call @IPGenCheckSum
; now we're ready to construct the IP header
call @IPStartPktOut
; then construct the TCP header
; point to correct tcb for current tcp connection
mov globTemp1, #(tcb1Offset-TCB1_BANK)
call @SetTCBPointer
; TCP <source_port>,<destination_port>,<sequence_number>,
; <acknowledgement_number>,<hlen>,<code>,<window>
mov indf, #(TCP_HDR_LENGTH<<4)
inc fsr
inc fsr
mov indf, #((TCP_WINDOW_SIZE&$FF00)>>8)
inc fsr
mov indf, #(TCP_WINDOW_SIZE&$00FF)
; make a pointer to the tcb for the current tcp connection
sb flags2.TCP_SOCK
mov globTemp3, #TCB1_BANK
snb flags2.TCP_SOCK
mov globTemp3, #TCB2_BANK
:loop mov fsr, globTemp3
mov w, indf ; load the value
call @TCPTxByte ; transmit and accumulate header
; checksum
inc globTemp3
jb flags2.TCP_SOCK, :check2
cse globTemp3, #TCB1_END ; is the loop finished?
jmp :loop
jmp :outloop
:check2 cse globTemp3, #TCB2_END ; is the loop finished?
jmp :loop
:outloop ; TCP <checksum>
call @TCPCheckSumAddHdr
bank TCP_BANK
mov w, /tcpCheckSumMSB
call NICWriteAgain_4
mov w, /tcpCheckSumLSB
call NICWriteAgain_4
; TCP <urgent_ptr>
mov w, #0
call NICWriteAgain_4
call NICWriteAgain_4
retp
; ******************************************************************************
_TCPRxHeader
; Process the TCP header of a received TCP packet
; INPUT: none
; OUTPUT: Z is set to 1 if the packet is invalid, 0 otherwise
; {tcb1RemotePortMSB,tcb1RemotePortLSB}
; or {tcb2RemotePortMSB,tcb2RemotePortLSB}
; {tcb1SendWinMSB,tcb1SendWinLSB} or {tcb2SendWinMSB,tcb2SendWinLSB}
; tcb1Offset or tcb2Offset
; tcb1Flags or tcb2Flags
; tcpRxFlags
; {tcpTmpSeq4-1} = <sequence_number>
; {tcpTmpAck4-1} = <acknowledgement_number>
; {tcpLengthMSB,tcpLengthLSB} = length of TCP Data
; {ipLengthMSB,ipLengthLSB} = length of TCP Data
; ******************************************************************************
bank TCPPORT_BANK
; <remote_port>
call NICReadAgain_4
mov tcpRemotePortMSB, w ; store remote port MSB
call NICReadAgain_4
mov tcpRemotePortLSB, w ; store remote port LSB
; <destination_port>
call NICReadAgain_4
mov tcpLocalPortMSB, w ; store dest port MSB
call NICReadAgain_4 ;
mov tcpLocalPortLSB, w ; store dest port LSB
call @TCPConnectionManager ; start the tcp conn/socket
; manager
snz ; is the packet OK?
retp ; no, return
; <sequence_number>
bank TCP_BANK
call NICReadAgain_4
mov tcpTmpSeq4, w
call NICReadAgain_4
mov tcpTmpSeq3, w
call NICReadAgain_4
mov tcpTmpSeq2, w
call NICReadAgain_4
mov tcpTmpSeq1, w
_bank TCPTMP_BANK
; <acknowledgement_number>
call NICReadAgain_4
mov tcpTmpAck4, w
call NICReadAgain_4
mov tcpTmpAck3, w
call NICReadAgain_4
mov tcpTmpAck2,w
call NICReadAgain_4
mov tcpTmpAck1, w
call NICReadAgain_4 ; receive the Data offset.
; Used to skip the options
and w, #TCP_OFFSET_MASK ; mask out the offset
mov globTemp2, w ; store w
; point to the correct tcb for the current tcp connection
mov globTemp1, #(tcb1Offset-TCB1_BANK)
call @SetTCBPointer
mov indf, globTemp2
clc
rr indf
rr indf
; ipLength = tcpLength = length of TCP Data
mov w, indf
_bank IP_BANK
sub ipLengthLSB, w ; subtract out size of TCP header
mov w, ipLengthLSB
bank TCP_BANK
mov tcpLengthLSB, w
bank IP_BANK
sc
dec ipLengthMSB
mov w, ipLengthMSB
bank TCP_BANK
mov tcpLengthMSB, w
; <code>
call NICReadAgain_4 ; receive the flags
mov tcpRxFlags, w
mov globTemp2, w
; point to the correct tcb for the current tcp connection
mov globTemp1, #(tcb1Flags-TCB1_BANK)
call @SetTCBPointer
mov indf, globTemp2
; <window>
call NICReadAgain_4
mov globTemp2, w
; point to the correct tcb for the current tcp connection
mov globTemp1, #(tcb1SendWinMSB-TCB1_BANK)
call @SetTCBPointer
mov indf, globTemp2 ; receive the window
call NICReadAgain_4
mov globTemp2, w
; point to the correct tcb for the current tcp connection
mov globTemp1, #(tcb1SendWinLSB-TCB1_BANK)
call @SetTCBPointer
mov indf, globTemp2
; point to the correct tcb for the current tcp connection
mov globTemp1, #(tcb1Offset-TCB1_BANK)
call @SetTCBPointer
sub indf, #((TCP_HDR_LENGTH<<2)-4)
mov w, indf
mov globTemp3, w
clr indf
:loop call NICReadAgain_4
decsz globTemp3
jmp :loop
clz
retp
; ******************************************************************************
_TCPReTransmit
; This is called to retransmit the TCP packet that's already setup in the NIC's
; TCP transmit buffer. Remember that a UDP/ICMP/ARP packet may have been sent
; after the TCP packet was initially sent, so we have to re-setup the NIC
; carefully.
; INPUT: none
; OUTPUT: none
; ******************************************************************************
; re-initialize the NIC's TPSR
bank NIC_BANK
clr nicIOAddr ; CR
:wait call @NICRead
jb wreg.2, :wait ; wait for prior transmission to
; complete
mov w, #%00100010 ; Page0, abort DMA
call @NICWrite
mov nicIOAddr, #$04 ; TPSR
; point to correct tcp tx buffer for current tcp connection
sb flags2.TCP_SOCK
mov w, #TXBUF2_START
snb flags2.TCP_SOCK
mov w, #TXBUF3_START
call @NICWrite
; read the NIC's TCP transmit buffer to find out the IP <length>
; so that we can re-initialize the NIC's TBCR
sb flags2.TCP_SOCK
mov w, #TXBUF2_START
snb flags2.TCP_SOCK
mov w, #TXBUF3_START
mov nicCopySrcMSB, w
mov nicCopySrcLSB, #(6+6+2+2) ; IP <length> (MSB)
call @NICBufRead
bank IP_BANK
mov ipLengthMSB, w
bank NIC_BANK
inc nicCopySrcLSB ; IP <length> (LSB)
call @NICBufRead
bank IP_BANK
mov ipLengthLSB, w
jmp @NICSendTxFrame ; re-transmit the ethernet frame
; ******************************************************************************
_Compare4Inc
; Compares 4 variables in Databanks
; INPUT: globTemp1 = pointer1, globTemp3 = pointer2
; OUTPUT: Z is set on a full match
; ******************************************************************************
bank IP_BANK
mov counter1, #4 ; load the counter
:loop
mov fsr, globTemp3 ; move pointer to fsr
mov w, indf ; move var in w
mov globTemp2, w ; store var in global2
mov fsr, globTemp1 ; move pointer to fsr
mov w, indf ; move var into w
xor w, globTemp2 ; xor tcp var with tcb var
jnz :CmpEnd ; test if equal
inc globTemp1 ; increment pointer
inc globTemp3 ; increment pointer
_bank IP_BANK ; check loop counter until finished
dec counter1
sz
jmp :loop
:CmpEnd retp
; ******************************************************************************
_TCPAppTxDone
; This is called following the last call to TCPAppTxData(). It signifies the
; transmitted Data has successfully reached the remote host
; [TCP API Function]
; INPUT: none
; OUTPUT: none
; ******************************************************************************
; jump to current tcp connection code
jb flags2.TCP_SOCK, :TCPAppTxDone2
; tcp1
retp
; tcp2
:TCPAppTxDone2 retp
ORG $A00 ; Page5
TCPAppRxData jmp _TCPAppRxData
; ******************************************************************************
TCPAppRxBytes
; Indicator to the application that a packet has been received and that
; TCPAppRxByte is about to be called as many times as they are bytes of data
; [TCP API Function]
; INPUT: {tcpAppRxBytesMSB,tcpAppRxBytesLSB} = number of received Data bytes
; OUTPUT: none
; ******************************************************************************
; jump to current tcp connection code
jb flags2.TCP_SOCK, :TCPAppRxBytes2
; tcp1
IF DYNDNS
mov globTemp2, #15 ; set rcv byte counter
mov globTemp3, #DYNDNSReply ; set pointer to rcv buffer
ENDIF
retp
; tcp2
:TCPAppRxBytes2 retp
; ******************************************************************************
TCPAppTxBytes
; Called before transmitting a TCP packet to see if the application has any
; Data it wishes to send. The application cannot send more than TCP_SEG_SIZE
; bytes at one go.
; [TCP API Function]
; INPUT: none
; OUTPUT: {tcp1UnAckMSB,tcp1UnAckLSB}
; or {tcp2UnAckMSB,tcp2UnAckLSB} = number of bytes to transmit
; ******************************************************************************
; check if tcp1 or tcp2's chance to transmit
jb flags2.TCP_TXSEMA, :tcpConn2Tx
; tcp1
clrb flags2.TCP_SOCK ; indicate tcp1 conn.
cse tcp1State, #TCP_ST_ESTABED ; check if in
; established state
retp ; no, return
IF DYNDNS
sb flags2.DYNDNS_TXEN ; check if we may tx
retp ; no
clrb flags2.DYNDNS_TXEN ; yes, clear for next tx
_bank DYNDNS_BANK
; DYNDNS_CLOSE = 0 ; DYNDNS closing or closed
; DYNDNS_CONNECT = 1 ; state machine in connection establishment
; DYNDNS_GET = 2 ; GET command sent, waiting for good/!good reply
; DYNDNS_RPLY = 3 ; Got reply.
; DYNDNS_WAIT = 4 ; Got WAIT response, now delay.
; DYNDNS_STOP = 5 ; Got 911 reply, now stop.
cje DYNDNSState, #DYNDNS_GET, :DYNDNSSndGET ; chk if have to
; tx GET URL
; nothing cje DYNDNSState, #DYNDNS_RPLY, :DYNDNSWait ; chk if have to
; rx reply word
cje DYNDNSState, #DYNDNS_CLOSE, :DYNDNSClose ; chk if have to
; close
;retp ; nothing?
:DYNDNSSndGet mov DYNDNSStrPointer, #(DYNDNS_URL) ; make a pointer to the
; char string.
bank TCP_BANK
mov tcp1UnAckLSB, #(DYNDNS_URL_END-DYNDNS_URL)
retp
:DYNDNSClose ; Will the remote host will initiate the close?
; retp
ENDIF
retp
; tcp2
:tcpConn2Tx setb flags2.TCP_SOCK ; indicate tcp2 conn.
cse tcp2State, #TCP_ST_ESTABED ; check if in
; established state
retp ; no, return
IF HTTP
snb flags2.BROWSER_TYPE ; do not send anything to netscape
; type browser on a post.
retp
bank HTTP_BANK
cje httpParseState, #2, :state2
cje httpParseState, #3, :state3
cje httpParseState, #4, :state4
retp
:state2 ; check how much there is to send
_bank EEPROM_BANK
csae e2FileLenMSB, #(HTTP_SEG_SIZE>>8)
jmp :lastSegment ; msb#1 < msb#2
cse e2FileLenMSB, #(HTTP_SEG_SIZE>>8)
jmp :notLast ; msb#1 > msb#2
csa e2FileLenLSB, #(HTTP_SEG_SIZE&$00FF)
jmp :lastSegment ; #1 <= #2
:notLast ; not the last segment so send as much as possible
; (i.e. full segment)
sub e2FileLenLSB, #(HTTP_SEG_SIZE&$00FF) ; e2FileLen
; -= HTTP_SEG_SIZE
sc ;
dec e2FileLenMSB ;
sub e2FileLenMSB, #(HTTP_SEG_SIZE>>8) ;
_bank TCP_BANK
mov tcp2UnAckMSB, #(HTTP_SEG_SIZE>>8)
mov tcp2UnAckLSB, #(HTTP_SEG_SIZE&$00FF)
retp
:lastSegment ; last segment so send whatever is leftover
mov w, e2FileLenMSB
_bank TCP_BANK
mov tcp2UnAckMSB, w
_bank EEPROM_BANK
mov w, e2FileLenLSB
_bank TCP_BANK
mov tcp2UnAckLSB, w
bank HTTP_BANK
inc httpParseState ; next-state = 3
retp
; no more to send so we close
:state3 call @TCPAppClose
retp
:state4
ENDIF
retp
; ******************************************************************************
TCPAppTxData
; This routine is called once for each byte the application has says it wishes
; to transmit.
; [TCP API Function]
; INPUT: none
; OUTPUT: w = Data byte to transmit
; ******************************************************************************
; jump to current tcp connection code
jb flags2.TCP_SOCK, :TCPAppTxData2
; tcp1
IF DYNDNS
_bank DYNDNS_BANK
cje DYNDNSState, #DYNDNS_GET, :DYNDNSTxGet ; chk if we have
; to tx GET URL
retp ; nothing?
; we have to send a GET URL <CRLF>
:DYNDNSTxGet mov w, #(DYNDNS_URL >> 8) ; upper nibble
jmp DYNDNSRdPrgMemData
ENDIF
retp
; tcp2
:TCPAppTxData2
IF HTTP
bank HTTP_BANK
cje httpURIHash, #URI1, :specialFile ; resource.htm
cje httpURIHash, #URI2, :specialFile ; temperature.htm
cje httpURIHash, #URI3, :specialFile2 ; postctrl.htm
call @E2Read8Ack
retp
:specialFile call @E2Read8Ack
mov globTemp1, w ; save temporarily
csb globTemp1, #$F0
jmp :match
mov w, globTemp1
retp
; look for magic number in file indicating Dynamic content
:specialFile2 setb flags3.LED_LOCK ; lock access to LED
call @E2Read8Ack
mov globTemp1, w ; save temporarily
csb globTemp1, #$F0
jmp :match2
mov w, globTemp1
retp
:match2 ; look if led is on or off now
jb LED_PORT.LED, :ledOffChar
; it is on, return last char of image for ledon.gif
mov w, #'n'
retp
; it is off, return last char of image for ledof.gif
:ledOffChar mov w, #'f'
retp
:match cjne globTemp1, #$F0, :subMatch ; 0xF0 is the magic number
:firstMatch bank HTTP_BANK
mov globTemp2, httpURIHash
mov fsr, #bcd3
cjne globTemp2, #URI1, :here
mov w, pageCount
inc pageCount
jmp :here1
:here _bank ADC_BANK
mov w, adc
:here1 call @Bin8ToBCD
mov w, bcd3+0
call @BCDToASCII
retp
:subMatch sub globTemp1, #$F0
_bank MISC_BANK
mov fsr, #bcd3
add fsr, globTemp1
mov w, indf
call @BCDToASCII
ENDIF
retp
; ******************************************************************************
_TCPAppRxData
; Called once for each byte received in a packet. Will only be called when
; tcpState is established.
; [TCP API Function]
; INPUT: w = received Data byte
; OUTPUT: none
; ******************************************************************************
; jump to current tcp connection code
jb flags2.TCP_SOCK, :TCPAppRxData2
; tcp1
IF DYNDNS
mov globTemp1, w ; store the rcvd byte
test globTemp2 ; check if we got the reply code,
; the rest is junk
snz
retp ; yes, we got it, just return on junk
; bytes
; receive the reply code
mov fsr, globTemp3 ; set pointer
mov indf, globTemp1 ; move rcvd byte to rcv buffer
inc globTemp3 ; advance pointer
dec globTemp2 ; receive until counter done
retp ; return to rcv some more bytes
ENDIF
retp
; tcp2
:TCPAppRxData2
IF HTTP
mov globTemp1, w
_bank HTTP_BANK
; check if this is 2nd packet from Netscape type browser, post
jb flags2.BROWSER_TYPE, :fieldSrch
; look if we got the method already
sb flags3.GOT_HTTP_METHOD
jmp :methodSrch1 ; no, go to method search
; yes, we have the method, jump to correct method parser
jb flags3.HTTP_METHOD, :postMethod
jmp :defaultMethod
:methodSrch1 cje globTemp1, #'P', :isPost ; is it a P ?
clrb flags3.HTTP_METHOD ; it's GET
setb flags3.GOT_HTTP_METHOD ; indicate we have the method
jmp :defaultMethod
:isPost setb flags3.HTTP_METHOD ; yes, so it must be POST or PUT
setb flags3.GOT_HTTP_METHOD ; indicate we have the method
setb flags3.LED_LOCK ; lock access to the LED
clr httpParseState
clr httpParseState2
retp
:postMethod ; have to get the requested resource now to set file pointer
jb flags3.GOT_URI, :fieldSrch ; check if we have to go
test httpParseState ; directly to field srch
jz :stateN0
cje httpParseState, #1, :stateN1
:stateN0 cse globTemp1, #' ' ; search for the space after the method
retp ; keyword
inc httpParseState ; got it, next-state = 1
retp
:stateN1 cje globTemp1, #' ', :gotURI ; make URI until space after
; requested resource
add httpURIHash, globTemp1
retp
; we have to search for the input field now. It's after 2 CRLFs
:fieldSrch cje httpParseState, #1, :gotCtrl
cje httpParseState, #2, :gotLf
cje httpParseState, #3, :gotBlkLine
cje httpParseState, #4, :gotField
csne globTemp1, #$0d ; check for first ctrl
inc httpParseState ; yes, got it
retp ; no
:gotCtrl cjne globTemp1, #$0a, :fldSrchRst
inc httpParseState ; yes, got it
retp ; no
:gotLf cjne globTemp1, #$0d, :fldSrchRst ; check for blank line
inc httpParseState ; yes, got to blank line
retp ; no
:gotBlkLine cjne globTemp1, #$0a, :fldSrchRst ; check for last char of
; blank line
inc httpParseState ; yes, we are at the field now
retp
:gotField cje httpParseState2, #1, :gotl
cje httpParseState2, #2, :gote
cje httpParseState2, #3, :gotd
cje httpParseState2, #4, :gotequal
csne globTemp1, #'l' ; look for 'l'
inc httpParseState2 ; yes, got it
retp ; no
:gotl csne globTemp1, #'e' ; look for 'e'
inc httpParseState2 ; yes, got it
retp ; no
:gote csne globTemp1, #'d' ; look for 'd'
inc httpParseState2 ; yes, got it
retp ; no
:gotd csne globTemp1, #'=' ; look for '='
inc httpParseState2 ; yes, got it
retp ; no
; now the next byte is the control byte for the led control
:gotequal cje globTemp1, #'1', :ledOn
cje globTemp1, #'0', :ledOff
cje globTemp1, #'t', :ledToggle
retp
:ledOn clrb LED_PORT.LED ; switch led on
retp
:ledOff setb LED_PORT.LED ; switch led off
retp
:ledToggle mov w, #(1<<LED) ; toggle led status
xor LED_PORT, w
retp
:fldSrchRst clr httpParseState ; no, gotta start over.
retp
:defaultMethod test httpParseState
jz :state0
cje httpParseState, #1, :state1
cjae httpParseState, #2, :state2
:state0 cse globTemp1, #' ' ; search for the space after the method
retp
inc httpParseState ; got it, next-state = 1
retp
:state1 cje globTemp1, #' ', :gotURI; make URI until space after
; requested resource
add httpURIHash, globTemp1
retp
:gotURI ; got the requested resource, obtain pointer to file
; check if coming from post method
jnb flags3.HTTP_METHOD, :gotURICont
; bit is set, so we came from post method
clr httpParseState ; clear for field parser
setb flags3.GOT_URI ; indicate we got URI for post field parser
:gotURICont mov w, httpURIHash
_bank EEPROM_BANK
mov e2AddrLSB, w
clr e2AddrMSB
clc ; e2Addr = httpURIHash * 2
rl e2AddrLSB ;
rl e2AddrMSB ;
call @E2Init ; reset EEPROM
call @E2SetAddr
call @E2SendRdCmd
call @E2Read8Ack
mov e2AddrMSB, w
call @E2Read8NoAckStop
mov e2AddrLSB, w
; start reading from file
call @E2SetAddr
call @E2SendRdCmd
; file length
call @E2Read8Ack
mov e2FileLenMSB, w
call @E2Read8Ack
mov e2FileLenLSB, w
; file checksum (ignore)
call @E2Read8Ack
call @E2Read8Ack
_bank HTTP_BANK
sb flags3.HTTP_METHOD ; do not increment if post
inc httpParseState ; next-state = 2
retp
:state2 ; here we receive bytes from after the requested resource
ENDIF
retp
IF DYNDNS
; ******************************************************************************
DYNDNSRdPrgMemData ; not relocatable. Must be in same page as caller
; Reads DYNDNS Data stored in program memory.
; INPUT: w contains upper nibble of prog memory location.
; DYNDNSPointer contains lower byte of prog mem location.
; OUTPUT: Data in w register
; ******************************************************************************
mov m, w ; into MODE register
mov w, DYNDNSStrPointer ; lower byte (2 nibbles)
inc DYNDNSStrPointer ; increment pointer
iread ; read data from prog memory into w register
retp
ENDIF
ORG $C00 ; Page6
TCPTransmit jmp _TCPTransmit
TCPAppRxDone jmp _TCPAppRxDone
TCPApp1Init jmp _TCPApp1Init
IF DYNDNS
DYNDNSCompareGood jmp _DYNDNSCompareGood
DYNDNSCompareWait jmp _DYNDNSCompareWait
DYNDNSCompare911 jmp _DYNDNSCompare911
DYNDNSCompare354 jmp _DYNDNSCompare354
ENDIF
; ******************************************************************************
SetTCBPointer
; Sets the fsr register to point to the correct TCB
; INPUT: globTemp1=offset into TCB1_BANK or TCB2_BANK
; OUTPUT: fsr contains pointer to variable in TCB bank
; ******************************************************************************
; check if pointer to be set for tcp1 or 2 connection.
jb flags2.TCP_SOCK, :tcb2pointer
; tcp1
add globTemp1, #TCB1_BANK
mov fsr, globTemp1 ; make pointer to TCB1_BANK for tcp1
retp
; tcp2
:tcb2pointer add globTemp1, #TCB2_BANK
mov fsr, globTemp1 ; make pointer to TCB2_BANK for tcp2
retp
; ******************************************************************************
CheckSocket1IP
; Checks if remoteIP is in tcp socket1
; INPUT: remoteIP3-0, sock1RemoteIP3-0
; OUTPUT: Z set if in there
; ******************************************************************************
mov globTemp1, #remoteIP3
mov globTemp3, #sock1RemoteIP3
call @Compare4Inc
retp
; ******************************************************************************
CheckSocket2IP
; Checks if remoteIP is in tcp socket2
; INPUT: remoteIP3-0, sock2RemoteIP3-0
; OUTPUT: Z set if in there
; ******************************************************************************
mov globTemp1, #remoteIP3
mov globTemp3, #sock2RemoteIP3
call @Compare4Inc
retp
; ******************************************************************************
CopyRemotePortTCB1
; Copies tcpRemotePortMSB,LSB into tcb1RemotePortMSB,LSB
; INPUT: tcpRemotePortMSB,LSB
; OUTPUT: tcb1RemotePortMSB,LSB
; ******************************************************************************
bank TCPPORT_BANK
mov w, tcpRemotePortMSB
bank TCB1_BANK
mov tcb1RemotePortMSB, w
bank TCPPORT_BANK
mov w, tcpRemotePortLSB
bank TCB1_BANK
mov tcb1RemotePortLSB, w
retp
; ******************************************************************************
CopyRemotePortTCB2
; Copies tcpRemotePortMSB,LSB into tcb2RemotePortMSB,LSB
; INPUT: tcpRemotePortMSB,LSB
; OUTPUT: tcb2RemotePortMSB,LSB
; ******************************************************************************
bank TCPPORT_BANK
mov w, tcpRemotePortMSB
bank TCB2_BANK
mov tcb2RemotePortMSB, w
bank TCPPORT_BANK
mov w, tcpRemotePortLSB
bank TCB2_BANK
mov tcb2RemotePortLSB, w
retp
; ******************************************************************************
CheckLocalPortTCB1
; Compares tcpLocalPortLSB, tcpLocalPortMSB against tcb1LocalPortLSB,
; tcb1LocalPortMSB
; INPUT: tcpLocalPortLSB, tcpLocalPortMSB, tcb1LocalPortLSB, tcb1LocalPortMSB
; OUTPUT: Z set if match
; ******************************************************************************
bank TCPPORT_BANK
mov w, tcpLocalPortMSB
bank TCB1_BANK
xor w, tcb1LocalPortMSB
sz
retp
mov w, tcb1LocalPortLSB
bank TCPPORT_BANK
xor w, tcpLocalPortLSB
retp
; ******************************************************************************
CheckLocalPortTCB2
; Compares tcpLocalPortLSB, tcpLocalPortMSB against tcb2LocalPortLSB,
; tcb2LocalPortMSB
; INPUT: tcpLocalPortLSB, tcpLocalPortMSB, tcb2LocalPortLSB, tcb2LocalPortMSB
; OUTPUT: Z set if match
; ******************************************************************************
bank TCPPORT_BANK
mov w, tcpLocalPortMSB
bank TCB2_BANK
xor w, tcb2LocalPortMSB
sz
retp
mov w, tcb2LocalPortLSB
bank TCPPORT_BANK
xor w, tcpLocalPortLSB
retp
; ******************************************************************************
TCPConnectionManager
; Manages TCP connections. Checks incoming tcp packets against listening ports,
; makes new sockets and indicates for which tcp connection the packet is.
; INPUT: none
; OUTPUT: flags2.TCP_SOCK
; ******************************************************************************
; check if we are waiting for an ARP response.
; have to Dump & ignore all incoming tcp packets until ARP
; response received or ARP timed out. The tcp receive functions
; can respond with sending tcp packets which will overwrite
; the stalled tcp packet. If we recorded which tcp conn. buffer
; has a stalled packet, we can accept tcp packets for the other
; tcp conn. but let's keep it simple now
jb flags3.ARP_REQ_SENT, :ignorePacket
; pre-screening to check if the local port=service is offered
call @CheckLocalPortTCB1 ; check if for a port
; we're listening on
jz :TCPSocket1 ; yes, service is bound
; to TCB1_BANK
call @CheckLocalPortTCB2 ; check if for a port
; we're listening on
jz :TCPSocket2 ; yes, service is bound
; to TCB2_BANK
jmp :ignorePacket ; no, we Don't offer the service
:TCPSocket1 call @CheckSocket1IP ; check if remote IP
; is in socket1
jnz :CreateTCPSocket1 ; no, make a new conn./socket
call @CheckRemotePortTCB1 ; yes, check if remote port
; is in TCB1_BANK
jz :TCPConnection1 ; yes, packet is for tcp conn. 1
jmp :CreateTCPSocket1 ; no, but make a new conn.
; if we're listening
:TCPSocket2 call @CheckSocket2IP ; check if remote IP
; is in socket2
jnz :CreateTCPSocket2 ; no, make a new conn./socket
call @CheckRemotePortTCB2 ; yes, check if remote port
; is in TCB2_BANK
jz :TCPConnection2 ; yes, packet is for tcp conn. 2
jmp :CreateTCPSocket2 ; no, but make a new conn.
; if we're listening
:CreateTCPSocket1
; we may only create a socket when tcp1 connection is in
; LISTEN state
_bank TCP_BANK
cjne tcp1State, #TCP_ST_LISTEN, :ignorePacket
; create tcp1 socket
call @CopyRemoteIPSocket1 ; store remote IP in socket1
call @CopyRemotePortTCB1 ; store remote port in socket1
jmp :TCPConnection1
:CreateTCPSocket2
; we may only create a socket when tcp2 connection is in
; LISTEN state
_bank TCP_BANK
cjne tcp2State, #TCP_ST_LISTEN, :ignorePacket
; create tcp2 socket
call @CopyRemoteIPSocket2 ; store remote IP in socket2
call @CopyRemotePortTCB2 ; store remote port in socket2
jmp :TCPConnection2
:TCPConnection1 clrb flags2.TCP_SOCK ; indicate tcp packet is for tcp1
clz ; indicate packet is ok
retp
:TCPConnection2 setb flags2.TCP_SOCK ; indicate tcp packet is for tcp2
clz ; indicate packet is ok
retp
:ignorePacket call @NICDumpRxFrame ; discard the tcp packet
stz ; indicate packet is not ok -
; don't process it
retp
; ******************************************************************************
_TCPTransmit
; See if the application has any Data to transmit. If there are no outstanding
; packets and the application has Data, then transmit a packet.
; INPUT: none
; OUTPUT: none
; ******************************************************************************
_bank TCP_BANK ; _bank cus we called
; TCPAppInit priorly
; check which tcp connection has chance to tx
jb flags2.TCP_TXSEMA, :tcp2Tx
; tcp1 has tx chance
cjae tcp1State, #TCP_ST_ESTABED, :ok1 ; is tcp1
; connection estab?
retp ; exit, tcp1 connection
; not established
; yes, tcp1 is est.
:ok1 test tcp1UnAckMSB ; are there any bytes
; unacknowledged?
jnz :timeout1
test tcp1UnAckLSB
jnz :timeout1
cje tcp1State, #TCP_ST_FINWAIT1, :finTimeout ; check for
; FIN timeout
jmp :askAppTxData
; tcp2 has tx chance
:tcp2Tx cjae tcp2State, #TCP_ST_ESTABED, :ok2 ; is tcp2
; connection estab?
retp ; exit, tcp2 connection
; not established
; yes, tcp2 is est.
:ok2 test tcp2UnAckMSB ; are there any bytes
; unacknowledged?
jnz :timeout2
test tcp2UnAckLSB
jnz :timeout2
cje tcp2State, #TCP_ST_FINWAIT1, :finTimeout ; check for
; FIN timeout
:askAppTxData call @TCPAppTxBytes ; ask the application if
; it wants to tx
_bank TCP_BANK ; _bank cus we called
; TCPAppTxBytes priorly
; check if unack bytes from tcp1 or 2
jb flags2.TCP_SOCK, :chkAppTxDataCon2
; tcp1
mov w, tcp1UnAckMSB
or w, tcp1UnAckLSB
jnz :appHasTxData
retp ; nope, it Doesn't; so we're Done here then
; tcp2
:chkAppTxDataCon2
mov w, tcp2UnAckMSB
or w, tcp2UnAckLSB
jnz :appHasTxData
retp ; nope, it Doesn't; so we're Done here then
:appHasTxData ; start a TCP packet
; check if for tcp1 or 2
jb flags2.TCP_SOCK, :loadUnackTcp2
; tcp1
mov tcpLengthLSB, tcp1UnAckLSB ; tcpLength =
; # bytes to transmit
mov tcpLengthMSB, tcp1UnAckMSB
jmp :contAppHasTxData
; tcp2
; tcpLength = # bytes to transmit
:loadUnackTcp2 mov tcpLengthLSB, tcp2UnAckLSB
mov tcpLengthMSB, tcp2UnAckMSB
:contAppHasTxData
mov globTemp1, #(tcb1Flags-TCB1_BANK)
; set pointer to correct tcb for current tcp connection
call @SetTCBPointer
mov indf, #((1<TCP_FLAG_PSH)|(1<<TCP_FLAG_ACK))
call @TCPCheckSumInit
call @TCPStartPktOut ; send the header
; insert the packet Data while computing the checksum
; over the Data
bank TCP_BANK
; check if copy for tcp1 or 2
jb flags2.TCP_SOCK, :cpyUnAckTCP2
; tcp1
mov tcpTmpLSB, tcp1UnAckLSB
mov tcpTmpMSB, tcp1UnAckMSB
jmp :dataLoopBgn
; tcp2
:cpyUnAckTCP2 mov tcpTmpLSB, tcp2UnAckLSB
mov tcpTmpMSB, tcp2UnAckMSB
:dataLoopBgn inc tcpTmpMSB ; so that we can loop easier later
:dataLoop call @TCPAppTxData
_banky TCP_BANK ; cus we called TCPAppTxData
; priorly
call @NICWriteAgain ; which Doesn't clobber w,
; which is nice
call @TCPCheckSumAcc ; accumulate the checksum
decsz tcpTmpLSB
jmp :dataLoop
decsz tcpTmpMSB
jmp :dataLoop
; now go back and fill in the TCP checksum
bank NIC_BANK
; use correct tx buffer for current tcp connection
sb flags2.TCP_SOCK
mov w, #TXBUF2_START
snb flags2.TCP_SOCK
mov w, #TXBUF3_START
mov nicCopySrcMSB, w
mov nicCopySrcLSB, #(6+6+2+20+16) ; TCP <checksum> (MSB)
bank TCP_BANK
mov w, /tcpCheckSumMSB
call @NICBufWrite
bank NIC_BANK
inc nicCopySrcLSB
bank TCP_BANK
mov w, /tcpCheckSumLSB
call @NICBufWrite
call @NICSendTxFrame ; end and send the packet
bank TIMER_BANK ; initialise the restart timer
; check if tcp1 or 2 timer to be cleared
jb flags2.TCP_SOCK, :initTcp2Timer
; tcp1
clr tcp1TimerMSB
clr tcp1TimerLSB
retp
; tcp2
:initTcp2Timer clr tcp2TimerMSB
clr tcp2TimerLSB
retp
:finTimeout bank TIMER_BANK
; check if tcp1 or 2 timer to be checked
jb flags2.TCP_TXSEMA, :chkClrTcp2Tmr
; tcp1
csae tcp1TimerMSB, #TCP_RESTART_EXP ; has the restart timer
; expired?
retp ; no
clr tcp1TimerMSB ; yes, initialise the
; restart timer
clr tcp1TimerLSB
jmp @TCPSendFin
; tcp2
:chkClrTcp2Tmr csae tcp2TimerMSB, #TCP_RESTART_EXP ; has the timer expired?
retp ; no
clr tcp2TimerMSB ; yes, initialise the
; restart timer
clr tcp2TimerLSB
jmp @TCPSendFin
; check if timed out on waiting for ack on tcp connection1
:timeout1 bank TIMER_BANK
csae tcp1TimerMSB, #TCP_RESTART_EXP ; has the restart timer
; expired?
retp ; no
clr tcp1TimerMSB ; yes, initialise the
; restart timer
clr tcp1TimerLSB
clrb flags2.TCP_SOCK ; indicate conn1.
jmp @TCPReTransmit ; transmit the packet
; again
:timeout2 bank TIMER_BANK
csae tcp2TimerMSB, #TCP_RESTART_EXP ; has the restart timer
; expired?
retp ; no
clr tcp2TimerMSB ; yes, initialise the
; restart timer
clr tcp2TimerLSB
setb flags2.TCP_SOCK ; indicate conn2.
jmp @TCPReTransmit ; transmit the packet
; again
IF DYNDNS
; ******************************************************************************
_DYNDNSCompareGood
; Compares the DYNDNS reply code in memory against Good.
; INPUT: DYNDNSReplyCode
; OUTPUT: Z = set if reply code
; ******************************************************************************
_bank DYNDNSREPLY_BANK
mov w, #'g'
xor w, DYNDNSReplyCode
sz
retp
mov w, #'o'
xor w, DYNDNSReplyCode+1
sz
retp
mov w, #'o'
xor w, DYNDNSReplyCode+2
retp
; ******************************************************************************
_DYNDNSCompareWait
; Compares the DYNDNS reply code in memory against Wait.
; INPUT: DYNDNSReplyCode
; OUTPUT: Z = set if reply code
; ******************************************************************************
_bank DYNDNSREPLY_BANK
mov w, #'w'
xor w, DYNDNSReplyCode
sz
retp
mov w, #'a'
xor w, DYNDNSReplyCode+1
sz
retp
mov w, #'i'
xor w, DYNDNSReplyCode+2
retp
; ******************************************************************************
_DYNDNSCompare911
; Compares the DYNDNS reply code in memory against 911
; INPUT: DYNDNSReplyCode
; OUTPUT: Z = set if reply code is 911
; ******************************************************************************
_bank DYNDNSREPLY_BANK
mov w, #'9'
xor w, DYNDNSReplyCode
sz
retp
mov w, #'1'
xor w, DYNDNSReplyCode+1
sz
retp
mov w, #'1'
xor w, DYNDNSReplyCode+2
retp
; ******************************************************************************
_DYNDNSCompare354
; Compares the DYNDNS reply code in memory against 354
; INPUT: DYNDNSReplyCode
; OUTPUT: Z = set if reply code is 220
; ******************************************************************************
_bank DYNDNSREPLY_BANK
mov w, #'3'
xor w, DYNDNSReplyCode3
sz
retp
mov w, #'5'
xor w, DYNDNSReplyCode2
sz
retp
mov w, #'4'
xor w, DYNDNSReplyCode1
retp
ENDIF
; ******************************************************************************
_TCPAppRxDone
; This is called following the last call to TCPAppRxData(). It signifies the
; end of the received packet
; [TCP API Function]
; INPUT: none
; OUTPUT: none
; ******************************************************************************
; jump to current tcp connection code
jb flags2.TCP_SOCK, :TCPAppRxDone2
; tcp1
IF DYNDNS
_bank DYNDNS_BANK
cje DYNDNSState, #DYNDNS_GET, :DYNDNSGet ; check if we
; sent a GETR URL
retp ; nothing?
; we have established a tcp conn with a remote DYNDNS
:DYNDNSGet
call @DYNDNSCompareGood ; check if we got Good.
; sz
; jmp :DYNDNSWeQuit ; no, we got something else
; we got a 220 service ready reply
; jmp :DYNDNSNxtState
; we have received a response to our HELO sent.
; We expect it to be 250
:DYNDNSNxtState _bank DYNDNS_BANK
inc DYNDNSState
setb flags2.DYNDNS_TXEN ; enable DYNDNS transmit so that
; a new command
; or text can be sent
ENDIF
retp
; tcp2
:TCPAppRxDone2
IF HTTP
; check if end of 2nd packet rcvd from Netscape type browser
_bank HTTP_BANK
jnb flags2.BROWSER_TYPE, :methodChk
clrb flags2.BROWSER_TYPE ; yes, clear flag
jmp :getM ; reset other flags
; check if we rcvd a packet with http post and did not get 'led'
; field meaning it came from a Netscape browser.
:methodChk jnb flags3.HTTP_METHOD, :getM ; skip chk if method get
; it is post. check if we got the 'led' field in this packet
cje httpParseState2, #4, :getM
setb flags2.BROWSER_TYPE ; no, netscape type browser
clr httpParseState ; clear for parser in 2nd pkt
:getM clrb flags3.GOT_HTTP_METHOD ; clear have method for nxt pkt
clrb flags3.GOT_URI
mov w, #2 ; restore the state of the
mov httpParseState, w ; httpParseState variable we
ENDIF ; borrowed for the POST parser
retp
; ******************************************************************************
_TCPApp1Init
; Called repeatedly as long as TCP connection1 state is closed
; [TCP API Function]
; INPUT: none
; OUTPUT: none
; ******************************************************************************
IF DYNDNS
;
; DYNDNS - Check if 8 byte timer has expired, or if button pressed
;
;
; check if this is the first time sw is pressed, or if it is
; still held in from the first time it was pressed.
; If email goes through before switch is released this will
; prevent another.
jnb flags2.SW_PRESSED, :firstPressChk
mov w, #(1<<SW) ; look if SW1 is pressed
and w, SW_PORT
snz ; no, so it must be released now
retp ; yes, have to wait until released
clrb flags2.SW_PRESSED
; check if the prev email was accepted by the remote DYNDNS, so we
; can try again.
jnb flags3.DYNDNS_OK, :sendMailAgain
; check here if we want to send email.
:firstPressChk mov w, #(1<<SW) ; look if SW1 is pressed
and w, SW_PORT
sz ; yes
retp ; no, just return
setb flags2.SW_PRESSED ; indicate switch is pressed
; yes, so we need to send an email now or again
:sendMailAgain clrb flags3.DYNDNS_OK ; clear the 'mail went through' indicator
; before we send it
_bank DYNDNS_BANK
mov w, #DYNDNS_CONNECT ; start DYNDNS state machine to connect
mov DYNDNSState, w
; set up local & remote ports for tcp1 connection
_bank TCB1_BANK
mov tcb1LocalPortLSB, #100
mov tcb1LocalPortMSB, #100
mov tcb1RemotePortLSB, #DYNDNS_PORT_LSB
mov tcb1RemotePortMSB, #DYNDNS_PORT_MSB
; fill in remote IP to connect with in tcp socket
_bank TCPSOCKET_BANK
mov sock1RemoteIP3, #DYNDNS_SERVER_IP3
mov sock1RemoteIP2, #DYNDNS_SERVER_IP2
mov sock1RemoteIP1, #DYNDNS_SERVER_IP1
mov sock1RemoteIP0, #DYNDNS_SERVER_IP0
; indicate tcp1 connection
clrb flags2.TCP_SOCK
jmp @TCPAppActiveOpen ; open a tcp connection on socket1
ENDIF
retp
ORG $E00 ; Page7
TCPApp2Init jmp _TCPApp2Init
DeleteSocket1 jmp _DeleteSocket1
DeleteSocket2 jmp _DeleteSocket2
IF HTTP
; jump table can be moved with all E2 functions if neccessary.
E2Delay600ns jmp _E2Delay600ns
E2Delay900ns jmp _E2Delay900ns
E2Delay1300ns jmp _E2Delay1300ns
E2SDAInput jmp _E2SDAInput
E2SDAOutputHi jmp _E2SDAOutputHi
E2SDAOutputLo jmp _E2SDAOutputLo
E2GenStartCond jmp _E2GenStartCond
E2GenStopCond jmp _E2GenStopCond
E2Write8 jmp _E2Write8
E2Read8 jmp _E2Read8
E2Read8Ack jmp _E2Read8Ack
E2Read8NoAckStop jmp _E2Read8NoAckStop
E2RecvAck jmp _E2RecvAck
E2SendAck jmp _E2SendAck
E2SendNotAck jmp _E2SendNotAck
E2SendRdCmd jmp _E2SendRdCmd
E2SendWrCmd jmp _E2SendWrCmd
E2SetAddr jmp _E2SetAddr
Bin8ToBCD jmp _Bin8ToBCD
BCDToASCII jmp _BCDToASCII
ENDIF
IF DHCP
DHCPREQUESTSend jmp _DHCPREQUESTSend
DHCPDISCOVERSend jmp _DHCPDISCOVERSend
DHCPSendCommon2 jmp _DHCPSendCommon2
UDPProcBcstPktIn jmp _UDPProcBcstPktIn
ENDIF
; ******************************************************************************
NICReadAgain_7
; Shortform for calling NICReadAgain(), which is in Page1 (This is in Page7)
; ******************************************************************************
jmp @NICReadAgain
; ******************************************************************************
NICWriteAgain_7
; Shortform for calling NICWriteAgain(), which is in Page1 (This is in Page7)
; ******************************************************************************
jmp @NICWriteAgain
; ******************************************************************************
NICDumpRxFrame_7
; Shortform for calling NICDumpRxFrame(), which is in Page1 (This is in Page7)
; ******************************************************************************
jmp @NICDumpRxFrame
; ******************************************************************************
UDPEndPktOut
; Wraps up and transmits the UDP packet
; [UDP API Function]
; INPUT: none
; OUTPUT: none
; ******************************************************************************
_bank NIC_BANK
jmp @NICSendTxFrameNow
; ******************************************************************************
UDPAppInit
; Application UDP Initialization code (Example)
; This function is called automatically once by the stack During startup
; [UDP API Function]
; INPUT: none
; OUTPUT: none
; ******************************************************************************
_bank UDP_BANK
mov udpRxDestPortMSB, #UDP_RX_DEST_MSB
mov udpRxDestPortLSB, #UDP_RX_DEST_LSB
retp
; ******************************************************************************
UDPAppProcPktIn
; Application Incoming UDP packet handler (Example)
; This function is called whenever an application (matches udpRxDestPortxSB)
; packet is received. The appplication can call NICReadAgain() to extract
; sequentially extract each byte of the <data> field in the UDP packet.
; [UDP API Function]
; INPUT: {udpRxDataLenMSB,udpRxDataLenLSB} = number of bytes in UDP <data>
; {udpRxSrcPortMSB,udpRxSrcPortLSB} = UDP <source_port>
; OUTPUT: none
; ******************************************************************************
call NICReadAgain_7
and w, #%01000000
xor ra, w ; toggle I/O pins
_bank UDP_BANK
clr udpTxSrcPortMSB
clr udpTxSrcPortLSB
mov udpTxDestPortMSB, udpRxSrcPortMSB
mov udpTxDestPortLSB, udpRxSrcPortLSB
clr udpTxDataLenMSB ; send 2 bytes of data
mov udpTxDataLenLSB, #2 ;
call UDPStartPktOut
mov w, ra ; send new port state
call NICWriteAgain_7
mov w, #$00 ; one-byte padding
call NICWriteAgain_7
jmp UDPEndPktOut
; ******************************************************************************
UDPStartPktOut
; Starts an outgoing UDP packet by constructing an IP and UDP packet header
; [UDP API Function]
; INPUT: {remoteIP0-3} = Destination IP addr for UDP pkt
; {udpTxSrcPortMSB,udpTxSrcPortLSB} = UDP Source Port
; {udpTxDestPortMSB,udpTxDestPortLSB} = UDP Destination Port
; {udpTxDataLenMSB,udpTxDataLenLSB} = UDP Data Length (just Data)
; OUTPUT: none
; ******************************************************************************
; compute IP <total_length>
_bank UDP_BANK
mov w, udpTxDataLenLSB
_bank IP_BANK
mov ipLengthLSB, w
_bank UDP_BANK
mov w, udpTxDataLenMSB
_bank IP_BANK
mov ipLengthMSB, w
add ipLengthLSB, #(20+8) ; add in size of UDP hdr (8)
; and IP hdr (20)
snc
inc ipLengthMSB
; update IP <identifier>
inc ipIdentLSB
snz
inc ipIdentMSB
; set IP <protocol> for UDP
mov ipProtocol, #17
; compute IP <header_checksum>
call @IPGenCheckSum
; now we're ready to construct the IP header
call @IPStartPktOut
; then construct the UDP header
_bank UDP_BANK
; UDP <source_port>
mov w, udpTxSrcPortMSB
call NICWriteAgain_7
mov w, udpTxSrcPortLSB
call NICWriteAgain_7
; UDP <destination_port>
mov w, udpTxDestPortMSB
call NICWriteAgain_7
mov w, udpTxDestPortLSB
call NICWriteAgain_7
; UDP <length>
mov w, #8
add w, udpTxDataLenLSB
mov w, udpTxDataLenMSB
snc
inc wreg
call NICWriteAgain_7
mov w, #8
add w, udpTxDataLenLSB
call NICWriteAgain_7
; UDP <checksum> = 0
mov w, #$0
call NICWriteAgain_7
jmp NICWriteAgain_7
; ******************************************************************************
UDPProcPktIn
; Processes an Incoming UDP packet
; INPUT: nicCurrPktPtr = points to beginning of received packet
; OUTPUT: none
; ******************************************************************************
_bank UDP_BANK
; UDP <source_port>
call NICReadAgain_7
mov udpRxSrcPortMSB, w
call NICReadAgain_7
mov udpRxSrcPortLSB, w
; UDP <destination_port>
call NICReadAgain_7
xor w, udpRxDestPortMSB
jnz :outtaHere
call NICReadAgain_7
xor w, udpRxDestPortLSB
jnz :outtaHere
; UDP <message_length>
call NICReadAgain_7
mov udpRxDataLenMSB, w
call NICReadAgain_7
mov udpRxDataLenLSB, w
; ignore UDP <checksum>
REPT 2
call NICReadAgain_7
ENDR
; UDP <data>
IF DHCP
snb flags.RX_IS_IP_BCST
call UDPProcBcstPktIn
; prevent UDP API func call when in config
_bank DHCP_BANK
jb dhcpFlags.DHCP_CONFIG, :outtaHere
ENDIF
sb flags.RX_IS_IP_BCST
call UDPAppProcPktIn
:outtaHere _bank IP_BANK
jmp NICDumpRxFrame_7
IF DHCP
; ******************************************************************************
CheckIPLeaseExpire
; Checks if our IP lease has expired. If it has, renew it. If we never got a
; lease in the first place, just return.
; INPUT: none
; OUTPUT: none
; ******************************************************************************
sb flags2.GOT_IP_LEASE ; test if we got an IP lease
retp ; return, we never got an IP lease
; we got an IP lease previously
; check if it is expiring. We're comparing seconds against
; seconds here
_bank DHCP_BANK
mov w, dhcpIPLeaseTm3
xor w, dhcpTimer3
jnz :outtaLeaseChk
mov w, dhcpIPLeaseTm2
xor w, dhcpTimer2
jnz :outtaLeaseChk
mov w, dhcpIPLeaseTm1
xor w, dhcpTimer1
jnz :outtaLeaseChk
mov w, dhcpIPLeaseTm0
xor w, dhcpTimer0
jnz :outtaLeaseChk
; Lease has expired, renew it
clrb flags2.GOT_IP_LEASE ; reset IP lease.
setb flags2.RENEW_IP_LEASE ; indicate this is a lease
; renewal
jmp DHCPConfig ; start the DHCP configuration
:outtaLeaseChk retp
; ******************************************************************************
DHCPConfig
; This function uses DHCP, Dynamic Host Configuration Protocol, to configure the
; iSX. The result is an assigned IP address for a certain time.
; INPUT: none
; OUTPUT: none
; ******************************************************************************
_bank DHCP_BANK
setb dhcpFlags.DHCP_CONFIG ; indicate DHCP config in progress
; initialize UDP receive port for DHCP
_bank UDP_BANK
clr udpRxDestPortMSB ; DHCP(BOOTP) Client (Port 68)
mov udpRxDestPortLSB, #68 ;
; DHCPConfig will be called again and again for IP lease
; renewals. Check if this is a renewal or a first entry from
; startup
jb flags2.RENEW_IP_LEASE, :leaseRenew
; Send a DHCP Discovery message
:dhcpDiscSend call DHCPDISCOVERSend ; send DHCPDISCOVER message
_bank DHCP_BANK
clr dhcpTimer0 ; initialize receive timeout timer
; Wait with timeout for an incoming frame
; on each timeout, a new Discovery will be sent until max tries
; reached
:dhcpWaitOffer call @NICWaitRxFrame ; check if we received something
jb flags2.GOT_RX_FRAME, :dhcpGotRxFrame ; check if we
; got something
_bank DHCP_BANK
cje dhcpTimer0, #DHCP_DISC_EXP, :outtaDHCP ; check if
; timeout - Disc
jmp :dhcpWaitOffer ; not timed out yet, wait some more
; Check if rcvd frame is UDP (DHCP carrier).
; If it is UDP, process contents, else go back to
; waiting for an incoming frame.
:dhcpGotRxFrame call @CheckIPDatagram
jnb flags.RX_IS_UDP, :dhcpWaitOffer
clrb flags.RX_IS_UDP
call UDPProcPktIn
sb flags.GOT_DHCP_OFFER
jmp :dhcpWaitOffer
; If we got to here, we rcvd a valid DHCP offer.
; Send a DHCP request message
:leaseRenew clr globTemp3 ; initialize re-transmit counter
:dhcpReqSend cje globTemp3, #DHCP_REQ_TRIES, :outtaDHCP ; tried enough?
_bank DHCP_BANK
clr dhcpTimer0
call DHCPREQUESTSend
inc globTemp3
; Wait with timeout for an incoming frame
; on each timeout, a new request will be sent
; until max tries reached
:dhcpWaitAck call @NICWaitRxFrame
jb flags2.GOT_RX_FRAME, :dhcpGotAck
_bank DHCP_BANK
cje dhcpTimer0, #DHCP_REQ_EXP, :dhcpReqSend
jmp :dhcpWaitAck ; wait some more
; Check if rcvd frame is UDP (DHCP carrier).
; If it is UDP, process contents, else go back to waiting
; for an incoming frame.
:dhcpGotAck call @CheckIPDatagram ; check packet type
jnb flags.RX_IS_UDP, :dhcpWaitAck ; if not UDP
; go back to waiting
clrb flags.RX_IS_UDP
call UDPProcPktIn ; is UDP, process contents
sb flags2.GOT_IP_LEASE ; check if we got an IP lease
jmp :dhcpWaitAck ; no wait some more
; reset 1sec renewal timers
_bank DHCP_BANK
clr dhcpBaseTimer0
clr dhcpBaseTimer1
clr dhcpTimer0
clr dhcpTimer1
clr dhcpTimer2
clr dhcpTimer3
:outtaDHCP clrb dhcpFlags.DHCP_CONFIG ; reset
call @UDPAppInit ; restore the user UDP application port
; check if successful, otherwise rebind
jb flags2.GOT_IP_LEASE, :dhcpConfigExit
jmp @Main ; rebind
; success, exit normally
:dhcpConfigExit clrb flags2.RENEW_IP_LEASE ; reset IP lease renewal
retp
; ******************************************************************************
DHCPSendCommon1
; Helper function for DHCPDISCOVERSend and DHCPREQUESTSend
; INPUT: none
; OUTPUT: none
; ******************************************************************************
; set ethernet addr to broadcast addr
_bank NIC_BANK
mov w, #$FF
mov nicRemoteEth0, w
mov nicRemoteEth1, w
mov nicRemoteEth2, w
mov nicRemoteEth3, w
mov nicRemoteEth4, w
mov nicRemoteEth5, w
; set IP addr to broadcast addr
bank IP_BANK
mov w, #$FF
mov remoteIP3, w
mov remoteIP2, w
mov remoteIP1, w
mov remoteIP0, w
_bank UDP_BANK
clr udpTxSrcPortMSB ; DHCP client
mov udpTxSrcPortLSB, #68 ;
clr udpTxDestPortMSB ; DHCP server
mov udpTxDestPortLSB, #67 ;
call @UDPStartPktOut
; <op>
mov w, #1
call NICWriteAgain_7
; <htype>
mov w, #1
call NICWriteAgain_7
; <hlen>
mov w, #6
call NICWriteAgain_7
; <hops>
mov w, #0
call NICWriteAgain_7
; <transaction_id> = 0xABABABAB
mov w, #$AB
REPT 4
call NICWriteAgain_7
ENDR
; <seconds> = 256
mov w, #1
REPT 2
call NICWriteAgain_7
ENDR
; <flags>
mov w, #$80
call NICWriteAgain_7
mov w, #0
jmp NICWriteAgain_7
; ******************************************************************************
_DHCPSendCommon2
; Helper function for DHCPDISCOVERSend and DHCPREQUESTSend
; INPUT: none
; OUTPUT: none
; ******************************************************************************
; <client_hw_addr>
mov w, #SX_ETH_ADDR0
call NICWriteAgain_7
mov w, #SX_ETH_ADDR1
call NICWriteAgain_7
mov w, #SX_ETH_ADDR2
call NICWriteAgain_7
mov w, #SX_ETH_ADDR3
call NICWriteAgain_7
mov w, #SX_ETH_ADDR4
call NICWriteAgain_7
mov w, #SX_ETH_ADDR5
call NICWriteAgain_7
; <client_hw_addr>,<server_host_name>,<boot_filename>
mov globTemp1, #(10+64+128)
mov w, #0
:loop2 call NICWriteAgain_7
decsz globTemp1
jmp :loop2
; <option_magic_cookie>
mov w, #99
call NICWriteAgain_7
mov w, #130
call NICWriteAgain_7
mov w, #83
call NICWriteAgain_7
mov w, #99
jmp NICWriteAgain_7
; ******************************************************************************
_DHCPDISCOVERSend
; Send DHCPDISCOVER message
; INPUT: none
; OUTPUT: none
; ******************************************************************************
_bank UDP_BANK
clr udpTxDataLenMSB
mov udpTxDataLenLSB, #(240+3+0+1) ; without req-IP option
;mov udpTxDataLenLSB, #(240+3+6+1) ; with req-IP option
call DHCPSendCommon1
; <client_IP>, <your_IP>,<server_IP>,<router_IP> = 0
mov globTemp1, #(4+4+4+4)
mov w, #0
:loop1 call NICWriteAgain_7
decsz globTemp1
jmp :loop1
call DHCPSendCommon2
; <option-message_type>
mov w, #53
call NICWriteAgain_7
mov w, #1
call NICWriteAgain_7
mov w, #1 ; DHCPDISCOVER
call NICWriteAgain_7
; <option-requested_IP> -- optional
;mov w, #50
;call NICWriteAgain_7
;mov w, #4
;call NICWriteAgain_7
;mov w, #SX_IP_ADDR3
;call NICWriteAgain_7
;mov w, #SX_IP_ADDR2
;call NICWriteAgain_7
;mov w, #SX_IP_ADDR1
;call NICWriteAgain_7
;mov w, #SX_IP_ADDR0
;call NICWriteAgain_7
; <option-end_option> -- not optional
mov w, #255
call NICWriteAgain_7
; and ... that should Do it!
jmp UDPEndPktOut
; ******************************************************************************
_DHCPREQUESTSend
; Send DHCPREQUEST message
; INPUT: none
; OUTPUT: none
; ******************************************************************************
_bank UDP_BANK
mov udpTxDataLenMSB, #((240+3+6+6+1)>>8)
mov udpTxDataLenLSB, #((240+3+6+6+1)&$FF)
call DHCPSendCommon1
; <client_IP>
_bank IP_BANK
mov w, myIP3
call NICWriteAgain_7
mov w, myIP2
call NICWriteAgain_7
mov w, myIP1
call NICWriteAgain_7
mov w, myIP0
call NICWriteAgain_7
; <your_IP>,<server_IP>,<router_IP> = 0
mov globTemp1, #(4+4+4)
mov w, #0
:loop1 call NICWriteAgain_7
decsz globTemp1
jmp :loop1
call DHCPSendCommon2
; <option-message_type>
mov w, #53
call NICWriteAgain_7
mov w, #1
call NICWriteAgain_7
mov w, #3 ; DHCPREQUEST
call NICWriteAgain_7
; <option-server_id>
mov w, #54 ; option server identifier
call NICWriteAgain_7
mov w, #4 ; length
call NICWriteAgain_7
_bank DHCP_BANK
mov w, dhcpServerId3
call NICWriteAgain_7
mov w, dhcpServerId2
call NICWriteAgain_7
mov w, dhcpServerId1
call NICWriteAgain_7
mov w, dhcpServerId0
call NICWriteAgain_7
; <option-requested_IP> -- not optional
mov w, #50
call NICWriteAgain_7
mov w, #4
call NICWriteAgain_7
_bank IP_BANK
mov w, myIP3
call NICWriteAgain_7
mov w, myIP2
call NICWriteAgain_7
mov w, myIP1
call NICWriteAgain_7
mov w, myIP0
call NICWriteAgain_7
; <option-end_option> -- not optional
mov w, #255
call NICWriteAgain_7
; and ... that should do it!
jmp UDPEndPktOut
; ******************************************************************************
_UDPProcBcstPktIn
; The only kind of broadcast UDP packets accepted are DHCP messages: DHCPOFFER
; and DHCPACK
; INPUT: none
; OUTPUT: none
; ******************************************************************************
call NICReadAgain_7
xor w, #2 ; check <op> = BOOTP reply
jnz :outtaHere
call NICReadAgain_7
xor w, #1 ; check <htype> = 1
jnz :outtaHere
call NICReadAgain_7
xor w, #6 ; check <hlen> = 6
jnz :outtaHere
; ignore <hops>
call NICReadAgain_7
; check <transaction_id> = 0xABABABAB
REPT 4
call NICReadAgain_7
xor w, #$AB
jnz :outtaHere
ENDR
; ignore <seconds>, <flags>, <client_IP>
mov globTemp1, #(2+2+4)
:loop1 call NICReadAgain_7
decsz globTemp1
jmp :loop1
; record <your_IP>
_bank IP_BANK
call NICReadAgain_7
mov myIP3, w
call NICReadAgain_7
mov myIP2, w
call NICReadAgain_7
mov myIP1, w
call NICReadAgain_7
mov myIP0, w
; check if it is non-zero
mov w, myIP3
or w, myIP2
or w, myIP1
or w, myIP0
jz :outtaHere
; skip <server_IP>, <router_IP>, <client_hw_addr>,
; <sever_host_name>, <boot_filename>, <option_magic_cookie>
mov globTemp1, #(4+4+16+64+128+4)
:loop2 call @NICPseudoRead
decsz globTemp1
jmp :loop2
; <option-message_type>
call NICReadAgain_7
xor w, #53 ; DHCP Message Type
jnz :outtaHere
call NICReadAgain_7
xor w, #1 ; length
jnz :outtaHere
call NICReadAgain_7
xor w, #2 ; DHCPOFFER
snz
setb flags.GOT_DHCP_OFFER
xor w, #2 ; get back value in w
xor w, #5 ; DHCPACK
jnz :loop4
setb flags.GOT_IP_ADDR ; indicate we got
; assigned an IP addr
setb flags2.GOT_IP_LEASE
; now search for that Dang(!) <option-server_id>
:loop4 call NICReadAgain_7
xor w, #54 ; Server Identifier
jz :foundServId
xor w, #54 ; restore value
xor w, #58 ; check for T1 (renewal time)
jnz :more01 ; go to routine to read and discard
call NICReadAgain_7
xor w, #4 ; length
jnz :outtaHere
_bank DHCP_BANK ; record T1
call NICReadAgain_7
mov dhcpIPLeaseTm3, w
call NICReadAgain_7
mov dhcpIPLeaseTm2, w
call NICReadAgain_7
mov dhcpIPLeaseTm1, w
call NICReadAgain_7
mov dhcpIPLeaseTm0, w
jmp :loop4
:more01
call NICReadAgain_7 ; length
mov globTemp1, w
:loop3 call @NICPseudoRead ; read Data but ignore
decsz globTemp1 ; read as many times as length
jmp :loop3
jmp :loop4
:foundServId call NICReadAgain_7 ; ignore length
_bank DHCP_BANK
call NICReadAgain_7
mov dhcpServerId3, w
call NICReadAgain_7
mov dhcpServerId2, w
call NICReadAgain_7
mov dhcpServerId1, w
call NICReadAgain_7
mov dhcpServerId0, w
:outtaHere retp
ENDIF
IF HTTP
; ******************************************************************************
_E2Delay600ns
; Delay 600ns
; INPUT: none
; OUTPUT: none
; ******************************************************************************
mov w, #6
:loop decsz wreg
jmp :loop
retp
; ******************************************************************************
_E2Delay900ns
; Delay 900ns
; INPUT: none
; OUTPUT: none
; ******************************************************************************
mov w, #8
:loop decsz wreg
jmp :loop
retp
; ******************************************************************************
_E2Delay1300ns
; Delay 1300ns
; INPUT: none
; OUTPUT: none
; ******************************************************************************
mov w, #13
:loop decsz wreg
jmp :loop
retp
; ******************************************************************************
_E2SDAInput
_E2SDAOutputHi
; Set SDA as input
; INPUT: none
; OUTPUT: none
; ******************************************************************************
mov !E2_PORT, #E2_DDR_SDA_IN
retp
; ******************************************************************************
_E2SDAOutputLo
; Set SDA as output-low
; INPUT: none
; OUTPUT: none
; ******************************************************************************
clrb E2SDA_PIN
mov !E2_PORT, #E2_DDR_SDA_OUT
retp
; ******************************************************************************
_E2GenStartCond
; Generate START condition
; INPUT: none
; OUTPUT: none
; ******************************************************************************
call E2SDAOutputHi
setb E2SCL_PIN
call E2Delay600ns
call E2SDAOutputLo
call E2Delay600ns
clrb E2SCL_PIN
call E2Delay600ns
retp
; ******************************************************************************
_E2GenStopCond
; Generate STOP condition
; INPUT: none
; OUTPUT: none
; ******************************************************************************
call E2SDAOutputLo
setb E2SCL_PIN
call E2Delay600ns
call E2SDAOutputHi
call E2Delay1300ns
retp
; ******************************************************************************
_E2Write8
; Write 8 bits out the I2C bus
; INPUT: w = Data to write
; OUTPUT: none
; ******************************************************************************
mov globTemp1, w ; Data buffer
mov globTemp2, #8 ; bit counter
:loop call E2Delay900ns
sb globTemp1.7
call E2SDAOutputLo
snb globTemp1.7
call E2SDAOutputHi
call E2Delay900ns
setb E2SCL_PIN
call E2Delay600ns
clrb E2SCL_PIN
rl globTemp1
decsz globTemp2
jmp :loop
retp
; ******************************************************************************
_E2Read8
; Read 8 bits from the I2C bus
; INPUT: none
; OUTPUT: w = Data read
; ******************************************************************************
call E2SDAInput
mov globTemp2, #8 ; bit counter
:loop call E2Delay900ns
sb E2SDA_PIN
clc
snb E2SDA_PIN
stc
rl globTemp1
setb E2SCL_PIN
call E2Delay600ns
clrb E2SCL_PIN
call E2Delay900ns
decsz globTemp2
jmp :loop
mov w, globTemp1
retp
; ******************************************************************************
_E2Read8Ack
; Read 8 bits from the I2C bus and send ACK
; INPUT: none
; OUTPUT: w = Data read
; ******************************************************************************
call E2Read8
mov globTemp1, w
call E2SendAck
mov w, globTemp1
retp
; ******************************************************************************
_E2Read8NoAckStop
; Read 8 bits from the I2C bus and send a no-ACK and stop-condition
; (terminates sequential read mode on EEPROM)
; INPUT: none
; OUTPUT: w = Data read
; ******************************************************************************
call E2Read8
mov globTemp1, w
call E2SendNotAck
call E2GenStopCond
mov w, globTemp1
retp
; ******************************************************************************
_E2RecvAck
; Receive ACK bit from I2C receiver
; INPUT: none
; OUTPUT: z: 1 = received ACK, 0 = Didn't receive ACK
; ******************************************************************************
call E2SDAInput
call E2Delay900ns
setb E2SCL_PIN
sb E2SDA_PIN
stz
snb E2SDA_PIN
clz
call E2Delay600ns
clrb E2SCL_PIN
call E2Delay900ns
retp
; ******************************************************************************
_E2SendAck
; Send ACK bit as acknowledge
; INPUT: none
; OUTPUT: z: 1 = received ACK, 0 = Didn't receive ACK
; ******************************************************************************
call E2SDAOutputLo
call E2Delay900ns
setb E2SCL_PIN
call E2Delay600ns
clrb E2SCL_PIN
call E2Delay900ns
retp
; ******************************************************************************
_E2SendNotAck
; Send ACK bit as not-acknowledge
; INPUT: none
; OUTPUT: z: 1 = received ACK, 0 = Didn't receive ACK
; ******************************************************************************
call E2SDAOutputHi
call E2Delay900ns
setb E2SCL_PIN
call E2Delay600ns
clrb E2SCL_PIN
call E2Delay900ns
retp
; ******************************************************************************
_E2SendRdCmd
; Tell I2C Device we wish to read from it for this transaction
; INPUT: none
; OUTPUT: none
; ******************************************************************************
call E2GenStartCond
mov w, #E2_CMD_RD
call E2Write8
call E2RecvAck
retp
; ******************************************************************************
_E2SendWrCmd
; Tell I2C Device we wish to write to it for this transaction
; INPUT: none
; OUTPUT: none
; ******************************************************************************
call E2GenStartCond
mov w, #E2_CMD_WR
call E2Write8
call E2RecvAck
retp
; ******************************************************************************
_E2SetAddr
; Set address pointer
; INPUT: {e2AddrMSB, e2AddrLSB} = address to set to
; OUTPUT: none
; ******************************************************************************
call E2SendWrCmd
_bank EEPROM_BANK
mov w, e2AddrMSB
call E2Write8
call E2RecvAck
mov w, e2AddrLSB
call E2Write8
call E2RecvAck
retp
; ******************************************************************************
_Bin8ToBCD
; Converts 8-bit binary number to unpacked BCD
; INPUT: w = binary number to convert
; fsr = pointer to MSD (lowest addr) of a 3-byte buffer
; OUTPUT: [fsr] = unpacked BCD
; ******************************************************************************
clr indf
inc fsr
clr indf
inc fsr ; LSD
mov indf, w
:loopHun mov w, #100
mov w, indf-w
jnc :loopTen
mov indf, w
dec fsr
dec fsr ; MSD
inc indf
inc fsr
inc fsr ; LSD
jmp :loopHun
:loopTen mov w, #10
mov w, indf-w
sc
jmp :exit
mov indf, w
dec fsr
inc indf
inc fsr
jmp :loopTen
:exit retp
; ******************************************************************************
_BCDToASCII
; Converts an unpacked BCD number to an ASCII character
; INPUT: w = unpacked BCD
; OUTPUT: w = ASCII character
; ******************************************************************************
mov globTemp1, w
mov w, #'0'
add w, globTemp1
retp
ENDIF
; ******************************************************************************
_TCPApp2Init
; Called repeatedly as long as TCP connection2 state is closed
; [TCP API Function]
; INPUT: none
; OUTPUT: none
; ******************************************************************************
; set up local port for tcp2 connection
IF HTTP
_bank TCB2_BANK
mov tcb2LocalPortLSB, #HTTP_PORT_LSB
mov tcb2LocalPortMSB, #HTTP_PORT_MSB
bank HTTP_BANK
clr httpParseState
clr httpURIHash
; indicate tcp2 connection
setb flags2.TCP_SOCK
jmp @TCPAppPassiveOpen
ENDIF
retp
; ******************************************************************************
_DeleteSocket1
; Deletes TCP socket1
; INPUT: none
; OUTPUT: sock1RemoteIP3-0
; ******************************************************************************
_bank TCPSOCKET_BANK
clr sock1RemoteIP3
clr sock1RemoteIP2
clr sock1RemoteIP1
clr sock1RemoteIP0
retp
; ******************************************************************************
_DeleteSocket2
; Deletes TCP socket1
; INPUT: none
; OUTPUT: sock2RemoteIP3-0
; ******************************************************************************
_bank TCPSOCKET_BANK
clr sock2RemoteIP3
clr sock2RemoteIP2
clr sock2RemoteIP1
clr sock2RemoteIP0
retp
; ***********
; *** END ***
; ***********
END
+
file: /Techref/scenix/lib/io/osi3/tcpip/dyndns-agm.htm, 80KB, , updated: 2002/6/30 21:55, local time: 2024/11/25 00:53,
owner: JMN-EFP-786,
3.140.185.194:LOG IN
|
©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://techref.massmind.org/techref/scenix/lib/io/osi3/tcpip/dyndns-agm.htm"> Convert DYNDNS to HTTP request Dynamic DNS. </A> |
Did you find what you needed? |
Welcome to massmind.org! |
Welcome to techref.massmind.org! |
.