;********************************************************
;*                                                      *
;*                    DrvSend                           *
;*                                                      *
;*   Function:   Split the input whole block into       *
;*               some packets and send its using        *
;*               IPX services.                          *
;*   Input:      SS:BP points to registers save         *
;*               area. Select from this area CX,        *
;*               and DS:DX. In CX's length of segment,  *
;*               DS:DX points start of segment.         *
;*   Output:     In AX places IPX return code or zero   *
;*               if all O.K!                            *
;*                                                      *
;*                                                      *
;* CopyRight 1995. Nicholas Poljakov all rights reserved.*
;*                                                      *
;********************************************************
.MODEL TINY
.DOSSEG

include c:\lu62\novell\inc\ipxhdr.inc
include c:\lu62\novell\inc\seg.inc

EXTRN   ipxProc : DWORD
EXTRN   CancelECB : PROC
EXTRN   PrepECB : PROC
EXTRN   ipxECB : BYTE
EXTRN   ActLuMsg : BYTE
EXTRN   LocalS : BYTE

PUBLIC  DrvSend, CurSeg, SndStart, MainCycl
PUBLIC  SndExit, SndBlk, LastBlk, CallIPX, PollInUse
PUBLIC  SetNtAddr, NextBlk
PUBLIC  LocSnd, SndCont
PUBLIC  SetSAddr, SBExit
PUBLIC  InfoMsg, TestBcs, CmpCycl, SetExit

BLKLT    EQU   546      ; length of IPX max. block

.CODE
DrvSend  PROC
         jmp   SndStart

CurSeg   DD    0        ; pointer to current segment
ipxSECB  IPXECB <>      ; IPX ECB area
ipxHDR   IPXHDR <>      ; IPX header area

SndStart:
         cmp   LocalS, 0 ; is it a "Local_Send" operation ?
         jne   LocSnd

         les   bx, DWORD PTR [bp + 8]  ; input DS:DX pointer
         mov   cx, WORD PTR [bp + 12]  ; input CX value
         jmp   short SndCont

LocSnd:
         mov   bx, OFFSET ActLuMsg
         mov   cx, PRFLT + 9

SndCont:
         mov   dx, cx
         sub   dx, PRFLT
         cmp   es:[bx].SegLen, dx
         je    MainCycl
         mov   ax, -1   ; error return code (wrong length of segment)
         jmp   SndExit
MainCycl:
         mov   WORD PTR CurSeg, bx     ; save pointer
         mov   ax, es                  ; to
         mov   WORD PTR CurSeg + 2, ax ; current segment
         call  SetNtAddr
         and   ax, ax   ; check return code
         jnz   SndExit  ; bad return code...
         call  NextBlk
         call  SndBlk   ; prepare IPX fields and send block
         and   ax, ax
         jnz   SndExit  ; bad return code fron IPX
         les   bx, CurSeg
         les   bx, es:[bx].SegLink     ; pointer to next segment
                                       ; if it present.
         mov   ax, es
         and   ax, ax   ; if NULL pointer
         jnz   MainCycl ; then
         and   bx, bx   ; exit
         jnz   MainCycl ; from procedure

         call  PrepECB  ; set "listen" mode for receiving

SndExit:
         clc
         ret
DrvSend  ENDP

SndBlk   PROC
;*
;* On input : CX - total length of block; ES:BX - pointer to
;*            block.
;*
         push  cx

; First, sets ECB fields

         mov   ipxSECB.SocNum, MY_SOCKET
         mov   ipxSECB.FragNum, 2 ; two fragments : IPX header and
                                  ; data segment.

         mov   ax, OFFSET ipxHDR
         mov   WORD PTR ipxSECB.FAddr, ax
         mov   ax, cs
         mov   WORD PTR ipxSECB.FAddr + 2, ax
         mov   ipxSECB.FLt, 30 ; header length

SetSAddr:
         mov   WORD PTR ipxSECB.SAddr, bx
         mov   ax, es
         mov   WORD PTR ipxSECB.SAddr + 2, ax
         cmp   cx, BLKLT
         jb    LastBlk
         mov   ipxSECB.SLt, BLKLT ; header length
         mov   ax, BLKLT + 30
         xchg  ah, al
         mov   ipxHDR.PLt, ax     ; length of IPX header and max. block
                                  ; length
         add   bx, BLKLT          ; pointer to next segment of message
         sub   cx, BLKLT          ; rest length of message
         jmp   short CallIPX
LastBlk:
         mov   ipxSECB.SLt, cx    ; header length
         xor   cx, cx             ; End_Of_Block identifyer

; Set total length of packet

         mov   ax, ipxSECB.SLt
         add   ax, ipxSECB.FLt
         xchg  ah, al
         mov   ipxHDR.PLt, ax

; Then, call IPX send service...

CallIPX:
         push  cx       ; save CX from modification
         mov   bx, cs
         mov   es, bx
         mov   bx, 3
         mov   si, OFFSET ipxSECB
         call  ipxProc

; Wait for complete of SEND function

         sti            ; enable interrupts
PollInUse:
         cmp   ipxSECB.InUse, 0
         jnz   PollInUse

         pop   cx
         and   cx, cx   ; have I some data for sending yet?
         jz    SBExit
         jmp   SetSAddr ; set address of next data fragment and
                        ; try again...
SBExit:
         xor   ah, ah
         mov   al, ipxSECB.RetCode  ; set return code

         pop   cx
         ret
SndBlk   ENDP

SetNtAddr PROC

; Set network address in ECB
; ES:BX points to start of input segment.

          push cx
          mov  ax, WORD PTR es:[bx]
          mov  WORD PTR ipxSECB.PAddr, ax
          mov  ax, WORD PTR es:[bx + 2]
          mov  WORD PTR ipxSECB.PAddr + 2, ax
          mov  ax, WORD PTR es:[bx + 4]
          mov  WORD PTR ipxSECB.PAddr + 4, ax

; Set network address in header

          mov  ax, WORD PTR es:[bx]
          mov  WORD PTR ipxHDR.NdAddr, ax
          mov  ax, WORD PTR es:[bx + 2]
          mov  WORD PTR ipxHDR.NdAddr + 2, ax
          mov  ax, WORD PTR es:[bx + 4]
          mov  WORD PTR ipxHDR.NdAddr + 4, ax

; Set destignated socket

          mov  ipxHDR.SkDest, MY_SOCKET

; Set packet type

          cmp  LocalS, 0
          je   InfoMsg
          mov  ipxHDR.PType, 0  ; it's a control message
          jmp  short TestBcs
InfoMsg:
          mov  ipxHDR.PType, 4  ; it's a information message

; Test if it broadcasting message...
TestBcs:

          xor  si, si
          mov  cx, 6
CmpCycl:
          cmp  BYTE PTR es:[bx + si], 0ffh ; Node address
          jne  SetExit                     ; == 0fffffffffffh
          inc  si                          ; ???
          loop CmpCycl

          call CancelECB                   ; cancel listen if so...

SetExit:
          xor  ax, ax
          pop  cx
          ret
SetNtAddr ENDP

NextBlk  PROC
         push  cx
         mov   ax, bx
         mov   cx, 4
         shr   ax, cl
         mov   di, es
         add   ax, di
         mov   es, ax
         and   bx, 000fh
         pop   cx
         ret
NextBlk  ENDP

         END
