udpsend.asm


;+
; **-udp_send-send a UDP datagram.
;
; inputs:
;   SRAM:
;       MEM_UDP_LEN     = native byte order length of data to send
;       MEM_ETH_DEST    = destination ethernet address
;       MEM_IP_DSTADDR  = destination IP address
;
;   transmit buffer:
;       UDP_DATA        = user data to be sent (MEM_UDP_LEN bytes of it)
;
; checksum algorithm:
;
;   ip_chksum = 0 ;
;   ip_chksum = ~checksum(IPH,IPHLEN)
;   udp_chksum = 0
;   ph.src = ip.src
;   ph.dst = ip.dst
;   ph.mbzprot = 0|(ip.prot<<8)
;   ph.len = udp_len (UDP data only, not header)
;   ph_chksum = checksum(UDP_HDR,UDP_LEN+UDP_HEADER_LEN)
;   udp_chksum = ~checksum(PH_HDR,PH_HEADER_LEN)
;-

#include "udpsend.h"

#define PH_HEADER  rcv_hdr+en_rbuf_nhdr
#define PH_SRCADDR PH_HEADER+0
#define PH_DSTADDR PH_HEADER+4
#define PH_MBZPROT PH_HEADER+8
#define PH_LEN     PH_HEADER+10
#define PH_CHKSUM  PH_HEADER+12
#define PH_HEADER_LEN      14

#define MOVW(x,y) pmovwi x,[y]

udp_send:
;
; compute UDP length and store in UDP_LEN field and PH_LEN field.
;
    MOVW(buf+2,MEM_UDP_LEN)             ; get length (native order)
    MOVW(buf,buf+2)                     ; copy it
    paddwi buf,UDP_HEADER_LEN           ; total length
    MOVW(MEM_UDP_LEN,swap buf)          ; set UDP length
;
; checksum UDP header, data, and store checksum (uncomplemented) in
; pseudoheader.
;
    pclrw MEM_UDP_CHKSUM                ; zero UDP checksum in header
    pclrw chkacc                        ; reset checksum accumulator
    pmovwi chkaddr,MEM_UDP_HEADER       ; -> data
    pmovwi chklen,UDP_HEADER_LEN        ; length
    sram_checksum                       ; compute checksum

    pmovb chkaddr+1,xmit_page           ; address transmit page
    pmovbi chkaddr,UDP_DATA             ; UDP data
    pmovwi chklen,[buf+2]               ; its length
    in_checksum                         ; accumulate into chkacc
    MOVW(PH_CHKSUM,chkacc)              ; store checksum in pseudoheader

    paddwi buf,IP_HEADER_LEN
    MOVW(MEM_IP_LEN,swap buf)           ; set IP length
;
; the IP header should be ready, zero its checksum, checksum it, and
; store complemented checksum back in header.
;
    pclrw MEM_IP_CHKSUM                 ; zero IP header checksum
    pclrw chkacc
    pmovwi chkaddr,MEM_IPH              ; -> IP header
    pmovwi chklen,IP_HEADER_LEN         ; length
    sram_checksum                       ; compute checksum
    pcomw chkacc
    MOVW(MEM_IP_CHKSUM,chkacc)          ; store in IP header
;
; finally, checksum the pseudoheader and store complemented checksum
; in UDP header.
;
    pmemcpy PH_SRCADDR,MEM_IP_SRCADDR,8 ; source/dest IP addrs
    pmovwi PH_MBZPROT,0x1100            ; UDP proto in PH
    MOVW(PH_LEN,MEM_UDP_LEN)            ; store net order length in ph

    pclrw chkacc
    pmovwi chkaddr,PH_HEADER            ; -> PH
    pmovwi chklen,PH_HEADER_LEN         ; length of PH
    sram_checksum
    pcomw chkacc
    MOVW(MEM_UDP_CHKSUM,chkacc)         ; store in UDP header checksum
;
; compute total packet size and send.
;
    MOVW(buf,swap MEM_IP_LEN)           ; ip length total
    paddwi buf,IPH                      ; compute length with ether header

    ps2x 0,MEM_ETH_DEST,UDP_DATA        ; slap on ether, ip, udp headers
    xmit_frame [buf]                    ; out she goes

    pret

Back