Web 51 - Processing of Ethernet packets

Serial line  software.html  Web 51 - WEB51 TCP sockets

Main loop

Main loop of Web51 server consists of several more or less mandatory parts grouped together in the web51.asm library module, and user portions - in our examples grouped in the www8051.asm module.

Composition of individual portions into the final main loop is ensured by linker. Main loop code is divided into several blocks that are linked one after another according to segment names. Individual sections are linked in this order:

Following main loop example demonstrates an application that operates a www server and talks to the serial line.

Entire main loop begins with the fast_begin section of web51 module.

At the beginning of each pass through the loop, 89S8252's watchdog is reset:

        .section fast_begin, #alloc
;#########################################################
;  Main Loop
;#########################################################
;
mainloop:
        mov     WMCON,#RESTARTWATCHDOG  ;restart Watchdog

During the pass, dataflow control conditions (Xon/Xoff, CTS) are tested and transmission begins if necessary.

.if SERIAL
        lcall   sstat                   ;scan RTS/CTS,...
.endif

RTL8019 is queried, packet header is read if found.

        mov     stateFlg,#0             ;clear rx_eth_bit, flagARP..flagTCP
        LCALL   rcv_pkt
        jnb     rx_eth_bit,NoRxEth

If a packet has been received, its contents are checked for known types. A known packet (ICMP / TCP / UDP / ARP) is processed.

        jnb     B2B(stateFlg, flagICMP),.+6   ;jnb     flagICMP,$+6     for Keil/Intel compilers
        lcall   ProcessICMP
        jnb     B2B(stateFlg, flagTCP),.+6
        lcall   ProcessTCP
        jnb     B2B(stateFlg, flagUDP),.+6
        lcall   ProcessUDP
        jnb     B2B(stateFlg, flagARP),.+6
        lcall   ProcessARP

If no packet was received, or an unknown packet was received, test whether 1 milisecond has passed.

NoRxEth:jnb     bit1ms,mainloop
        clr     bit1ms
;~1 ms loop
fastloop:

Send requests for gateway or "telnet" target MAC address, if needed.

        jnb     flagArpGwRq,.+6
        lcall   ProcessArpGwRq
.if ACTIVESTACK
        jnb     flagArpPoiRq,.+6
        lcall   ProcessArpPoiRq

If MAC address of "telnet" target is detected and connection is allowed, begin TCP negotiation by transmitting a SYN packet.

        jnb     flagSynRq,.+6
        lcall   ProcessSynRq
.endif

The main program now passes through individual fast sections of user module(s) (e.g. web8051 in our examples).

        .section fast, #alloc
;*************************************************************

If connection to a "telnet" target is closed but enabled, begin negotiation.

        jnb     rxint, no23ch   ;if Not Data to send, don't make connection
        jnb     flagIPactive,no23ch ;if flash_ip_point = 0.0.0.0,
                                ;don't make connection
        mov     r7,#LASTSTACK1
        lcall   changeStack
        mov     a,tcpState
        jnz     est23ch         ;if Connect Established, don't make new
        lcall   ConnectTCP1
        sjmp    no23ch

If connection to a "telnet" target is open, check the buffer. If it contains lots of unsent data, transmit them.

est23ch:
        jb      flag1WaitForAck,no23ch
                        ;if All previous send data is Acked
                        ;and sizeof(unsend data in Rx buffer) >= MAXCHAR/2 char
                        ;then send output packet
        mov     a,r1point
        cjne    a,#rser+(MAXCHAR/2),.+3
        jc      no23ch  ;jump if sizeof(unsend data in Rx buffer) < MAXCHAR/2
        lcall   OutTCP1 ;send all queued data
no23ch:

After passing through all individual fast sections of user modules, program continues with fast_end section of web51 module.

        .section fast_end, #alloc
;*************************************************************

Check whether 50 ms have passed.

        djnz    slowtimer,main
        mov     slowtimer,#slowtiming
;~50 ms loop
slowloop:

Continue to slow_begin section of web51 module.

        .section slow_begin, #alloc
;*************************************************************
        clr     B2B(tcpState, stateSyn)
.if DUALSTACK
        clr     B2B(tcpStateXX, stateSyn)
        clr     B2B(tcpStateXX+1, stateSyn)
.endif

