mirror of
https://github.com/bobbimanners/emailler.git
synced 2024-11-18 21:07:03 +00:00
457 lines
11 KiB
ArmAsm
457 lines
11 KiB
ArmAsm
; ICMP implementation
|
|
|
|
.include "../inc/common.inc"
|
|
.include "../inc/error.inc"
|
|
|
|
.export icmp_init
|
|
.export icmp_process
|
|
.export icmp_add_listener
|
|
.export icmp_remove_listener
|
|
|
|
.export icmp_callback
|
|
|
|
.export icmp_inp
|
|
.export icmp_outp
|
|
.exportzp icmp_type
|
|
.exportzp icmp_code
|
|
.exportzp icmp_cksum
|
|
.exportzp icmp_data
|
|
|
|
.ifdef TCP
|
|
.export icmp_echo_ip
|
|
.export icmp_send_echo
|
|
.export icmp_ping
|
|
.endif
|
|
|
|
.import ip65_process
|
|
.import ip65_error
|
|
|
|
.import ip_calc_cksum
|
|
.import ip_inp
|
|
.import ip_outp
|
|
.import ip_broadcast
|
|
.import ip_send
|
|
.import ip_create_packet
|
|
.importzp ip_proto
|
|
.importzp ip_proto_icmp
|
|
|
|
.importzp ip_cksum_ptr
|
|
.importzp ip_header_cksum
|
|
.importzp ip_src
|
|
.importzp ip_dest
|
|
.importzp ip_data
|
|
.importzp ip_len
|
|
|
|
.import eth_tx
|
|
.import eth_inp
|
|
.import eth_inp_len
|
|
.import eth_outp
|
|
.import eth_outp_len
|
|
.import timer_read
|
|
.import timer_timeout
|
|
|
|
|
|
.data
|
|
|
|
icmp_cbtmp: jmp $0000 ; temporary vector - address filled in later
|
|
|
|
|
|
.bss
|
|
|
|
; argument for icmp_add_listener
|
|
icmp_callback: .res 2
|
|
|
|
; icmp callbacks
|
|
icmp_cbmax = 2
|
|
icmp_cbveclo: .res icmp_cbmax ; table of listener vectors (lsb)
|
|
icmp_cbvechi: .res icmp_cbmax ; table of listener vectors (msb)
|
|
icmp_cbtype: .res icmp_cbmax ; table of listener types
|
|
icmp_cbcount: .res 1 ; number of active listeners
|
|
|
|
; icmp packet offsets
|
|
icmp_inp = ip_inp + ip_data ; pointer to inbound icmp packet
|
|
icmp_outp = ip_outp + ip_data ; pointer to outbound icmp packet
|
|
icmp_type = 0 ; offset of 'type' field in icmp packet
|
|
icmp_code = 1 ; offset of 'code' field in icmp packet
|
|
icmp_cksum = 2 ; offset of 'checksum' field in icmp packet
|
|
icmp_data = 4 ; offset of 'data' field in icmp packet
|
|
|
|
; icmp echo packet offsets
|
|
icmp_echo_id = 4 ; offset of 'id' field in icmp echo request/echo response
|
|
icmp_echo_seq = 6 ; offset of 'sequence' field in icmp echo request/echo response
|
|
icmp_echo_data = 8 ; offset of 'data' field in icmp echo request/echo response
|
|
|
|
; icmp type codes
|
|
icmp_msg_type_echo_reply = 0
|
|
icmp_msg_type_destination_unreachable = 3
|
|
icmp_msg_type_source_quench = 4
|
|
icmp_msg_type_redirect = 5
|
|
icmp_msg_type_echo_request = 8
|
|
icmp_msg_type_time_exceeded = 11
|
|
icmp_msg_type_paramater_problem = 12
|
|
icmp_msg_type_timestamp = 13
|
|
icmp_msg_type_timestamp_reply = 14
|
|
icmp_msg_type_information_request = 15
|
|
icmp_msg_type_information_reply = 16
|
|
|
|
; ping states
|
|
ping_state_request_sent = 0
|
|
ping_state_response_received = 1
|
|
|
|
|
|
.ifdef TCP
|
|
|
|
.bss
|
|
|
|
icmp_echo_ip: .res 4 ; destination IP address for echo request ("ping")
|
|
icmp_echo_cnt: .res 1 ; ping sequence counter
|
|
ping_state: .res 1
|
|
ping_timer: .res 2
|
|
|
|
.endif
|
|
|
|
|
|
.code
|
|
|
|
; initialize icmp
|
|
; inputs: none
|
|
; outputs: none
|
|
icmp_init:
|
|
lda #0
|
|
sta icmp_cbcount
|
|
rts
|
|
|
|
; process incoming icmp packet
|
|
; inputs:
|
|
; eth_inp points to an ethernet frame containing an icmp packet
|
|
; outputs:
|
|
; carry flag - set on any error, clear if OK
|
|
; if inbound packet is a request (e.g. 'echo request') and an icmp listener
|
|
; has been installed, then an appropriate response message will be
|
|
; generated and sent out (overwriting the eth_outp buffer)
|
|
icmp_process:
|
|
lda icmp_inp + icmp_type
|
|
cmp #icmp_msg_type_echo_request ; ping
|
|
beq @echo
|
|
|
|
lda icmp_cbcount ; any installed icmp listeners?
|
|
beq @drop
|
|
|
|
ldx icmp_cbcount ; check listened types
|
|
dex
|
|
: lda icmp_cbtype,x
|
|
cmp icmp_inp + icmp_type
|
|
beq @handle ; found a match
|
|
dex
|
|
bpl :-
|
|
|
|
@drop:
|
|
sec
|
|
rts
|
|
|
|
@handle:
|
|
lda icmp_cbveclo,x ; copy vector
|
|
sta icmp_cbtmp + 1
|
|
lda icmp_cbvechi,x
|
|
sta icmp_cbtmp + 2
|
|
jsr icmp_cbtmp ; call listener
|
|
clc
|
|
rts
|
|
|
|
@echo:
|
|
lda ip_broadcast ; check if packet is broadcast
|
|
beq @notbc
|
|
sec ; don't reply to broadcast pings
|
|
rts
|
|
@notbc:
|
|
ldx #5
|
|
: lda eth_inp,x ; swap dest and src mac
|
|
sta eth_outp + 6,x
|
|
lda eth_inp + 6,x
|
|
sta eth_outp,x
|
|
dex
|
|
bpl :-
|
|
|
|
ldx #12 ; copy the packet
|
|
: lda eth_inp,x
|
|
sta eth_outp,x
|
|
inx
|
|
cpx eth_inp_len
|
|
bne :-
|
|
|
|
ldx #3
|
|
: lda ip_inp + ip_src,x ; swap dest and src ip
|
|
sta ip_outp + ip_dest,x
|
|
lda ip_inp + ip_dest,x
|
|
sta ip_outp + ip_src,x
|
|
dex
|
|
bpl :-
|
|
|
|
lda #0 ; change type to reply
|
|
sta icmp_outp + icmp_type
|
|
|
|
lda icmp_inp + icmp_cksum ; recalc checksum
|
|
clc
|
|
adc #8
|
|
sta icmp_outp + icmp_cksum
|
|
bcc :+
|
|
inc icmp_outp + icmp_cksum + 1
|
|
: lda eth_inp_len ; copy length
|
|
sta eth_outp_len
|
|
lda eth_inp_len + 1
|
|
sta eth_outp_len + 1
|
|
|
|
lda #0 ; clear checksum
|
|
sta ip_outp + ip_header_cksum
|
|
sta ip_outp + ip_header_cksum + 1
|
|
ldax #ip_outp ; calculate ip header checksum
|
|
stax ip_cksum_ptr
|
|
ldax #20
|
|
jsr ip_calc_cksum
|
|
stax ip_outp + ip_header_cksum
|
|
|
|
jsr eth_tx ; send packet
|
|
clc
|
|
rts
|
|
|
|
; add an icmp listener
|
|
; inputs:
|
|
; A = icmp type
|
|
; icmp_callback: vector to call when an icmp packet of specified type arrives
|
|
; outputs:
|
|
; carry flag - set if error, clear if no error
|
|
icmp_add_listener:
|
|
ldx icmp_cbcount ; any listeners at all?
|
|
beq @add
|
|
cpx #icmp_cbmax ; max?
|
|
beq @full
|
|
ldx #0
|
|
: cmp icmp_cbtype,x ; check if type is already listened
|
|
beq @busy
|
|
inx
|
|
cpx icmp_cbcount
|
|
bne :-
|
|
@add:
|
|
inc icmp_cbcount ; increase counter
|
|
sta icmp_cbtype,x ; add type
|
|
lda icmp_callback ; and vector
|
|
sta icmp_cbveclo,x
|
|
lda icmp_callback + 1
|
|
sta icmp_cbvechi,x
|
|
clc
|
|
rts
|
|
|
|
@full:
|
|
@busy:
|
|
sec
|
|
rts
|
|
|
|
; remove an icmp listener
|
|
; inputs:
|
|
; A = icmp type
|
|
; outputs:
|
|
; carry flag - set if error (i.e. no listner for this type exists),
|
|
; clear if no error
|
|
icmp_remove_listener:
|
|
ldx icmp_cbcount ; any listeners installed?
|
|
beq @notfound
|
|
dex
|
|
: cmp icmp_cbtype,x ; check if type is listened
|
|
beq @remove
|
|
dex
|
|
bpl :-
|
|
@notfound:
|
|
sec
|
|
rts
|
|
@remove:
|
|
txa ; number of listeners below
|
|
eor #$ff
|
|
clc
|
|
adc icmp_cbcount
|
|
beq @done
|
|
@move:
|
|
tay ; number of items to move
|
|
: lda icmp_cbtype + 1,x ; move type
|
|
sta icmp_cbtype,x
|
|
lda icmp_cbveclo + 1,x ; move vector lsb
|
|
sta icmp_cbveclo,x
|
|
lda icmp_cbvechi + 1,x ; move vector msb
|
|
sta icmp_cbvechi,x
|
|
inx
|
|
dey
|
|
bne :-
|
|
@done:
|
|
dec icmp_cbcount ; decrement counter
|
|
clc
|
|
rts
|
|
|
|
.ifdef TCP
|
|
|
|
; icmp_send_echo was contributed by Glenn Holmer (ShadowM)
|
|
; send an ICMP echo ("ping") request
|
|
; inputs:
|
|
; icmp_echo_ip: destination IP address
|
|
; outputs:
|
|
; carry flag - set if error, clear if no error
|
|
icmp_send_echo:
|
|
ldy #3
|
|
: lda icmp_echo_ip,y
|
|
sta ip_outp + ip_dest,y
|
|
dey
|
|
bpl :-
|
|
|
|
lda #icmp_msg_type_echo_request
|
|
sta icmp_outp + icmp_type
|
|
lda #0 ; not used for echo packets
|
|
sta icmp_outp + icmp_code
|
|
sta icmp_outp + icmp_cksum ; clear checksum
|
|
sta icmp_outp + icmp_cksum + 1
|
|
sta icmp_outp + icmp_echo_id ; set id to 0
|
|
sta icmp_outp + icmp_echo_id + 1
|
|
inc icmp_echo_cnt + 1 ; big-endian
|
|
bne :+
|
|
inc icmp_echo_cnt
|
|
: ldax icmp_echo_cnt
|
|
stax icmp_outp + icmp_echo_seq
|
|
|
|
ldy #0
|
|
: lda ip65_msg,y
|
|
beq @set_ip_len
|
|
sta icmp_outp + icmp_echo_data,y
|
|
iny
|
|
bne :-
|
|
@set_ip_len:
|
|
tya
|
|
clc
|
|
adc #28 ; IP header + ICMP type, code, cksum, id, seq
|
|
sta ip_outp + ip_len + 1 ; high byte first
|
|
lda #0 ; will never be >256
|
|
sta ip_outp + ip_len
|
|
|
|
ldax #icmp_outp ; start of ICMP packet
|
|
stax ip_cksum_ptr
|
|
tya
|
|
clc
|
|
adc #8 ; ICMP type, code, cksum, id, seq
|
|
ldx #0 ; AX = length of ICMP data
|
|
jsr ip_calc_cksum
|
|
stax icmp_outp + icmp_cksum
|
|
lda #ip_proto_icmp
|
|
sta ip_outp + ip_proto
|
|
jsr ip_create_packet
|
|
jmp ip_send
|
|
|
|
; send a ping (ICMP echo request) to a remote host, and wait for a response
|
|
; inputs:
|
|
; icmp_echo_ip: destination IP address
|
|
; outputs:
|
|
; carry flag - set if no response, otherwise AX is time (in miliseconds) for host to respond
|
|
icmp_ping:
|
|
lda #0 ; reset the "packet sent" counter
|
|
sta icmp_echo_cnt
|
|
@send_one_message:
|
|
jsr icmp_send_echo
|
|
bcc @message_sent_ok
|
|
; we couldn't send the message - most likely we needed to do an ARP lookup.
|
|
; so wait a bit, and retry
|
|
|
|
jsr timer_read ; read current timer value
|
|
stax ping_timer
|
|
@loop_during_arp_lookup:
|
|
jsr ip65_process
|
|
ldax ping_timer
|
|
adc #50 ; set timeout to now + 50 ms
|
|
bcc :+
|
|
inx
|
|
: jsr timer_timeout
|
|
bcs @loop_during_arp_lookup
|
|
jsr icmp_send_echo
|
|
bcc @message_sent_ok
|
|
; still can't send? then give up
|
|
lda #IP65_ERROR_TRANSMIT_FAILED
|
|
sta ip65_error
|
|
rts
|
|
@message_sent_ok:
|
|
jsr timer_read ; read current timer value
|
|
stax ping_timer
|
|
ldax #icmp_ping_callback
|
|
stax icmp_callback
|
|
lda #icmp_msg_type_echo_reply
|
|
jsr icmp_add_listener
|
|
lda #ping_state_request_sent
|
|
sta ping_state
|
|
@loop_till_get_ping_response:
|
|
jsr ip65_process
|
|
|
|
lda ping_state
|
|
cmp #ping_state_response_received
|
|
beq @got_reply
|
|
ldax ping_timer
|
|
inx ; x rolls over about 4 times per second
|
|
inx ; so we will timeout after about 2 seconds
|
|
inx
|
|
inx
|
|
inx
|
|
inx
|
|
inx
|
|
inx
|
|
|
|
jsr timer_timeout
|
|
bcs @loop_till_get_ping_response
|
|
lda #IP65_ERROR_TIMEOUT_ON_RECEIVE
|
|
sta ip65_error
|
|
lda #icmp_msg_type_echo_reply
|
|
jsr icmp_remove_listener
|
|
sec
|
|
rts
|
|
@got_reply:
|
|
lda #icmp_msg_type_echo_reply
|
|
jsr icmp_remove_listener
|
|
jsr timer_read
|
|
sec
|
|
sbc ping_timer
|
|
pha
|
|
txa
|
|
sbc ping_timer+1
|
|
tax
|
|
pla
|
|
clc
|
|
rts
|
|
|
|
icmp_ping_callback:
|
|
lda icmp_inp + icmp_echo_seq
|
|
cmp icmp_echo_cnt
|
|
bne @not_what_we_were_waiting_for
|
|
lda #ping_state_response_received
|
|
sta ping_state
|
|
@not_what_we_were_waiting_for:
|
|
rts
|
|
|
|
ip65_msg:
|
|
.byte "ip65 - the 6502 IP stack",0
|
|
|
|
.endif
|
|
|
|
|
|
|
|
; -- LICENSE FOR icmp.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.
|
|
;
|
|
; Contributor(s): Jonno Downes, Glenn Holmer
|
|
; -- LICENSE END --
|