home *** CD-ROM | disk | FTP | other *** search
- ; arp.asm
- ;========================================================================
-
- ; Copyright (C) 1991 by Jan.Engvald@ldc.lu.se, see file COPYING.
-
- ;************************************************************************
- ;************************************************************************
- ;*
- ;* UDP/IP library
- ;*
- ;* This library is in a transition phase from a PDCLKSET specific library
- ;* into a multiprocess, reentrant, any hardware type, general UDP/IP
- ;* library. The buffers used have a descriptor part and a packet part.
- ;* The descriptor part is used to allow reentrancy, different physical
- ;* address lengths and varying number of IP options.
- ;*
- ;* In this library DS:BX always points to the descriptor buffer, DS:DI and
- ;* DS:SI usually points to the physical header/IP header/UDP header part of
- ;* the IP packet buffer and DX,AX often contains an IP number in network
- ;* byte order (DL,DH,AL,AH). For efficiency reasons, IP numbers are
- ;* searched last half first (first halves are often equal).
- ;*
- ;* As this library is still evolving, you can not assume that it looks
- ;* the same in the next release. In particular, if you are using any of
- ;* of the subroutines, check if their calls or results have been changed.
- ;* For the 2.0 version subroutine register usage has changed from save
- ;* almost everything to save almost nothing. This because it speeds up
- ;* execution speed significantly and there were only a few places where
- ;* it affected the caller so he had to save additional registers.
- ;*
- ;* The current implementation is RFC791 (IP) and RFC1122 (host requirements)
- ;* compliant, except for a few cases: I havn't found a reasonable solution
- ;* on how to report back to the application ICMP errors like parameter
- ;* problem, protocol and port unreachables, and fragment reassembly time
- ;* exceeded. Also, IP options are allowed, but the interpretation and handling
- ;* must be done by the application. Apart from the above, it is a de luxe
- ;* implementation that includes things like multiple default gateways,
- ;* sending protocol and port unreachables, IP type of service handling (not
- ;* tested), fragment reassembly and source quench introduced delay.
- ;*
- ;************************************************************************
- ;************************************************************************
-
- Descriptor struc
- dLink LinkStruc <> ; next & prev links
- ; dIOCB iocb <> ; pkt drvr hi perf struc
- dPtrPhys dw 0 ; ptr to physical hdr
- dPtrIp dw 0 ; ptr to IP hdr
- dPtrUdp dw 0 ; ptr to UDP hdr
- dPktLen dw 0 ; packet length (bytes)
- dPktEnd dw 0 ; end of packet
- dTimOut2Msg equ dPktEnd ; Timeout msg for findsends
- dSqDelay dw 0 ; source quench delay (ms)
- dWaitEvent dw 0 ; event to wait for
- dPtrFrag equ dWaitEvent ; ptr to defargment listhead
- dTimOutMsg dw 0 ; to be displayed at timeout
- dTickResend dw 1*18 ; resend start interval (ticks)
- dTickTimeout dw 4*18 ; timeout ticks (in 1/18 s)
- dTick2Timeout dw 14*18 ; second timeout
- dIdxHwDst equ dSqDelay ; arp table index for hw dst
- dIdxIpDst equ dTick2Timeout ; arp table index for IP dst
- dAdjust equ (4-(($-dLink) and 3)) and 3
- if dAdjust
- db dAdjust dup (0)
- endif
- dGwys2Chk db 0 ; # of untried gateways
- dSnap db 0 ; 802.3 snaps used
- dPtrDes dw 0 ; ptr to start of descriptor
- dHwDst equ $-dLink ; (part of pd packet)
- Descriptor ends
- DESCRLEN equ SIZE Descriptor
-
- HwStruc struc
- hEthDst db 6 dup (0) ; Ethernet destination address
- hEthSrc db 6 dup (0) ; my Ether addr
- hProtType dw 0008 ; 0800 = IP
- HwStruc ends
- HWHDRLEN equ SIZE HwStruc
-
- SnapStruc struc
- sDSAP db 170
- sSSAP db 170
- sContr db 3
- sOrgCode db 0,0,0
- sProt db 08, 00
- SnapStruc ends
- SNAPLEN equ SIZE SnapStruc
-
- ArpStruc struc
- iArpHtype dw 0 ; 0001 = Ether
- iArpProt dw 0008h ; 0800 = IP
- iArpHlen db 0 ; Hw addr length
- iArpPlen db 4 ; IP addr length
- iArpOp dw 0100h ; 0001 = request
- iArpMyHwAd db 2*MAX_ADDR_LEN+2*4 dup (0)
- ArpBodyLen = $-iArpHtype
- ArpStruc ends
-
- DriverClass label byte
- Class2Htype db 0
- db 1 ; 1 Ethernet
- db 4 ; 2 Pronet-10
- db 6 ; 3 802.5 TR
- db 0 ; 4 Omninet
- db 11 ; 5 LocalTalk
- db 0 ; 6 Slip
- if 0
- db 1 ; 7 StarLan
- db 7 ; 8 Arcnet
- db 3 ; 9 AX.25
- endif
-
- ifndef ARPSLOTS
- ARPSLOTS equ 12
- endif
-
- ; The arp table contains information on hosts on this net.
- ; Slot 0, 1 and 2 (index 0, 2 and 4) are static and contain:
- ; this net broadcast, this subnet broadcast and my address, respectively.
- ;
- ; If we don't RECEIVE packets for more than a minute from a host or gateway,
- ; its slot is cleared. If we then DO receive a packet, the slot is restored
- ; by VerifyIpHdr without sending an ARP. On the other hand, if WE want to
- ; send the next packet, we will do an ARP and can thus detect dead hosts
- ; or gateways.
- even
- ArpTabIp2 dw 2 dup (0ffffh) ; IP # (last part)
- dw ARPSLOTS-2 dup (0)
- ArpTabIp1 dw 2 dup (0ffffh) ; IP # (first part)
- dw ARPSLOTS-2 dup (0)
- ArpTabTr dw ARPSLOTS dup (0) ; timer
- ArpTabFlags dw ARPSLOTS dup (0) ; flags
- ArpTabTrSq dw ARPSLOTS dup (0) ; source quench timer
- ArpTabSqDelay dw ARPSLOTS dup (0) ; source quench delay
- ArpTabHwAdr db ARPSLOTS*MAX_ADDR_LEN dup (0ffh) ; hardware addr (max 16 bytes)
- ArpTabHwEnd equ $
- USE_SNAP equ 1 ; bit in ArpTabFlags
- SQ_UPDATED equ 2 ; bit in ArptabFlags/RouteTabFl
-
- ARPMYIDX equ 4
- ArpPutSlot dw ARPMYIDX
-
- ArpType dw 0608h
- ArpBuf ArpStruc <>
-
- ArpFixedLen equ $-ArpType
- aArpOffsSrcIp equ iArpMyHwAd+2-iArpHtype
- MyHwAd equ ArpBuf.iArpMyHwAd
- IpType equ ArpBuf.iArpProt
- ArpFixedPart equ ArpType
-
- even
- DONT_WAIT equ 1
- GOT_BOOTP equ 2
- GOT_ARPREPLY equ 4
- GOT_TIMEREPLY equ 8
- GOT_ARPREQ equ 16
- GOT_ICMPMSG equ 32
- GOT_NSREPLY equ 64
- Events dw 1 ; =1 so DONT_WAIT always true
-
- ARGZONE equ 2
- ARGZONESPEC equ 4
- DSTNOW equ 8
- IS_A_386 equ 16
- TBL_READY equ 32
- UDP_ECHO equ 64
- DBGSTOP equ 0080h
- ECHO_DISPL equ 0100h
- GOT_DSP_ROW equ 0200h
- CONT_ON_ERR equ 0400h ; = xor STOP_ON_ERR
- NO_ERR_YET equ 0800h
- NO_DROP_YET equ 1000h
- PING_DELAY equ 2000h
- PROBE_REPLY equ 4000h
- DBGINTERR equ 8000h
- GenFlags dw NO_DROP_YET
-
- SnapHdr SnapStruc <>
-
- ArpHandle dw 0
- MySegm dw 0
- Hlen dw 0
- H2Len dw 0
- LongerTimOut dw 0
- SavedTicks dw 0
- InSendAndW db 0
-
- if DEBUG
- DbgIntCnt db 1
- endif ; DEBUG
-
-
-
- ;************************************************************************
- ;* CurrentTicks
- ;* Output: CX = low word of ticks (1/18 second) counter
- ;* Destroys: CX, ES
- ;************************************************************************
-
- CurrentTicks proc near
- assume ds:nothing
- mov cx,040h ; DOS data segment
- mov es,cx
- mov cx,es:[6ch] ; get low word of ticks cntr
- mov cs:SavedTicks,cx
- ret
- CurrentTicks endp
-
-
-
- if RFCC
- ;************************************************************************
- ;* HardwareTicks (48 bit time to si:dx:ax in 838 ns units)
- ;************************************************************************
-
- TimerResolution equ 1193 ; hw ticks per millisecond
-
- InitTimer proc near
- assume ds:code_s
- test ArgFlags,AVOID_HDWR
- jnz InitTimRet
- mov dx,043h ; select timer control port
- mov al,034h
- out dx,al ; mode 2: Rate generator
- call IoDelay ; (counts down by 1 to zero)
- xor ax,ax
- mov dx,040h ; select timer 0
- out dx,al ; set divide by 2**16
- call IoDelay
- out dx,al ; the generator is now started
- InitTimRet:
- ret
- InitTimer endp
-
- RestoreTimer proc near
- assume ds:code_s
- test ArgFlags,AVOID_HDWR
- jnz ResTimRet
- mov dx,043h ; select timer control port
- mov al,036h
- out dx,al ; mode 3: Square wave generator
- call IoDelay ; (counts down by 2 to zero,
- xor ax,ax ; twice)
- mov dx,040h ; select timer 0
- out dx,al ; set divide by 2**16
- call IoDelay
- out dx,al
- ResTimRet:
- ret
- RestoreTimer endp
-
- IoDelay proc near
- assume ds:nothing
- push ax
- in al,061h ; ISA/EISA: 1us, MCA: 0.5 us
- pop ax
- ret
- IoDelay endp
-
- HardwareTicks proc near
- assume ds:nothing
- test cs:ArgFlags,AVOID_HDWR
- jnz HwTicksNoHi
-
- push es
- mov dx,020h ;/* Address PIC ocw3 */
- mov al,00Ah ;/* Ask to read irr */
- cli
- out dx,al
-
- xor al,al ;/* Latch timer 0 */
- out 043h,al
- in al,040h ;/* Counter --> ax*/
- mov ah,al ;/* LSB in AH */
- in al,040h ;/* MSB in AL */
- xchg al,ah
- not ax ;/* Need ascending counter */
- push ax ; Save hardware counter value
-
- in al,dx ;/* Read irr */
- push ax ; Save irr
-
- in al,021h ;/* Read PIC imr */
- push ax ; Save imr
-
- mov al,00FFh ;/* Mask all interrupts */
- out 021h,al
-
- mov ax,040h ;/* read low word of time */
- mov es,ax ;/* from BIOS data area */
- mov dx,es:[06Ch]
- mov si,es:[06Ch+2] ; get high word too
-
- pop ax ; Restore imr
- out 021h,al
- pop ax ; Restore irr
- test al,001h ;/* Counter hit 0? */
- pop ax ; Restore counter value
- jnz HwTicksMore ;/* Jump if yes */
- sti
- pop es
- ret
-
- HwTicksMore:
- cmp ax,0FFh ;/* Counter > 0x0FF? */
- ja HwTicksDone ;/* Done if so */
-
- add dx,1 ;/* Else count int req. */
- adc si,0
- HwTicksDone:
- sti
- pop es
- ret
-
- HwTicksNoHi:
- push es
- mov ax,040h
- mov es,ax
- cli
- mov dx,es:[06Ch]
- mov si,es:[06Ch+2]
- xor ax,ax
- sti
- pop es
- ret
- HardwareTicks endp
- endif ; RFCC
-
-
-
- ;************************************************************************
- ;* OpenProt
- ;************************************************************************
-
- OpenProt proc near
- assume ds:code_s
- push si ; save protocol ptr
- push ds
- mov ax,1ffh ; driver_info
- int_pkt
- pop ds
-
- call fatal_error
-
- mov ah,2 ; access all packets.
- mov al,ch ; their class from driver_info().
- mov DriverClass,ch
- mov bx,offset Class2Htype ; class dependent code
- xlat
- mov byte ptr ArpBuf.iArpHtype+1,al
- cmp al,6 ; 802.2 ?
- jne InitNotSnap
- or GenFlags,USE_SNAP
- InitNotSNap:
- mov al,ch
- mov bx,dx ; their type from driver_info().
- mov dl,cl ;their number from driver_info().
- mov cx,2 ;type length of two.
- pop si ;ds:si -> protocol type
- push cs
- pop es
- mov di,offset Receiver ;es:di -> our receiver.
-
- push ds
- int_pkt
- pop ds
-
- call fatal_error
- ret
- OpenProt endp
-
-
-
- ;************************************************************************
- ;* InitProtocols
- ;************************************************************************
-
- InitProtocols proc near
- assume ds:code_s
-
- push sp ; find CPU features
- pop ax
- cmp ax,sp ; 286 or better?
- jne IsNot386
-
- pushf
- pop ax
- or ax,7000h ;the 386 lets us set these bits
- push ax
- popf
- pushf
- pop ax
- test ax,7000h ;did the bits get set?
- jz IsNot386 ;no.
- or GenFlags,IS_A_386 ;yes, use a 386-optimized code
- IsNot386:
- call CurrentTicks ; get current ticks value
- mov BootpXid,cx
- if RFCC
- mov AgeNext,cx ; initialize ageing
- mov AgeFragsNext,cx
- endif ; RFCC
-
- mov si,offset IpType ; start IP
- call OpenProt
- mov IpHandle,ax
-
- cmp byte ptr ArpBuf.iArpHtype+1,0 ; need ARP?
- je InitArpNotUsed
-
- mov si,offset ArpType ; start ARP
- call OpenProt
- mov ArpHandle,ax
-
- mov bx,ax
- push cs
- pop es
- mov di,offset MyHwAd
- push di
- mov cx,15
- mov ah,6 ; get my Hw addr
-
- push ds
- int_pkt
- pop ds
-
- call fatal_error
-
- mov ArpBuf.iArpHlen,cl ; save Hw address length
- mov Hlen,cx
- shl cx,1
- mov H2Len,cx
-
- pop si ; my HW addr to ARP tab
- xor ax,ax
- mov dx,ax
- call ArpPutNew
- InitArpNotUsed:
- push cs
- pop es
- ret
- InitProtocols endp
-
-
-
- ;************************************************************************
- ;* EndProtocol
- ;************************************************************************
-
- EndProtocol proc near
- assume ds:code_s
- mov ah,3 ; release handle in bx
-
- push ds
- int_pkt
- pop ds
-
- call print_error
-
- ret
- EndProtocol endp
-
-
-
- ;************************************************************************
- ;* MakeSendDescr
- ;*
- ;* Input: DS:BX = IP description buffer ptr (saved)
- ;* Output: Descriptor defaults filled in
- ;* DI = Udp ptr
- ;* Destroys: DI, flags
- ;************************************************************************
-
- MakeSendDescr proc near
- assume ds:nothing
- push si
- push cx
- mov [bx].dSqDelay,0
- mov [bx].dWaitEvent,0
- mov [bx].dTimOutMsg,offset MsgNoConect
- mov [bx].dTickTimeout,4*18
- mov [bx].dTickResend,1*18
- lea di,[bx+DESCRLEN+2*MAX_ADDR_LEN+2+SNAPLEN]
- mov si,di
- sub si,2
- xor cx,cx
- test cs:GenFlags,USE_SNAP ; 802.5 network?
- jz MakeNotSnap
- sub si,SNAPLEN
- inc cx
- MakeNotSnap:
- mov [bx].dSnap,cl
- sub si,cs:H2Len
- mov [bx].dPtrPhys,si
- add si,cs:MyGiant
- mov [bx].dPktEnd,si
-
- mov [bx].dPtrIp,di
- mov word ptr [di].iIpVerHlen,0045h ; IP ver 4; Tos = 0
- mov [di].iIpFlFrag,0
- mov [di].iIpTtl,90
-
- add di,IPHDRLEN
- mov [bx].dPtrUdp,di
- pop cx
- pop si
- ret
- MakeSendDescr endp
-
-
-
- ;************************************************************************
- ;* PutPhysSrc
- ;*
- ;* Input: DS:BX = IP description buffer ptr (saved)
- ;* ES = DS
- ;* Output: HW src addr and IP prot type put into pkt
- ;* CX = phys header length
- ;* Destroys: CX, SI, DI, ES, flags, enables interrupt
- ;************************************************************************
-
- PutPhysSrc proc near
- assume ds:nothing
- CHK_ES_EQ_DS
- mov si,offset MyHwAd ; get my HW addr from ARP buf
- mov di,[bx].dPtrPhys
- mov cx,cs:Hlen
- add di,cx
- PutPhysLoop1:
- cli
- rep movs byte ptr es:[hEthSrc],cs:[MyHwAd]
- sti
-
- test [bx].dSnap,1 ; use snap?
- jz PutPhysNotSnap
-
- mov cx,[bx].dPktLen
- add cx,SNAPLEN
- xchg ch,cl
- mov [di],cx
- add di,2
-
- mov si,offset SnapHdr
- rept (sProt-sDSAP)/2
- movs word ptr es:[sDSAP], word ptr cs:[SnapHdr]
- endm
- PutPhysNotSnap:
- mov cx,di
- sub cx,[bx].dPtrPhys
- add cx,2 ; physical header length
-
- mov word ptr [di],0008h ; protocol type IP (0800)
-
- ret
- PutPhysSrc endp
-
-
-
- ;************************************************************************
- ;* ArpFindIp
- ;*
- ;* Input: DX = first word of IP # (saved)
- ;* AX = second word of IP # (saved)
- ;* A PushfDI must be done before calling
- ;* Output: if found: zero and DI = arp table index
- ;* ES = CS
- ;* Destroys: CX, DI, ES, flags
- ;************************************************************************
-
- ArpFindIp proc near
- assume ds:nothing
- mov es,cs:MySegm
- mov di,offset ArpTabIp2
- mov cx,ARPSLOTS
- ArpFindIpNext: ; look for matching slot
- repne scasw
- jnz ArpFindIpRet
-
- cmp dx,cs:2*ARPSLOTS-2[di] ; does IP # first part match?
- jne ArpFindIpNext ; - no, look further
-
- sub di,offset ArpTabIp2+2 ; - yes, compute slot index
- cmp di,di ; set zero flag
- ArpFindIpRet:
- ret
- ArpFindIp endp
-
-
-
- ;************************************************************************
- ;* ArpFindHw
- ;*
- ;* Input: DS:AX = address of HW addr
- ;* A PushfDI must be done before calling
- ;* Output: if found: zero and DI = arp table index
- ;* ES = CS
- ;* Destroys: (AX,) DX, CX, SI, DI, ES, flags
- ;************************************************************************
-
- ArpFindHwHl proc near
- assume ds:nothing
- add ax,cs:Hlen ; get physical src addr
- ArpFindHw:
- mov es,cs:MySegm
- mov dx,offset ArpTabHwAdr+MAX_ADDR_LEN ; first two entries are similar
- ArpFindHwNext:
- mov cx,cs:Hlen
- mov di,dx
- mov si,ax
- repe cmpsb ; is this hw addr in arp tab?
- jz ArpFindHwFound
-
- add dx,MAX_ADDR_LEN ; check next entry
- cmp dx,offset ArpTabHwEnd-MAX_ADDR_LEN ; more entries?
- jbe ArpFindHwNext
-
- ret ; not found (non-zero) return
-
- ArpFindHwFound:
- sub dx,offset ArpTabHwAdr
- shr dx,1
- shr dx,1
- shr dx,1
- mov di,dx
- cmp di,di
- ret ; found (zero) return
- ArpFindHwHl endp
-
-
-
- ;************************************************************************
- ;* ArpPutHwAd
- ;*
- ;* Input: DS:SI = pointer to physical address (saved)
- ;* DS:BX = descriptor buffer ptr (saved)
- ;* DI = arp table index
- ;* A PushfDI must be done before calling
- ;* Destroys: CX, DI, ES, flags
- ;************************************************************************
-
- ArpPutHwAd proc near
- assume ds:nothing
- mov es,cs:MySegm
- push si
-
- mov cx,cs:SavedTicks ; get current ticks value
- mov cs:ArpTabTr[di],cx
-
- mov cx,cs:ArpTabFlags[di]
- and cl,not USE_SNAP
- or cl,[bx].dSnap ; remember if snaps used
- mov cs:ArpTabFlags[di],cx ; by that host
-
- mov cl,3 ; put hw addr into slot
- shl di,cl
- lea di,ArpTabHwAdr[di]
- mov cx,cs:Hlen
- rep movsb
- pop si
- ret
- ArpPutHwAd endp
-
-
-
- ;************************************************************************
- ;* ArpPutHwDst
- ;*
- ;* Input: DX = first word of IP # (saved)
- ;* AX = second word of IP # (saved)
- ;* DS:BX = description buffer ptr (saved)
- ;* Output: if found: zero, HW dst addr copied to pkt and CX = 0
- ;* ES = DS
- ;* Destroys: CX, SI, DI, ES, flags
- ;************************************************************************
-
- ArpPutHwDst proc near
- assume ds:nothing
- cli
-
- call ArpFindIp ; IP # in arp table?
- mov cx,ds
- mov es,cx
- jnz ArpPutHwRet ; - no, non-zero (not found)
-
- mov cx,cs:ArpTabFlags[di] ; use snap if neeeded
- and cl,USE_SNAP
- mov [bx].dSnap,cl ; by dst host
- if RFCC
- push ax
- mov cx,cs:SavedTicks
- mov ax,cs:ArpTabSqDelay[di] ; move sq delay to descriptor
- mov [bx].dSqDelay,ax
- dec ax ; any delay?
- js ArpNoSqDelay
- mov ax,cs:ArpTabTrSq[di] ; - yes
- add ax,18 ; has one second has passed
- cmp ax,cx ; since we last decremented
- jns ArpNoSqDelay ; the delay value?
- mov cs:ArpTabTrSq[di],cx
- dec cs:ArpTabSqDelay[di] ; - yes, one millisecond off
- ArpNoSqDelay:
- pop ax
- endif ; RFCC
- mov cl,3 ; - yes, copy HW addr
- shl di,cl
- lea si,ArpTabHwAdr[di]
- mov di,[bx].dPtrPhys
- mov cx,cs:Hlen
- rep movs byte ptr es:[hEthDst],cs:[ArpTabHwAdr]
- cmp di,di ; zero (found) return
- ArpPutHwRet:
- sti
- ret
- ArpPutHwDst endp
-
-
-
- ;************************************************************************
- ;* ArpPutNew
- ;*
- ;* Input: DX = first word of IP # (saved)
- ;* AX = second word of IP # (saved)
- ;* SI = pointer to physical address (saved)
- ;* Destroys: CX, DI, ES, flags
- ;************************************************************************
-
- ArpPutNewSiHl proc near
- assume ds:nothing
- mov si,[bx].dPtrPhys
- add si,cs:Hlen
- ArpPutNew:
- PushfDI
-
- call ArpFindIp ; already have IP # ?
- jz ArpPutHere ; - yes, update hw addr
- ArpPutWrap: ; - no, find next slot
- mov di,cs:ArpPutSlot
- add di,2 ; advance index two bytes
-
- cmp di,2*ARPSLOTS ; end of arp table?
- jb ArpPut
-
- mov di,ARPMYIDX+2 ; preserve bcast mappings
- ArpPut: ; (first slots)
- if TBLBUILD
- push si
- mov si,di
- add si,2
- cmp si,2*ARPSLOTS
- jb ArpPut2
- mov si,ARPMYIDX+2
- ArpPut2:
- mov cx,cs:ArpTabTr[di]
- sub cx,cs:ArpTabTr[si]
- js ArpPut3
- mov di,si ; use elder of next 2 slots
- ArpPut3:
- pop si
- endif ; TBLBUILD
- mov cs:ArpPutSlot,di
- mov cs:ArpTabIp1[di],dx ; put IP # into slot
- mov cs:ArpTabIp2[di],ax
- xor cx,cx ; clear other fileds
- mov cs:ArpTabFlags[di],cx
- mov cs:ArpTabSqDelay[di],cx
- ArpPutHere:
- call ArpPutHwAd ; put HW addr into slot
-
- PopfEI
- ret
- ArpPutNewSiHl endp
-
-
-
- ;************************************************************************
- ;* SendAndWait
- ;* Input: DS:BX = description buffer ptr (saved)
- ;* Output: Zero and CX = 0 if OK
- ;* non-zero and CX = errorcode if error
- ;* Destroys: AX, CX, DX, SI, DI, ES, flags
- ;************************************************************************
-
- SendAndWait proc near
- assume ds:nothing
- inc cs:InSendAndW
-
- mov si,[bx].dWaitEvent ; event to wait for
- or si,si ; no event to wait for?
- jz SendDontWait
-
- not si
- and cs:Events,si ; clear this event bit
- SendDontWait:
- not si
- push si
- if RFCC
- ; Do RFC1016 Source Quench Introduced Delay
-
- mov di,[bx].dSqDelay
- or di,di ; any SQ delay?
- jz SendNoSqDelay
-
- call HardwareTicks
- call DblShr10
- add di,ax
-
- test cs:ArgFlags,AVOID_HDWR
- jz SendSqLoop
- add di,55/2 ; round up
- SendSqLoop:
- call Something2Do ; wait a while
- call HardwareTicks
- call DblShr10
- cmp ax,di ; can we send it now?
- js SendSqLoop
- SendNoSqDelay:
- endif ; RFCC
- call SendRawPkt ; send packet part of buffer
-
- pop si
- test cs:Events,si ; got what we want?
- jz SendWait4Rep
- SendWaitOK:
- xor cx,cx
- SendWaitRet:
- dec cs:InSendAndW
- or cx,cx
- ret
-
-
- SendWait4Rep:
- mov cx,cs:SavedTicks
- mov di,[bx].dTickResend ; first resend time
- mov ax,cx
- add ax,di
- add ax,cs:LongerTimOut
-
- mov dx,cx
- add dx,cs:LongerTimOut
- add dx,[bx].dTickTimeout ; time out time
- WaitLoop:
- test cs:Events,si ; got what we want?
- jnz SendWaitOK
- SendChk:
- call Something2Do ; anything else to do?
- ChkTimeout:
- call CurrentTicks
- cmp cx,dx ; time out?
- jns SendTimedout
-
- cmp cx,ax ; time to resend?
- js WaitLoop
-
- shl di,1 ; double resend time
-
- cmp di,30*18
- jbe SendDouble
- mov di,30*18 ; max 30 seconds
- SendDouble:
- add ax,di ; next resend time
-
- push ax
- push dx
- push si
- push di
- call SendRawPkt ; send same packet again
- pop di
- pop si
- pop dx
- pop ax
- jmp short WaitLoop
-
- SendTimedout:
- mov dx,[bx].dTimOutMsg
- mov cx,SERRTIMOUT
- or dx,dx ; if no timeout msg
- jz SendWaitRet ; just return
-
- mov al,04 ; error code 4
- call PrTerminate ; print error msg in dx
- SendAndWait endp
-
-
-
- ;************************************************************************
- ;* SendRawPkt
- ;* Input: DS:BX = description buffer ptr (saved)
- ;* Destroys: AX, CX, DX, SI, DI, ES, flags
- ;************************************************************************
-
- SendRawPkt proc near
- assume ds:nothing
- if PINGCLIENT
- mov ax,[bx].dPktLen
- add ax,8+4+12 ; preamble, crc, intergap
- cli
- add cs:EchoLoad+2,ax
- adc cs:EchoLoad,0
- sti
- endif ; PINGCLIENT
- mov ax,3000 ; # of retries if temporary err
- SendRawAgain:
- push ax
- push bx
- push bp
- mov si,[bx].dPtrPhys ; get start of packet
- mov cx,[bx].dPktLen ; and its length
-
- mov ah,4 ; send packet to
- push ds ; packet driver
- int_pkt
- pop ds
-
- pop bp
- pop bx
- pop ax
-
- jc SendBadPkt ; any errors?
- if DEBUG
- mov ax,0aaaah ; trash regs
- mov cx,ax
- mov dx,ax
- mov si,ax
- mov es,ax
- endif ; DEBUG
- ret
-
- SendBadPkt:
- cmp dh,CANT_SEND ; can't send?
- jne SendPermBad
- SendTempBad:
- dec ax ; have we tried enough times?
- jnz SendRawAgain
- SendPermBad:
- stc
- call print_error ; display explanation
-
- mov al,03 ; error code 3
- call Terminate
- SendRawPkt endp
-
-
-
- ;************************************************************************
- ;* SendArpReq
- ;*
- ;* Input: DX = first word of IP # (saved)
- ;* AX = second word of IP # (saved)
- ;* DS:BX = IP description buffer ptr (saved)
- ;* Output: Zero and CX = 0 if OK
- ;* non-zero and CX = errorcode if error
- ;* Destroys: CX, SI, DI, ES, flags
- ;************************************************************************
-
- SendArpReq proc near
- assume ds:nothing
- push dx ; dx,ax has IP # to arp for
- push ax
- push bx ; save IP descr addr
- push ds
-
- call BufAlloc ; get a buffer
- mov cx,SERRNOBUF
- jz SendArpRet
-
- call MakeSendDescr ; set up descriptor
-
- mov di,[bx].dPtrPhys
- mov si,offset ArpTabHwAdr ; put Ether broadcast dst
- mov cx,cs:Hlen
- SendArpL1:
- movs byte ptr es:[hEthDst],cs:[ArpTabHwAdr]
- loop SendArpL1
-
- call PutPhysSrc ; put Ether src addr
-
- push di
- mov si,offset ArpFixedPart ; copy in static arp part
- mov cx,ArpFixedLen-2*MAX_ADDR_LEN
- add cx,cs:H2len
- SendArpL2:
- movs byte ptr es:[hEthSrc],byte ptr cs:[ArpFixedPart]
- loop SendArpL2
-
- sub di,[bx].dPtrPhys ; calculate packet length
- mov [bx].dPktLen,di
-
- pop di ; compute addr to dst IP #
- add di,aArpOffsSrcIp
- add di,cs:H2Len
-
- mov [di+4],dx ; IP # to arp for
- mov [di+4+2],ax
-
- sub di,cs:Hlen ; fill in My IP #
- mov dx,cs:MyIpNr
- mov ax,cs:MyIpNr+2
- mov [di],dx
- mov [di+2],ax
-
- pop es
- pop si ; IP descr addr
- push si
- push es
-
- mov cx,es:[si].dTimOutMsg ; use application timeout msg
- mov [bx].dTimOutMsg,cx
-
- mov cx,es:[si].dTickTimeout
- cmp cx,3*18 ; limit arp timeout
- jbe SendArpOkTim
- mov cx,3*18 ; to 3 seconds or less
- SendArpOkTim:
- mov [bx].dTickTimeout,cx
-
- mov [bx].dWaitEvent,GOT_ARPREPLY
-
- call SendAndWait ; send arp request packet
-
- call BufRelease ; release buffer
- SendArpRet:
- or cx,cx
- pop ds ; restore IP descr addr
- pop bx
-
- pop ax ; restore IP # we ARPed for
- pop dx
- ret
- SendArpReq endp
-
-
-
- ;************************************************************************
- ;* ARP receiver (branched off from general receiver) *
- ;************************************************************************
-
- assume ds:nothing
-
- ArpRecvCont:
- SHOW_EVENT 'C'
- push di
- mov ax,[bx].dPtrPhys
- call ArpFindHwHl ; Hw Src addr in ARP table?
- pop si
- jnz ArpRecNew
-
- cmp di,ARPMYIDX ; ignore pkts from bcast or me
- jbe ArpRecRet ; (also helps NDIS)
- ArpRecNew:
- lea di,[si].iArpMyHwAd
- mov cx,[si].iArpOp ; ARP reply?
-
- mov si,di
- add di,cs:Hlen
- mov dx,word ptr [di] ; get HIS (!) IP # and keep
- mov ax,word ptr [di+2] ; it for a long while
-
- add di,4
- cmp di,[bx].dPktEnd ; big enough to be arp pkt?
- ja ArpRecRet
-
- ; The following test is not according to the ARP RFC. The reason for this
- ; divergence is that if we follow the RFC algorithm, anybody that momentarily
- ; uses a wrong IP number would disrupt our communication with the original
- ; owner of that IP number. This would be true even if the program he uses
- ; is nice (NCSA Telnet for example) and starts by sending an ARP packet for
- ; itself to see if anybody will answer (a very good thing to do and this
- ; package does so too).
- ;
- ; We do obey an unsolicited arp reply immediately, other cases of changed
- ; hardware address will be taken care of in a minute automagically by the
- ; arp table ageing mechanism, so this package should do well even when moving
- ; hosts in a proxy arp environment.
-
- cmp cx,0200h ; ARP reply?
- jne ArpNotReply
-
- call ArpFindIp ; if he is in our ARP table we
- jnz ArpNotThere
-
- SHOW_EVENT 'D'
- call ArpPutHwAd ; should update his HW addr
- ArpNotThere:
- ArpNotReply:
- mov di,si
- add di,cs:H2Len
- mov cx,[di+4]
- cmp cx,cs:MyIpNr ; is this arp for me?
- jne ArpRecTbl
- mov cx,[di+6]
- cmp cx,cs:MyIpNr+2
- jne ArpRecTbl
-
- add di,8
- cmp di,[bx].dPktEnd
- ja ArpRecRet
-
- SHOW_EVENT 'E'
- call ArpPutNew ; - yes, put his IP # and HW
- ; addr into the ARP table
- mov di,[bx].dPtrIp
- cmp [di].iArpOp,0100h ; arp request?
- je ArpRecReq
-
- or cs:Events,GOT_ARPREPLY ; - no, probably a wanted reply
- ArpRecTbl:
-
- if TBLBUILD
- test cs:ArgFlags,MAKE_TABLE
- jnz ArpRecBld
- endif ; TBLBUILD
-
- ArpRecRet:
- jmp IpRecRet
-
- ArpRecKeepBuf:
- jmp IpRecKeepBuf
-
- if TBLBUILD
- ArpRecBld:
- cmp cs:FreeBufs.lBufsAvail,NBUFS/4 ; prevent starving
- jbe ArpRecRet
-
- test cs:GenFlags,TBL_READY
- jz ArpRecRet
-
- SHOW_EVENT 'F'
- mov si,offset TblToDo
- call AddToList ; collect adress info
- jmp short ArpRecKeepBuf
- endif ; TBLBUILD
-
- ArpRecReq:
- SHOW_EVENT 'G'
- mov [di].iArpOp,0200h ; put arp reply code
-
- mov di,si
- push di
- push ds
- pop es
- mov cx,cs:Hlen
- add cx,4
- add di,cx
- rep movsb ; mov arp dst to arp src
- pop di
-
- mov si,offset MyHwAd
- mov cx,cs:Hlen
- ArpRecReqL1:
- movs byte ptr es:[hEthSrc],cs:[MyHwAd] ; put in my HW addr as arp src
- loop ArpRecReqL1
-
- mov cx,cs:MyIpNr
- mov [di],cx ; put my IP # to arp src
- mov si,cs:MyIpNr+2
- mov [di+2],si
-
- cmp dx,cx ; is he stealing my IP # ?
- jne ArpRecNoSteal
- cmp ax,si
- jne ArpRecNoSteal
-
- mov dx,0ffffh ; - yes, tell everybody by
- mov ax,dx ; broadcasting my reply
- ArpRecNoSteal:
- mov [bx].dWaitEvent,0
-
- call ArpPutHwDst ; put dst Ether addr fr DX,AX
-
- call PutPhysSrc ; put src Ether addr
-
- mov word ptr [di],0608h ; arp prot
-
- mov si,offset SendToDo ; put buffer on the send list
- call AddToList ; for non-interrupt handling
- jmp short ArpRecKeepBuf
-
- ;========================================================================
- ; endinclude
-