The main program now asses through individual slow sections of user module(s) (e.g. web8051 in our examples).

	.section slow, #alloc
;*************************************************************

First, check connection timers of TCP/serial channel ("telnet")

;; telnet timer
;~50 ms loop
        mov     a,Retry1
        jz      no23timer
        dec     Timeout1
        mov     a,Timeout1
        jnz     no23timer
;~200 ms loop

Retransmit un-acknowledged data, or close connection after specified number of unsuccessful retries.

        mov     Timeout1,#ethtiming
        dec     Retry1
        mov     a,Retry1
        jz      kill23
        lcall   RetryTCP1
        ajmp    no23
kill23: lcall   CloseTCP1
        ajmp    no23

Transmit any unsent data in the buffer.

no23timer:
        mov     r7,#LASTSTACK1
        lcall   changeStack
        jnb     B2B(tcpState, stateEstablished),no23
        jbc     flag1WaitForAck,no23
        jnb     rxint,no23
        lcall   OutTCP1         ;send all queued
                                ;data, don't wait for limit MAXCHAR/2
no23:

Similarly process http connection, close after timeout.

;; http timer
;~50 ms loop
        mov     a,Retry2
        jz      no80
        dec     Timeout2
        mov     a,Timeout2
        jnz     no80
;~200 ms loop
        mov     Timeout2,#ethtiming
        dec     Retry2
        mov     a,Retry2
        jnz     no80
        lcall   CloseTCP2
no80:

After performing all individual slow sections of user modules, continue with slow_end section of web51 module.

        .section slow_end, #alloc
;*************************************************************
        ajmp    main

Processing of received Ethernet packets

Normally, processing of a received Ethernet packet is concentrated into the web51 module.

After a packet is received, it is scanned for several "magic" numbers that specify packet type. First, it is searched for identification according to RFC894 (A Standard for the Transmission of IP Datagrams over Ethernet Networks) specifying that it is indeed an IP packet. Second, it is searched for ARP packet identification according to RFC826 (An Ethernet Address Resolution Protocol).

        .section cpu_rom, #alloc
;
;**************************************************************************
ProcessEthPacket:
;;if (rx_eth_pkt.pktType == 0x0800) goto IPPacket; //IP
;;else if (rx_eth_pkt.pktType == 0x0806) goto ArpPacket; //ARP
;;else goto UnknownEthType;
        mov     a,eth_pkt_hdr_type
        xrl     a,#0x08         ;high ARP and IP ID
        jnz     UnknownEthType
        mov     a,eth_pkt_hdr_type+1
        jz      IPPacket
        xrl     a,#0x06         ;low ARP ID
        jz      ArpPacket
UnknownEthType:
        ret                     ;Unknown ID of Ethernet packet
;**************************************************************************
;Type of ethernet packet = 0806h ARP
ArpPacket:
        setb    B2B(stateFlg, flagARP)
        ret
From the received IP packet, see RFC791 (Internet Protocol), a block of 12 bytes is copied into a temporary field in processor RAM.
VersionIHLType of ServiceTotal Length
IdentificationFlagsFragment Offset
Time to LiveProtocolHeader Checksum
Source Address
Destination Address
 

Destination Address is compared to IP of Web 51. Packets destined to other IPs are ignored.

;**************************************************************************
;Type of ethernet packet = 0800h IP
NoMyIP:
        mov     WMCON,#WATCHDOG         ;disable EEPROM & DPTR'
        ret                             ;IP with IP_DSTADDR != flash_my_ip
