PAGE 60,132
NAME PKT_RX

ifdef ??version        ; using TASM
 masm
 jumps
endif

PUBLIC _pktDrop, _pktRxBuf, _pktTxBuf,    _pktTemp
PUBLIC _rxOutOfs, _rxInOfs, _PktReceiver, _pktRxEnd

;
; these sizes MUST be equal to the sizes in PKTDRVR.H
;

RX_BUF_SIZE = 1500      ; max message size on Ethernet
TX_BUF_SIZE = 1500

ifdef DOSX
.386
 NUM_RX_BUF = 32       ; # of RX element buffers
 _TEXT   SEGMENT PUBLIC DWORD USE16 'CODE'
 _TEXT   ENDS
 _DATA   SEGMENT PUBLIC DWORD USE16 'CODE'
 _DATA   ENDS
 D_SEG   EQU <_TEXT SEGMENT>
 D_END   EQU <_TEXT ENDS>
 ASSUME  CS:_TEXT,DS:_TEXT
else
.286
 NUM_RX_BUF = 10
 _TEXT   SEGMENT PUBLIC DWORD 'CODE'
 _TEXT   ENDS
 _DATA   SEGMENT PUBLIC DWORD 'DATA'
 _DATA   ENDS
 D_SEG   EQU <_DATA SEGMENT>
 D_END   EQU <_DATA ENDS>
 ASSUME  CS:_TEXT,DS:_DATA
endif

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

D_SEG

RX_ELEMENT     STRUC
  firstCount  dw  0                          ; # of bytes on 1st call
  secondCount dw  0                          ; # of bytes on 2nd call
  handle      dw  0                          ; handle for upcall
  destinAdr   db  6           dup (0)        ; packet destination address
  sourceAdr   db  6           dup (0)        ; packet source address
  protocol    dw  0                          ; packet protocol number
  rxBuffer    db  RX_BUF_SIZE dup (0)        ; RX buffer
ENDS
              align 4
_rxOutOfs      dw  offset _pktRxBuf           ; ring buffer offsets
_rxInOfs       dw  offset _pktRxBuf           ; into _pktRxBuf
_pktDrop       dw  0,0                        ; packet drop counter
_pktTemp       db  20                dup (0)  ; temp work area
_pktTxBuf      db  (TX_BUF_SIZE+14)  dup (0)  ; TX buffer
_pktRxBuf      RX_ELEMENT NUM_RX_BUF dup (<>) ; RX structures
LAST_OFS      = offset $

screenSeg     dw  0B800h
newInOffset   dw  0

fanChars      db  '-\|/'
fanIndex      dw  0

D_END

_TEXT SEGMENT


SHOW_RX  MACRO
        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
        stosw                         ;; write to screen at ES:EDI
        inc fanIndex                  ;; update next index
        and fanIndex, 3
        pop bx
        pop es
ENDM

;------------------------------------------------------------------------
;
; This macro return ES:DI to tail of Rx queue

ENQUEUE  MACRO
        LOCAL @noWrap
        mov ax, _rxInOfs              ;; DI = current in-offset
        add ax, SIZE RX_ELEMENT       ;; point to next _pktRxBuf buffer
        cmp ax, LAST_OFS              ;; pointing past last ?
        jb  @noWrap                   ;; no - jump
        lea ax, _pktRxBuf             ;; yes, point to 1st buffer
        align 4
@noWrap: cmp ax, _rxOutOfs             ;; in-ofs = out-ofs ?
        je  @dump                     ;; yes, queue is full
        mov di, _rxInOfs              ;; ES:DI -> buffer at queue input
        mov newInOffset, ax           ;; remember new input offset

  ;; NOTE. rxInOfs is updated after the packet has been copied
  ;; to ES:DI (= DS:SI on 2nd call) by the packet driver

ENDM

;------------------------------------------------------------------------
;
; 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
ifdef DOSX
        mov bx, cs
else
        mov bx, SEG _DATA
endif
        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, RX_BUF_SIZE+14      ; size OK ?
        ja  @skip                   ; no, packet to large for us

        ENQUEUE                     ; ES:DI -> _pktRxBuf[n]

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

        align 4
@dump:   inc _pktDrop[0]             ; discard the packet on 1st call
        adc _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

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

        sub si, 6                   ; DS:SI -> _pktRxBuf[n].destinAdr
      ;
      ; push si
      ; push [si].firstCount
      ; call bpf_filter_match       ; run the filter here some day?
      ; add sp, 4
      ; cmp ax, 0
      ; je  @discard

        mov [si].secondCount, cx
        mov ax, newInOffset
        mov _rxInOfs, ax            ; update _pktRxBuf input offset

        align 4
@discard:pop ds
        popf
        retf

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

_TEXT ENDS

END