mirror of
https://github.com/bobbimanners/emailler.git
synced 2024-11-19 12:30:51 +00:00
1a5bd8c7e5
In general I consider the approach of a netmask length a typical case of over-optimzation - incl. the typical downside of an "unnecessary" bug. However as the optimization is already present I opted to not remove it but rather fix the bug: So far the gateway was in usual environments only used if the target IP address differed already in the first byte from the local net IP addresses. Now the gateway is used correctly - even for i.e. the address 192.168.1.1 from the local net 192.168.0.x
424 lines
9.8 KiB
ArmAsm
424 lines
9.8 KiB
ArmAsm
; ARP address resolution
|
|
|
|
.include "zeropage.inc"
|
|
.include "../inc/common.i"
|
|
|
|
.export arp_init
|
|
.export arp_lookup
|
|
.export arp_process
|
|
.export arp_add
|
|
.export arp_calculate_gateway_mask
|
|
.export arp_ip
|
|
.export arp_mac
|
|
.export arp_cache
|
|
.exportzp ac_size
|
|
|
|
.import eth_inp
|
|
.import eth_inp_len
|
|
.import eth_outp
|
|
.import eth_outp_len
|
|
.import eth_tx
|
|
.import eth_set_broadcast_dest
|
|
.import eth_set_my_mac_src
|
|
.import eth_set_proto
|
|
.importzp eth_proto_arp
|
|
|
|
.import cfg_mac
|
|
.import cfg_ip
|
|
.import cfg_netmask
|
|
.import cfg_gateway
|
|
|
|
.import timer_read
|
|
.import timer_timeout
|
|
|
|
ap = ptr1
|
|
|
|
ARP_TIMEOUT_MS = 100
|
|
|
|
|
|
.bss
|
|
|
|
; arp state machine
|
|
arp_idle = 1 ; idling
|
|
arp_wait = 2 ; waiting for reply
|
|
arp_state: .res 1 ; current activity
|
|
|
|
; arguments for lookup and add
|
|
arp: ; ptr to mac/ip pair
|
|
arp_mac: .res 6 ; result is delivered here when arp_lookup returns with carry flag clear
|
|
arp_ip: .res 4 ; set arp_ip before calling arp_lookup
|
|
|
|
; arp cache
|
|
ac_size = 8 ; lookup cache
|
|
ac_ip = 6 ; offset for ip
|
|
ac_mac = 0 ; offset for mac
|
|
arp_cache: .res (6+4) * ac_size ; cache of IP addresses and corresponding MAC addresses
|
|
|
|
; offsets for arp packet generation
|
|
ap_hw = 14 ; hw type (eth = 0001)
|
|
ap_proto = 16 ; protocol (ip = 0800)
|
|
ap_hwlen = 18 ; hw addr len (eth = 06)
|
|
ap_protolen = 19 ; proto addr len (ip = 04)
|
|
ap_op = 20 ; request = 0001, reply = 0002
|
|
ap_shw = 22 ; sender hw addr
|
|
ap_sp = 28 ; sender proto addr
|
|
ap_thw = 32 ; target hw addr
|
|
ap_tp = 38 ; target proto addr
|
|
ap_packlen = 42 ; total length of packet
|
|
|
|
; gateway handling
|
|
gw_mask: .res 4 ; inverted netmask
|
|
gw_test: .res 4 ; gateway ip or'd with inverted netmask
|
|
gw_last: .res 1 ; netmask length - 1
|
|
|
|
; timeout
|
|
arptimeout: .res 2 ; time when we will have timed out
|
|
|
|
|
|
.code
|
|
|
|
; initialize arp (including clearing the arp cache)
|
|
; inputs: none
|
|
; outputs: none
|
|
arp_init:
|
|
lda #0
|
|
|
|
ldx #(6+4)*ac_size - 1 ; clear cache
|
|
: sta arp_cache,x
|
|
dex
|
|
bpl :-
|
|
|
|
arp_calculate_gateway_mask:
|
|
lda #$ff ; counter for netmask length - 1
|
|
sta gw_last
|
|
|
|
ldx #3
|
|
@gw:
|
|
lda cfg_netmask,x
|
|
eor #$ff
|
|
cmp #$ff
|
|
beq :+
|
|
inc gw_last
|
|
: sta gw_mask,x
|
|
ora cfg_gateway,x
|
|
sta gw_test,x
|
|
dex
|
|
bpl @gw
|
|
|
|
lda #arp_idle ; start out idle
|
|
sta arp_state
|
|
rts
|
|
|
|
; lookup the mac address for an ip
|
|
; inputs: arp_ip should be set to ip address to be resolved
|
|
; outputs:
|
|
; if carry flag is clear, then arp_mac will be set to correct mac address
|
|
; if carry flag is set, then the correct mac address could not be found in
|
|
; the arp cache, so an arp request was sent. so the caller should wait a while
|
|
; (to allow time for an arp response message to arrive) and then call arp_lookup again.
|
|
arp_lookup:
|
|
lda arp_ip ; check for broadcast IP (255.255.255.255)
|
|
and arp_ip + 1
|
|
and arp_ip + 2
|
|
and arp_ip + 3
|
|
cmp #$ff
|
|
bne @notbroadcast
|
|
ldx #6 ; copy ff:ff:ff:ff:ff:ff to ap_mac
|
|
: sta arp_mac,x
|
|
dex
|
|
bpl :-
|
|
clc
|
|
rts
|
|
|
|
@notbroadcast:
|
|
ldx gw_last ; check if address is on our subnet
|
|
: lda arp_ip,x
|
|
ora gw_mask,x
|
|
cmp gw_test,x
|
|
bne @notlocal
|
|
dex
|
|
bpl :-
|
|
bmi @local
|
|
|
|
@notlocal:
|
|
ldx #3 ; copy gateway's ip address
|
|
: lda cfg_gateway,x
|
|
sta arp_ip,x
|
|
dex
|
|
bpl :-
|
|
|
|
@local:
|
|
jsr findip
|
|
bcs @cachemiss
|
|
|
|
ldy #ac_ip - 1 ; copy mac
|
|
: lda (ap),y
|
|
sta arp,y
|
|
dey
|
|
bpl :-
|
|
rts
|
|
|
|
@cachemiss:
|
|
lda arp_state ; are we already waiting for a reply?
|
|
cmp #arp_idle
|
|
beq @sendrequest ; yes, send request
|
|
|
|
ldax arptimeout ; check if we've timed out
|
|
jsr timer_timeout
|
|
bcs @notimeout ; no, don't send
|
|
|
|
@sendrequest: ; send out arp request
|
|
jsr eth_set_broadcast_dest
|
|
jsr eth_set_my_mac_src
|
|
|
|
jsr makearppacket ; add arp, eth, ip, hwlen, protolen
|
|
|
|
lda #0 ; set opcode (request = 0001)
|
|
sta eth_outp + ap_op
|
|
lda #1
|
|
sta eth_outp + ap_op + 1
|
|
|
|
ldx #5
|
|
: lda cfg_mac,x ; set source mac addr
|
|
sta eth_outp + ap_shw,x
|
|
lda #0 ; set target mac addr
|
|
sta eth_outp + ap_thw,x
|
|
dex
|
|
bpl :-
|
|
|
|
ldx #3
|
|
: lda cfg_ip,x ; set source ip addr
|
|
sta eth_outp + ap_sp,x
|
|
lda arp_ip,x ; set target ip addr
|
|
sta eth_outp + ap_tp,x
|
|
dex
|
|
bpl :-
|
|
|
|
lda #<ap_packlen ; set packet length
|
|
sta eth_outp_len
|
|
lda #>ap_packlen
|
|
sta eth_outp_len + 1
|
|
|
|
jsr eth_tx ; send packet
|
|
|
|
lda #arp_wait ; waiting for reply
|
|
sta arp_state
|
|
|
|
jsr timer_read ; read current timer value
|
|
clc
|
|
adc #<ARP_TIMEOUT_MS ; set timeout to now + ARP_TIMEOUT_MS
|
|
sta arptimeout
|
|
txa
|
|
adc #>ARP_TIMEOUT_MS
|
|
sta arptimeout + 1
|
|
|
|
@notimeout:
|
|
sec ; set carry to indicate that
|
|
rts ; no result is availble
|
|
|
|
; find arp_ip in the cache
|
|
; clc returns pointer to entry in (ap)
|
|
findip:
|
|
ldax #arp_cache
|
|
stax ap
|
|
ldx #ac_size
|
|
@compare: ; compare cache entry
|
|
ldy #ac_ip
|
|
lda (ap),y
|
|
beq @notfound
|
|
: lda (ap),y
|
|
cmp arp,y
|
|
bne @next
|
|
iny
|
|
cpy #ac_ip + 4
|
|
bne :-
|
|
clc ; return
|
|
rts
|
|
|
|
@next: ; next entry
|
|
lda ap
|
|
clc
|
|
adc #10
|
|
sta ap
|
|
bcc :+
|
|
inc ap + 1
|
|
: dex
|
|
bne @compare
|
|
|
|
@notfound:
|
|
sec
|
|
rts
|
|
|
|
; handle incoming arp packets
|
|
; inputs: eth_inp should contain an arp packet
|
|
; outputs:
|
|
; carry flag is set if there was an error processing the arp packet, clear otherwise
|
|
; the arp_cache will be updated with the mac & ip address (whether the inbound
|
|
; message was a request or a response). if the incoming packet was an arp
|
|
; request for this machine, then an arp response will be created (overwriting
|
|
; eth_outp) and sent out
|
|
arp_process:
|
|
lda eth_inp + ap_op ; should be 0
|
|
bne @badpacket
|
|
lda eth_inp + ap_op + 1 ; check opcode
|
|
cmp #1 ; request?
|
|
beq @request
|
|
cmp #2 ; reply?
|
|
beq @reply
|
|
|
|
@badpacket:
|
|
sec
|
|
rts
|
|
|
|
@request:
|
|
ldx #3
|
|
: lda eth_inp + ap_tp,x ; check if they're asking for
|
|
cmp cfg_ip,x ; my address
|
|
bne @done
|
|
dex
|
|
bpl :-
|
|
|
|
ldax #eth_inp + ap_shw
|
|
jsr ac_add_source ; add them to arp cache
|
|
|
|
ldx #5 ; send reply
|
|
: lda eth_inp + ap_shw,x
|
|
sta eth_outp,x ; set sender packet dest
|
|
sta eth_outp + ap_thw,x ; and as target
|
|
lda cfg_mac,x ; me as source
|
|
sta eth_outp + ap_shw,x
|
|
dex
|
|
bpl :-
|
|
|
|
jsr eth_set_my_mac_src ; me as packet source
|
|
|
|
jsr makearppacket ; add arp, eth, ip, hwlen, protolen
|
|
|
|
lda #0 ; set opcode (reply = 0002)
|
|
sta eth_outp + ap_op
|
|
lda #2
|
|
sta eth_outp + ap_op + 1
|
|
|
|
ldx #3
|
|
: lda eth_inp + ap_sp,x ; sender as target addr
|
|
sta eth_outp + ap_tp,x
|
|
lda cfg_ip,x ; my ip as source addr
|
|
sta eth_outp + ap_sp,x
|
|
dex
|
|
bpl :-
|
|
|
|
lda #<ap_packlen ; set packet length
|
|
sta eth_outp_len
|
|
lda #>ap_packlen
|
|
sta eth_outp_len + 1
|
|
|
|
jsr eth_tx ; send packet
|
|
|
|
@done:
|
|
clc
|
|
rts
|
|
|
|
@reply:
|
|
lda arp_state
|
|
cmp #arp_wait ; are we waiting for a reply?
|
|
bne @badpacket
|
|
|
|
ldax #eth_inp + ap_shw
|
|
jsr ac_add_source ; add to cache
|
|
|
|
lda #arp_idle
|
|
sta arp_state
|
|
rts
|
|
|
|
; add arp_mac and arp_ip to the cache
|
|
; inputs:
|
|
; arp_ip is ip address to add to cache
|
|
; arp_mac is corresponding mac address of specified ip
|
|
; outputs:
|
|
; arp_cache is updated
|
|
arp_add:
|
|
jsr findip ; check if ip is already in cache
|
|
bcs @add
|
|
|
|
ldy #9 ; update old entry
|
|
: lda arp,y ; move to top as well?
|
|
sta (ap),y
|
|
dey
|
|
bpl :-
|
|
rts
|
|
|
|
@add:
|
|
ldax #arp ; add
|
|
|
|
; add source to cache
|
|
ac_add_source:
|
|
stax ap
|
|
|
|
ldx #9 ; make space in the arp cache
|
|
: lda arp_cache + 60,x
|
|
sta arp_cache + 70,x
|
|
lda arp_cache + 50,x
|
|
sta arp_cache + 60,x
|
|
lda arp_cache + 40,x
|
|
sta arp_cache + 50,x
|
|
lda arp_cache + 30,x
|
|
sta arp_cache + 40,x
|
|
lda arp_cache + 20,x
|
|
sta arp_cache + 30,x
|
|
lda arp_cache + 10,x
|
|
sta arp_cache + 20,x
|
|
lda arp_cache,x
|
|
sta arp_cache + 10,x
|
|
|
|
dex
|
|
bpl :-
|
|
|
|
ldy #9
|
|
: lda (ap),y ; copy source
|
|
sta arp_cache,y
|
|
dey
|
|
bpl :-
|
|
rts
|
|
|
|
; adds proto = arp, hw = eth, and proto = ip to outgoing packet
|
|
makearppacket:
|
|
lda #eth_proto_arp
|
|
jsr eth_set_proto
|
|
|
|
lda #0 ; set hw type (eth = 0001)
|
|
sta eth_outp + ap_hw
|
|
lda #1
|
|
sta eth_outp + ap_hw + 1
|
|
|
|
lda #8 ; set protcol (ip = 0800)
|
|
sta eth_outp + ap_proto
|
|
lda #0
|
|
sta eth_outp + ap_proto + 1
|
|
|
|
lda #6 ; set hw addr len (eth = 06)
|
|
sta eth_outp + ap_hwlen
|
|
lda #4 ; set proto addr len (eth = 04)
|
|
sta eth_outp + ap_protolen
|
|
rts
|
|
|
|
|
|
|
|
; -- LICENSE FOR arp.s --
|
|
; The contents of this file are subject to the Mozilla Public License
|
|
; Version 1.1 (the "License"); you may not use this file except in
|
|
; compliance with the License. You may obtain a copy of the License at
|
|
; http://www.mozilla.org/MPL/
|
|
;
|
|
; Software distributed under the License is distributed on an "AS IS"
|
|
; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
|
|
; License for the specific language governing rights and limitations
|
|
; under the License.
|
|
;
|
|
; The Original Code is ip65.
|
|
;
|
|
; The Initial Developer of the Original Code is Per Olofsson,
|
|
; MagerValp@gmail.com.
|
|
; Portions created by the Initial Developer are Copyright (C) 2009
|
|
; Per Olofsson. All Rights Reserved.
|
|
; -- LICENSE END --
|