;
; This file requires NASM 0.97+ to assemble
;
; Currently used only for djgpp + DOS4GW targets
;
; these sizes MUST be equal to the sizes in PKTDRVR.H
;
%define  ETH_MTU     1500                  ; max data size on Ethernet
%define  ETH_MIN     60                    ; min/max total frame size
%define  ETH_MAX     (ETH_MTU+2*6+2)       ; =1514
%define  NUM_RX_BUF  32                    ; # of RX element buffers
%define  RX_SIZE     (ETH_MAX+6)           ; sizeof(RX_ELEMENT) = 1514+6
%idefine offset

struc RX_ELEMENT
     .firstCount  resw 1                  ; # of bytes on 1st call
     .secondCount resw 1                  ; # of bytes on 2nd call
     .handle      resw 1                  ; handle for upcall
   ; .timeStamp   resw 4                  ; 64-bit RDTSC value
     .destinAdr   resb 6                  ; packet destination address
     .sourceAdr   resb 6                  ; packet source address
     .protocol    resw 1                  ; packet protocol number
     .rxBuffer    resb ETH_MTU            ; RX buffer
endstruc

;-------------------------------------------

[org 0]  ; assemble to .bin file

_rxOutOfs   dw   offset _pktRxBuf          ; ring buffer offsets
_rxInOfs    dw   offset _pktRxBuf          ; into _pktRxBuf
_pktDrop    dw   0,0                       ; packet drop counter
_pktTemp    resb 20                        ; temp work area
_pktTxBuf   resb (ETH_MAX)                 ; TX buffer
_pktRxBuf   resb (RX_SIZE*NUM_RX_BUF)      ; RX structures
LAST_OFS   equ  $

screenSeg   dw  0B800h
newInOffset dw  0

fanChars    db  '-\|/'
fanIndex    dw  0

%macro SHOW_RX 0
      push es
      push bx
      mov bx, [screenSeg]
      mov es, bx                    ;; r-mode segment of colour screen
      mov di, 158                   ;; upper right corner - 1
      mov bx, [fanIndex]
      mov al, [fanChars+bx]         ;; get write char
      mov ah, 15                    ;;  and white colour
      cld                           ;; Needed?
      stosw                         ;; write to screen at ES:EDI
      inc word [fanIndex]           ;; update next index
      and word [fanIndex], 3
      pop bx
      pop es
%endmacro

;PutTimeStamp
;       rdtsc
;       mov [si].timeStamp, eax
;       mov [si+4].timeStamp, edx
;       ret


;------------------------------------------------------------------------
;
; This routine gets called by the packet driver twice:
;   1st time (AX=0) it requests an address where to put the packet
;
;   2nd time (AX=1) the packet has been copied to this location (DS:SI)
;   BX has client handle (stored in RX_ELEMENT.handle).
;   CX has # of bytes in packet on both call. They should be equal.
; A test for equality is done by putting CX in _pktRxBuf [n].firstCount
; and _pktRxBuf[n].secondCount, and CL on first call in
; _pktRxBuf[n].rxBuffer[CX]. These values are checked in "PktReceive"
; (PKTDRVR.C)
;
;---------------------------------------------------------------------

_PktReceiver:
        pushf
        cli                         ; no distraction wanted !
        push ds
        push bx
        mov bx, cs
        mov ds, bx
        mov es, bx                  ; ES = DS = CS or seg _DATA
        pop bx                      ; restore handle

        cmp ax, 0                   ; first call? (AX=0)
        jne @post                   ; AX=1: second call, do post process

%ifdef DEBUG
        SHOW_RX                     ; show that a packet is received
%endif

        cmp cx, ETH_MAX             ; size OK ?
        ja  @skip                   ; no, too big

        mov ax, [_rxInOfs]
        add ax, RX_SIZE
        cmp ax, LAST_OFS
        jb  @noWrap
        mov ax, offset _pktRxBuf
@noWrap:
        cmp ax, [_rxOutOfs]
        je  @dump
        mov di, [_rxInOfs]          ; ES:DI -> _pktRxBuf[n]
        mov [newInOffset], ax

        mov [di], cx                ; remember firstCount.
        mov [di+4], bx              ; remember handle.
        add di, 6                   ; ES:DI -> _pktRxBuf[n].destinAdr
        pop ds
        popf
        retf                        ; far return to driver with ES:DI

@dump:   add word [_pktDrop+0], 1    ; discard the packet on 1st call
        adc word [_pktDrop+2], 0    ; increment packets lost

@skip:   xor di, di                  ; return ES:DI = NIL pointer
        xor ax, ax
        mov es, ax
        pop ds
        popf
        retf

@post:   or si, si                   ; DS:SI->_pktRxBuf[n][n].destinAdr
        jz @discard                 ; make sure we don't use NULL-pointer

      ;
      ; push si
      ; call bpf_filter_match       ; run the filter here some day
      ; pop si
      ; cmp ax, 0
      ; je  @discard

        mov [si-6+2], cx            ; store _pktRxBuf[n].secondCount
        mov ax, [newInOffset]
        mov [_rxInOfs], ax          ; update _pktRxBuf input offset

      ; call PutTimeStamp

@discard:
        pop ds
        popf
        retf

_pktRxEnd  db 0                      ; marker for end of r-mode code/data

END