IPPacket:
;;if (rx_eth_pkt.pkt.ip.ipheader.DstAddr == flash_my_ip) {
        mov     R7,#dwordtemp           ;buffer_addr = dwordtemp & iftemp
        mov     R5,#IP_TTL              ;source_packet_offset
        mov     R3,#12                  ;length
        lcall   short_pr2s      ;read IP_TTL & IP_PROTO & IP_CKSUM
                                ;IP_SRCADDR & IP_DSTADDR to temp var
        mov     dptr,#flash_my_ip
        mov     r0, #dwordtemp+(IP_DSTADDR-IP_TTL)
        mov     r1, #IP_ADDR_LEN
        mov     WMCON,#WATCHDOG OR EEMEN;enable EEPROM
myiploop:movx   a,@dptr
        xrl     a,@r0
        jnz     NoMyIP
        inc     dptr
        inc     r0
        djnz    r1,myiploop

Then, Source Address is checked to determine whether the source is on the same network as Web 51, or if we need to communicate through a gateway.

Starting with formulas
MY_NETWORK = ( my_ip AND network_mask )
SRC_NETWORK = ( src_ip AND network_mask )
and test expression MY_NETWORK == SRC_NETWORK
with a possible machine representation ( MY_NETWORK XOR SRC_NETWORK ) == 0
after substitutions gaining (( my_ip XOR src_ip ) AND network_mask ) == 0 which is the actual test used in Web 51.

;;if (((rx_eth_pkt.pkt.ip.ipheader.SrcAddr & flash_my_ip) & flash_ip_mask) != 0) {
        mov     dptr,#flash_my_ip
        mov     r0, #dwordtemp+(IP_SRCADDR-IP_TTL)
        mov     r1, #IP_ADDR_LEN
gwloop1:movx    a,@dptr
        xrl     a,@r0
        mov     @r0,a
        inc     dptr
        inc     r0
        djnz    r1,gwloop1
        mov     dptr,#flash_ip_mask
        mov     r0, #dwordtemp+(IP_SRCADDR-IP_TTL)
        mov     r1, #IP_ADDR_LEN
gwloop2:movx    a,@dptr
        anl     a,@r0
        jnz     gwloopbreak
        inc     dptr
        inc     r0
        djnz    r1,gwloop2
gwloopbreak:
        mov     WMCON,#WATCHDOG         ;disable EEPROM & DPTR'
        jz      noneedgw

Although in 99% of cases a request from another network comes through gateway and therefore has a correct source MAC address, it cannot be relied upon. Therefore, in a packet received from another network, source MAC is overwritten by gateway MAC address. This MAC is then used in eventual reply as the destination address. However, MAC can be changed only if it is known. So, it is necessary to test whether gateway MAC has been determined by an ARP request. If not, the appropriate flag (ARP request needed) is set and the packet is thrown away as non-processable.

;;  if(mac_gateway == 0) {
        mov     r0, #mac_gateway
        mov     r1, #ETHER_ADDR_LEN
gwloop3:mov     a,@r0
        jnz     noneedarpgw
        inc     r0
        djnz    r1,gwloop3
;;    MakeArpGwRq(); return;
        setb    flagArpGwRq             ;Arp Gateway Request
        ret
;;  } else {
;;    EthRcvHdr.pktSrc = mac_gateway;
noneedarpgw:
        mov     r0, #mac_gateway
        mov     r1, #eth_pkt_hdr_src
        mov     r2, #ETHER_ADDR_LEN
gwloop4:mov     a,@r0
        mov     @r1,a
        inc     r0
        inc     r1
        djnz    r2,gwloop4
;;  }
;;}

Packet with verified IP addresses is scanned for protocol numbers according to RFC1700 (Assigned Numbers). If a protocol supported by Web51 is found, its flag is set to tell e.g. the main loop that a processable packet has been received.

noneedgw:
;;  switch (rx_eth_pkt.pkt.ip.Proto) {
;;    case IPT_ICMP: goto protoICMP;
        mov     R0,#dwordtemp+(IP_PROTO-IP_TTL)
        mov     a,@R0
        xrl     a,#IPT_ICMP             ;proto ICMP
        jz      protoICMP
;;    case IPT_TCP:  goto protoTCP;
        xrl     a,#IPT_ICMP xor IPT_TCP ;proto TCP
        jz      protoTCP
;;    case IPT_UDP:  goto protoUDP;
        xrl     a,#IPT_TCP xor IPT_UDP  ;proto UDP
        jz      protoUDP
        ret
protoICMP:
        setb    B2B(stateFlg, flagICMP)
        ret
protoTCP:
        setb    B2B(stateFlg, flagTCP)
        ret
protoUDP:
        setb    B2B(stateFlg, flagUDP)
        ret
;;  }
;;}
;




Sponzored by LPhard Ltd. Graphics by GIMP Created by EasyPad

(c)Copyright 2000 - 2002, HW server & Radek Benedikt
Web51@HW.cz, Web51.HW.cz
Serial line  Obsah  Web 51 - WEB51 TCP sockets