diff --git a/client/cfg/c64prg.cfg b/client/cfg/c64prg.cfg index b59f2d5..9cd8359 100644 --- a/client/cfg/c64prg.cfg +++ b/client/cfg/c64prg.cfg @@ -13,5 +13,7 @@ SEGMENTS { BSS: load = RAM, type = bss; ZEROPAGE: load = ZP, type = zp; IP65ZP: load = IP65ZP, type = zp; - EXEHDR: load = DISCARD, type = ro; + EXEHDR: load = DISCARD, type = ro; + TCP_VARS: load = RAM, type = bss; + } diff --git a/client/ip65/tcp.s b/client/ip65/tcp.s index f2afa17..1d7c968 100644 --- a/client/ip65/tcp.s +++ b/client/ip65/tcp.s @@ -10,33 +10,240 @@ .export tcp_init .export tcp_process -.export tcp_add_listener -.export tcp_remove_listener -.export tcp_send +.export tcp_listen +.export tcp_connect +.export tcp_callback +.export tcp_remote_ip + +.import ip_calc_cksum +.import ip_send +.import ip_create_packet +.import ip_inp +.import ip_outp +.importzp ip_cksum_ptr +.importzp ip_header_cksum +.importzp ip_src +.importzp ip_dest +.importzp ip_data +.importzp ip_proto +.importzp ip_proto_tcp +.importzp ip_id +.importzp ip_len + +.import copymem +.importzp copy_src +.importzp copy_dest + +.import cfg_ip .segment "TCP_VARS" -tcp_cxn_state =0 -tcp_cxn_local_port =1 -tcp_cxn_remote_port =3 -tcp_cxn_remote_ip =5 -tcp_cxn_local_seq =9 -tcp_cxn_remote_seq =13 -tcp_cxn_entry_size =17 -tcp_max_connections =10 +tcp_cxn_state_listening = 1 ;(waiting for an inbound SYN) +tcp_cxn_state_syn_sent = 2 ;(waiting for an inbound SYN/ACK) + + +; tcp packet offsets +tcp_inp = ip_inp + ip_data ;pointer to tcp packet inside inbound ethernet frame +tcp_outp = ip_outp + ip_data ;pointer to tcp packet inside outbound ethernet frame +tcp_src_port = 0 ;offset of source port field in tcp packet +tcp_dest_port = 2 ;offset of destination port field in tcp packet +tcp_seq = 4 ;offset of sequence number field in tcp packet +tcp_ack = 8 ;offset of acknowledgement field in tcp packet +tcp_header_length = 12 ;offset of header length field in tcp packet +tcp_flags_field = 13 ;offset of flags field in tcp packet +tcp_window_size = 14 ; offset of window size field in tcp packet +tcp_checksum = 16 ; offset of checksum field in tcp packet +tcp_urgent_pointer = 18 ; offset of urgent pointer field in tcp packet +tcp_data=20 ;offset of data in tcp packet + +; virtual header +tcp_vh = tcp_outp - 12 +tcp_vh_src = 0 +tcp_vh_dest = 4 +tcp_vh_zero = 8 +tcp_vh_proto = 9 +tcp_vh_len = 10 + +; +tcp_flag_FIN =1 +tcp_flag_SYN =2 +tcp_flag_RST =4 +tcp_flag_PSH =8 +tcp_flag_ACK =16 +tcp_flag_URG =32 + + + + +.segment "TCP_VARS" +tcp_state: .res 1 +tcp_local_port: .res 2 +tcp_remote_port: .res 2 +tcp_remote_ip: .res 4 +tcp_sequence_number: .res 4 +tcp_ack_number: .res 4 +tcp_data_ptr: .res 2 +tcp_data_len: .res 2 +tcp_callback: .res 2 +tcp_flags: .res 1 +.data +tcp_client_port: .word $0004 ;=$0400 in network byte order -tcp_connections: - .res tcp_max_connections*tcp_cxn_entry_size .code -tcp_add_listener: -tcp_remove_listener: -tcp_send: -tcp_process: - lda #NB65_ERROR_FUNCTION_NOT_SUPPORTED - sta ip65_error - sec + tcp_init: + + rts + +;make outbound tcp connection +;inputs: +; tcp_remote_ip: destination ip address (4 bytes) +; AX: destination port (2 bytes) +; tcp_callback: vector to call when data arrives on this connection +;outputs: +; carry flag is set if an error occured, clear otherwise +tcp_connect: + stax tcp_remote_port + inc tcp_client_port + ldax tcp_client_port + stax tcp_local_port + lda #tcp_cxn_state_syn_sent + sta tcp_state + lda #tcp_flag_SYN + sta tcp_flags + ldax #0 + stax tcp_data_len + stax tcp_ack_number + stax tcp_ack_number+2 + jsr tcp_send_packet rts +;send a single tcp packet +;inputs: +; tcp_remote_ip: IP address of destination server +; tcp_remote_port: destination tcp port +; tcp_local_port: source tcp port +; tcp_flags: 6 bit flags +; tcp_data_ptr: pointer to data to include in this packet +; tcp_data_len: length of data pointed at by tcp_data_ptr +;outputs: +; carry flag is set if an error occured, clear otherwise +tcp_send_packet: + ldax tcp_data_ptr + stax copy_src ; copy data to output buffer + ldax #tcp_outp + tcp_data + stax copy_dest + ldax tcp_data_len + jsr copymem + + ldx #3 ; copy virtual header addresses +: lda tcp_remote_ip,x + sta tcp_vh + tcp_vh_dest,x ; set virtual header destination + lda cfg_ip,x + sta tcp_vh + tcp_vh_src,x ; set virtual header source + dex + bpl :- + + lda tcp_local_port ; copy source port + sta tcp_outp + tcp_src_port + 1 + lda tcp_local_port + 1 + sta tcp_outp + tcp_src_port + + lda tcp_remote_port ; copy destination port + sta tcp_outp + tcp_dest_port + 1 + lda tcp_remote_port + 1 + sta tcp_outp + tcp_dest_port + + ldx #3 ; copy sequence and ack numbers (in reverse order) + ldy #0 +: lda tcp_sequence_number,x + sta tcp_outp + tcp_seq,y + lda tcp_ack_number,x + sta tcp_outp + tcp_ack,y + iny + dex + bpl :- + + lda #$50 ;4 bit header length in 32bit words + 4 bits of zero + sta tcp_outp+tcp_header_length + lda tcp_flags + sta tcp_outp+tcp_flags_field + + lda #ip_proto_tcp + sta tcp_vh + tcp_vh_proto + + ldax #$1000 + stax tcp_outp+tcp_window_size + + lda #0 ; clear checksum + sta tcp_outp + tcp_checksum + sta tcp_outp + tcp_checksum + 1 + sta tcp_vh + tcp_vh_zero ; clear virtual header zero byte + + ldax #tcp_vh ; checksum pointer to virtual header + stax ip_cksum_ptr + + lda tcp_data_len ; copy length + 20 + clc + adc #20 + sta tcp_vh + tcp_vh_len + 1 ; lsb for virtual header + tay + lda tcp_data_len + 1 + adc #0 + sta tcp_vh + tcp_vh_len ; msb for virtual header + + tax ; length to A/X + tya + + clc ; add 12 bytes for virtual header + adc #12 + bcc :+ + inx +: + jsr ip_calc_cksum ; calculate checksum + stax tcp_outp + tcp_checksum + + ldx #3 ; copy addresses +: lda tcp_remote_ip,x + sta ip_outp + ip_dest,x ; set ip destination address + dex + bpl :- + + jsr ip_create_packet ; create ip packet template + + lda tcp_outp + tcp_data_len + 1 ; ip len = tcp data length +20 byte ip header + 20 byte tcp header + ldx tcp_outp + tcp_data_len + clc + adc #40 + bcc :+ + inx +: sta ip_outp + ip_len + 1 ; set length + stx ip_outp + ip_len + + ldax #$1234 ; set ID + stax ip_outp + ip_id + + lda #ip_proto_tcp ; set protocol + sta ip_outp + ip_proto + + jmp ip_send ; send packet, sec on error + + +;listen on the tcp port specified +; tcp_callback: vector to call when data arrives on specified port +; AX: set to tcp port to listen on +tcp_listen: + rts + +tcp_process: +;process incoming tcp packet +;inputs: +; eth_inp: should contain an ethernet frame encapsulating an inbound tcp packet +;outputs: +; carry flag set if any error occured (including if packet not part of +; existing connection) +; carry flag clear if no error +; if connection was found, an outbound message may be created, overwriting eth_outp + rts diff --git a/client/test/test_tcp.s b/client/test/test_tcp.s index 4e07ba9..5a0295b 100644 --- a/client/test/test_tcp.s +++ b/client/test/test_tcp.s @@ -6,6 +6,12 @@ .import parse_dotted_quad .import dotted_quad_value + + .import tcp_listen + .import tcp_callback + .import ip65_process + .import tcp_connect + .import tcp_remote_ip .import __CODE_LOAD__ .import __CODE_SIZE__ @@ -105,9 +111,29 @@ init: ldax #$1234 jsr test_add_16_32 + + jsr print_cr + init_ip_via_dhcp + jsr print_ip_config + +@loop_forever: + ldax #tcp_callback_routine + stax tcp_callback + ldax tcp_dest_ip + stax tcp_remote_ip + ldax tcp_dest_ip+2 + stax tcp_remote_ip+2 + + + ldax #80 + jsr tcp_connect + + jsr ip65_process + jmp @loop_forever rts - +tcp_callback_routine: + rts ;assumes acc32 & op32 already set @@ -226,3 +252,6 @@ number15: number16: .byte $00,$00,$00,$00 + +tcp_dest_ip: + .byte 10,5,1,1 \ No newline at end of file