Web 51 - Processing of Ethernet packets |
|
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:
- fast_begin - in web51 module
- fast - in user module(s), e.g. www8051
- fast_end - in web51 module
- slow_begin - in web51 module
- slow - in user module(s), e.g. www8051
- slow_end - in web51 module
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 WatchdogDuring the pass, dataflow control conditions (Xon/Xoff, CTS) are tested and transmission begins if necessary.
.if SERIAL lcall sstat ;scan RTS/CTS,... .endifRTL8019 is queried, packet header is read if found.
mov stateFlg,#0 ;clear rx_eth_bit, flagARP..flagTCP LCALL rcv_pkt jnb rx_eth_bit,NoRxEthIf 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 ProcessARPIf 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 ProcessArpPoiRqIf MAC address of "telnet" target is detected and connection is allowed, begin TCP negotiation by transmitting a SYN packet.
jnb flagSynRq,.+6 lcall ProcessSynRq .endifThe 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 no23chIf 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) .endifThe 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 loopRetransmit 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 no23Transmit 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
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.
Version IHL Type of Service Total Length Identification Flags Fragment Offset Time to Live Protocol Header 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,myiploopThen, 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 noneedgwAlthough 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 ;; } ;;} ;
| Web51 description | News | FAQ | ORDER FORM | DOWNLOAD | Links |
| (c)Copyright 2000 - 2002, HW server & Radek Benedikt
Web51@HW.cz, Web51.HW.cz |
|