; UDP (user datagram protocol) functions .include "../inc/common.inc" .include "../inc/error.inc" .import ip65_error .export udp_init .export udp_process .export udp_add_listener .export udp_remove_listener .export udp_send .export udp_send_internal .export udp_callback .export udp_inp .export udp_outp .exportzp udp_src_port .exportzp udp_dest_port .exportzp udp_len .exportzp udp_cksum .exportzp udp_data .export udp_send_dest .export udp_send_src_port .export udp_send_dest_port .export udp_send_len .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_udp .importzp ip_id .importzp ip_len .import copymem .importzp copy_src .importzp copy_dest .import cfg_ip .data udp_cbtmp: jmp $ffff ; temporary vector - gets filled in later .bss ; argument for udp_add_listener udp_callback: .res 2 ; vector to routine to be called when a udp packet arrives ; arguments for udp_send udp_send_dest: .res 4 ; set to ip address that udp packet will be sent to udp_send_src_port: .res 2 ; set to port that udp packet will be sent from udp_send_dest_port: .res 2 ; set to port that udp packet will be sent to udp_send_len: .res 2 ; set to length of data to be sent in udp packet (excluding ethernet,ip & udp headers) ; udp listener callbacks udp_cbmax = 4 udp_cbveclo: .res udp_cbmax ; table of listener vectors (lsb) udp_cbvechi: .res udp_cbmax ; table of listener vectors (msb) udp_cbportlo: .res udp_cbmax ; table of ports (lsb) udp_cbporthi: .res udp_cbmax ; table of ports (msb) udp_cbcount: .res 1 ; number of active listeners ; udp packet offsets udp_inp = ip_inp + ip_data ; pointer to udp packet inside inbound ethernet frame udp_outp = ip_outp + ip_data ; pointer to udp packet inside outbound ethernet frame udp_src_port = 0 ; offset of source port field in udp packet udp_dest_port = 2 ; offset of destination port field in udp packet udp_len = 4 ; offset of length field in udp packet udp_cksum = 6 ; offset of checksum field in udp packet udp_data = 8 ; offset of data in udp packet ; virtual header udp_vh = udp_outp - 12 udp_vh_src = 0 udp_vh_dest = 4 udp_vh_zero = 8 udp_vh_proto = 9 udp_vh_len = 10 ; temp for port comparison port: .res 2 .code ; initialize udp ; inputs: none ; outputs: none udp_init: lda #0 sta udp_cbcount rts ; process incoming udp packet ; inputs: ; eth_inp: should contain an ethernet frame encapsulating an inbound udp packet ; outputs: ; carry flag set if any error occured (including if no handler for specified port ; was found) ; carry flag clear if no error ; if handler was found, an outbound message may be created, overwriting eth_outp udp_process: lda udp_cbcount ; any installed udp listeners? beq @drop tax ; check ports dex @checkport: lda udp_cbportlo,x cmp udp_inp + udp_dest_port + 1 bne :+ lda udp_cbporthi,x cmp udp_inp + udp_dest_port beq @handle : dex bpl @checkport @drop: sec rts @handle: lda udp_cbveclo,x ; copy vector sta udp_cbtmp + 1 lda udp_cbvechi,x sta udp_cbtmp + 2 jsr udp_cbtmp ; call listener clc rts ; add a udp listener ; inputs: ; udp_callback: vector to call when udp packet arrives on specified port ; AX: set to udp port to listen on ; outputs: ; carry flag set if too may listeners already installed, clear otherwise udp_add_listener: sta port stx port + 1 ldy udp_cbcount ; any listeners at all? beq @add cpy #udp_cbmax ; max? beq @full ldy #0 @check: lda udp_cbportlo,y ; check if port is already handled cmp port bne :+ lda udp_cbporthi,y cmp port + 1 beq @busy : iny cpy udp_cbcount bne @check @add: inc udp_cbcount ; increase counter sta udp_cbportlo,y ; add port txa sta udp_cbporthi,y ; add port lda udp_callback ; and vector sta udp_cbveclo,y lda udp_callback + 1 sta udp_cbvechi,y clc rts @full: @busy: lda #IP65_ERROR_LISTENER_NOT_AVAILABLE sta ip65_error sec rts ; remove an udp listener ; inputs: ; AX = port to stop listening on ; outputs: ; carry flag clear of handler found and removed ; carry flag set if handler for specified port not found udp_remove_listener: sta port stx port + 1 ldy udp_cbcount ; any listeners installed? beq @notfound dey @check: lda udp_cbportlo,y ; check if port is handled cmp port bne :+ lda udp_cbporthi,y cmp port + 1 beq @remove : dey bpl @check @notfound: sec rts @remove: tya ; number of listeners below eor #$ff clc adc udp_cbcount beq @done @move: tax ; number of items to move : lda udp_cbportlo + 1,y ; move ports sta udp_cbportlo,y lda udp_cbporthi + 1,y sta udp_cbporthi,y lda udp_cbveclo + 1,y ; move vectors sta udp_cbveclo,y lda udp_cbvechi + 1,y sta udp_cbvechi,y iny dex bne :- @done: dec udp_cbcount ; decrement counter clc rts ; send udp packet ; inputs: ; udp_send_dest: destination ip address (4 bytes) ; udp_send_dest_port: destination port (2 bytes) ; udp_send_src_port: source port (2 bytes) ; udp_send_len: length of data to send (exclusive of any headers) ; AX: pointer to buffer containing data to be sent ; outputs: ; carry flag is set if an error occured, clear otherwise udp_send: stax copy_src ; copy data to output buffer ldax #udp_outp + udp_data stax copy_dest ldax udp_send_len jsr copymem ; now we can fall through into udp_send_internal ; send udp packet with data at (udp_outp + udp_data) ; inputs: ; udp_send_dest: destination ip address (4 bytes) ; udp_send_dest_port: destination port (2 bytes) ; udp_send_src_port: source port (2 bytes) ; udp_send_len: length of data to send (exclusive of any headers) ; outputs: ; carry flag is set if an error occured, clear otherwise udp_send_internal: ldx #3 ; copy virtual header addresses : lda udp_send_dest,x sta udp_vh + udp_vh_dest,x ; set virtual header destination lda cfg_ip,x sta udp_vh + udp_vh_src,x ; set virtual header source dex bpl :- lda udp_send_src_port ; copy source port sta udp_outp + udp_src_port + 1 lda udp_send_src_port + 1 sta udp_outp + udp_src_port lda udp_send_dest_port ; copy destination port sta udp_outp + udp_dest_port + 1 lda udp_send_dest_port + 1 sta udp_outp + udp_dest_port lda #ip_proto_udp sta udp_vh + udp_vh_proto lda #0 ; clear checksum sta udp_outp + udp_cksum sta udp_outp + udp_cksum + 1 sta udp_vh + udp_vh_zero ; clear virtual header zero byte ldax #udp_vh ; checksum pointer to virtual header stax ip_cksum_ptr lda udp_send_len ; copy length + 8 clc adc #8 sta udp_outp + udp_len + 1 ; lsb for udp header sta udp_vh + udp_vh_len + 1 ; lsb for virtual header tay lda udp_send_len + 1 adc #0 sta udp_outp + udp_len ; msb for udp header sta udp_vh + udp_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 udp_outp + udp_cksum ldx #3 ; copy addresses : lda udp_send_dest,x sta ip_outp + ip_dest,x ; set ip destination address dex bpl :- jsr ip_create_packet ; create ip packet template lda udp_outp + udp_len + 1 ; ip len = udp len + 20 ldx udp_outp + udp_len clc adc #20 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_udp ; set protocol sta ip_outp + ip_proto jmp ip_send ; send packet, sec on error ; -- LICENSE FOR udp.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 --