226 lines
5.5 KiB
Forth
226 lines
5.5 KiB
Forth
( ARP: Address Resolution Protocol JCB 13:12 08/24/10)
|
|
module[ arp"
|
|
|
|
\ ARP uses a small cache of entries. Each entry has an age counter; new
|
|
\ entries have an age of 0, any entry with an age >N is old.
|
|
\
|
|
|
|
|
|
d# 12 constant arp-cache-entry-size
|
|
d# 5 constant arp-cache-entries
|
|
TARGET? [IF]
|
|
meta
|
|
arp-cache-entry-size arp-cache-entries * d# 64 max
|
|
target
|
|
constant arp-size
|
|
create arp-cache arp-size allot
|
|
meta
|
|
arp-cache-entries 1- arp-cache-entry-size * arp-cache +
|
|
target
|
|
constant arp-cache-last
|
|
[ELSE]
|
|
arp-cache-entry-size arp-cache-entries * d# 64 max constant arp-size
|
|
create arp-cache arp-size allot
|
|
arp-cache-entries 1- arp-cache-entry-size * arp-cache + constant arp-cache-last
|
|
[THEN]
|
|
|
|
: arp-foreach \ (func -- )
|
|
arp-cache-last 2>r
|
|
begin
|
|
2r@ swap \ ptr func
|
|
execute
|
|
r> dup arp-cache-entry-size - >r
|
|
arp-cache =
|
|
until
|
|
2r> 2drop
|
|
;
|
|
|
|
build-debug? [IF]
|
|
: arp-.
|
|
dup @ hex4 space \ age
|
|
dup 2+ dup @ swap d# 2 + dup @ swap d# 2 + @ ethaddr-pretty space
|
|
d# 8 + 2@ ip-pretty
|
|
cr
|
|
;
|
|
|
|
: arp-dump
|
|
['] arp-. arp-foreach
|
|
;
|
|
[THEN]
|
|
|
|
: arp-del h# ff swap ! ;
|
|
: arp-reset ['] arp-del arp-foreach ;
|
|
: used? @ h# ff <> ;
|
|
: arp-age-1 dup used? d# 1 and swap +! ;
|
|
: arp-age ['] arp-age-1 arp-foreach ;
|
|
: arp-cmp ( ptr0 ptr1 -- ptr) over @ over @ > ?: ;
|
|
: arp-oldest \ return the address of the oldest ARP entry
|
|
arp-cache ['] arp-cmp arp-foreach ;
|
|
|
|
\ ARP offsets
|
|
\ d# 28 sender ethaddr
|
|
\ d# 34 sender ip
|
|
\ d# 38 target ethaddr
|
|
\ d# 44 target ip
|
|
|
|
d# 20 constant OFFSET_ARP_OPCODE
|
|
d# 22 constant OFFSET_ARP_SRC_ETH
|
|
d# 28 constant OFFSET_ARP_SRC_IP
|
|
d# 32 constant OFFSET_ARP_DST_ETH
|
|
d# 38 constant OFFSET_ARP_DST_IP
|
|
|
|
: arp-is-response
|
|
OFFSET_ETH_TYPE packet@ h# 806 =
|
|
OFFSET_ARP_OPCODE packet@ d# 2 =
|
|
and
|
|
;
|
|
|
|
\ write the current arp response into the cache, replacing the oldest entry
|
|
: !-- \ ( val ptr -- ptr-2 )
|
|
tuck \ ptr val ptr
|
|
!
|
|
2-
|
|
;
|
|
|
|
\ Current packet is an ARP response; write it to the given slot in the ARP cache, ageing all others
|
|
|
|
: arp-cache-write \ ( ptr -- )
|
|
arp-age \ because this new entry will have age d# 0
|
|
d# 0 over ! \ age d# 0
|
|
>r
|
|
|
|
d# 3 OFFSET_ARP_SRC_ETH mac-inoffset mac@n
|
|
r@ d# 6 + !-- !-- !-- drop
|
|
d# 2 OFFSET_ARP_SRC_IP mac-inoffset mac@n
|
|
r> d# 8 + 2!
|
|
|
|
;
|
|
|
|
\ Comparison of IP
|
|
: arp-cmpip \ (ip01 ip23 ptr/0 ptr -- ip01 ip23 ptr)
|
|
dup used? if
|
|
dup d# 8 + 2@ d# 2 2pick d<> ?:
|
|
else
|
|
drop
|
|
then
|
|
;
|
|
|
|
: arp-cache-find ( ip01 ip23 -- ip01 ip23 ptr )
|
|
\ Find an IP. Zero if the IP was not found in the cache, ptr to entry otherwise
|
|
d# 0 ['] arp-cmpip arp-foreach ;
|
|
|
|
|
|
: arp-issue-whohas \ (ip01 ip23 -- ptr)
|
|
mac-pkt-begin
|
|
ethaddr-broadcast mac-pkt-3,
|
|
net-my-mac mac-pkt-3,
|
|
h# 806 \ frame type
|
|
d# 1 \ hard type
|
|
h# 800 \ prot type
|
|
mac-pkt-3,
|
|
h# 0604 \ hard size, prot size
|
|
d# 1 \ op (1=request)
|
|
mac-pkt-2,
|
|
net-my-mac mac-pkt-3,
|
|
net-my-ip mac-pkt-2,
|
|
ethaddr-broadcast mac-pkt-3,
|
|
mac-pkt-2,
|
|
mac-pkt-complete drop
|
|
mac-send
|
|
;
|
|
|
|
\ Look up ethaddr for given IP.
|
|
\ If found, return pointer to the 6-byte ethaddr
|
|
\ If not found, issue an ARP request and return d# 0.
|
|
|
|
: arp-lookup \ ( ip01 ip23 -- ptr)
|
|
2dup
|
|
ip-router 2@ dxor ip-subnetmask 2@ dand
|
|
d0<>
|
|
if
|
|
2drop
|
|
ip-router 2@
|
|
then
|
|
arp-cache-find \ ip01 ip23 ptr
|
|
dup 0= if
|
|
-rot \ d# 0 ip01 ip23
|
|
arp-issue-whohas \ d# 0
|
|
else
|
|
nip nip 2+ \ ptr
|
|
then
|
|
;
|
|
|
|
\ If the current packet is an ARP request for our IP, answer it
|
|
: arp-responder
|
|
\ is destination ff:ff:ff:ff:ff:ff or my mac
|
|
d# 3 OFFSET_ETH_DST mac-inoffset mac@n
|
|
and and invert 0=
|
|
|
|
net-my-mac \ a b c
|
|
d# 2 OFFSET_ETH_DST 2+ mac-inoffset mac@n
|
|
d= swap \ F a
|
|
OFFSET_ETH_DST packet@ = and
|
|
|
|
or
|
|
OFFSET_ETH_TYPE packet@ h# 806 = and
|
|
\ is target IP mine?
|
|
d# 2 OFFSET_ARP_DST_IP mac-inoffset mac@n net-my-ip d= and
|
|
if
|
|
mac-pkt-begin
|
|
|
|
d# 3 OFFSET_ARP_SRC_ETH mac-pkt-src
|
|
net-my-mac mac-pkt-3,
|
|
h# 806 \ frame type
|
|
d# 1 \ hard type
|
|
h# 800 \ prot type
|
|
mac-pkt-3,
|
|
h# 0604 \ hard size, prot size
|
|
d# 2 \ op (2=reply)
|
|
mac-pkt-2,
|
|
net-my-mac mac-pkt-3,
|
|
net-my-ip mac-pkt-2,
|
|
d# 3 OFFSET_ARP_SRC_ETH mac-pkt-src
|
|
d# 2 OFFSET_ARP_SRC_IP mac-pkt-src
|
|
|
|
mac-pkt-complete drop
|
|
mac-send
|
|
then
|
|
;
|
|
|
|
: arp-announce
|
|
mac-pkt-begin
|
|
|
|
ethaddr-broadcast mac-pkt-3,
|
|
net-my-mac mac-pkt-3,
|
|
h# 806 \ frame type
|
|
d# 1 \ hard type
|
|
h# 800 \ prot type
|
|
mac-pkt-3,
|
|
h# 0604 \ hard size, prot size
|
|
d# 2 \ op (2=reply)
|
|
mac-pkt-2,
|
|
net-my-mac mac-pkt-3,
|
|
net-my-ip mac-pkt-2,
|
|
ethaddr-broadcast mac-pkt-3,
|
|
net-my-ip mac-pkt-2,
|
|
|
|
mac-pkt-complete drop
|
|
mac-send
|
|
|
|
;
|
|
|
|
: arp-handler
|
|
arp-responder
|
|
arp-is-response
|
|
if
|
|
d# 2 OFFSET_ARP_SRC_IP mac-inoffset mac@n
|
|
arp-cache-find nip nip
|
|
dup 0= if
|
|
drop arp-oldest
|
|
then
|
|
arp-cache-write
|
|
then
|
|
;
|
|
|
|
]module
|