home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
p
/
pcrte224.zip
/
SOURCE.ZIP
/
IP.INC
< prev
next >
Wrap
Text File
|
1992-06-09
|
29KB
|
904 lines
;;*************************************************************************
;; ip.inc ip.inc
;;*************************************************************************
;;
;; Copyright (C) 1989 Northwestern University, Vance Morrison
;;
;;
;; Permission to view, compile, and modify for LOCAL (intra-organization)
;; USE ONLY is hereby granted, provided that this copyright and permission
;; notice appear on all copies. Any other use by permission only.
;;
;; Northwestern University makes no representations about the suitability
;; of this software for any purpose. It is provided "as is" without expressed
;; or implied warranty. See the copywrite notice file for complete details.
;;
;;*****************************************************************************
;;
;; Routines provided by this module
;;
;; IP_DECLARE name, router, dls, icmp
;; IP_DEFINE name
;; IP_R_READ name, code_label
;; IP_R_RETURN name
;; IP_R_SRC_in_SI_ES_out_AX_BX_const_CX_DX_BP_SI_DI_ES name
;; IP_R_BROAD_in_SI_ES_const_CX_DX_BP_SI_DI_ES name, broadcast
;; IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES name
;; IP_W_ACCESS_in_AX_BX_CX_DL_out_AX_DI_ES name
;; IP_W_WRITE_in_CX name
;; IP_COMPUTE_NET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES dls
;;
;; Variables Provided by this Module (READ ONLY!!!)
;;
;; ip_&name&_dls ;; 1..dls are the names of the IP_DL objects
;;
;;*****************************************************************************
;; IP packet header def
;; masks for the Flag field
IP_DONT_FRAG = 4000H
IP_MORE_FRAG = 2000H
SWAPPED_IP_DONT_FRAG = 40H
SWAPPED_IP_MORE_FRAG = 20H
ip STRUC ;; and IP packet
ip_ver_size DB ?
ip_tos DB ?
ip_length DW ?
ip_id DW ?
ip_frag DW ?
ip_ttl DB ?
ip_proto DB ?
ip_check DW ?
ip_src DD ?
ip_dst DD ?
ip ENDS
ip_data STRUC
ip_write_dst DD ?
ip_write_src DD ?
ip_write_off DW ?
ip_write_seg DW ?
ip_write_gate DW ?
ip_write_proto DB ?
ip_write_dl DB ?
ip_write_id DW ?
ip_packet DW (dl_ip_max_mtu/2 + 16) dup (0)
ip_header DW 32 dup (0)
ip_broadcast DB ?
ip_read_head DW ?
ip_read_jmp DW 32 dup (0)
ip_data ENDS
;;******************************************************************************
;; IP_DECLARE name, dls
;; IP_DECLARE declares a network ojbect that will route packets
;; using 'router' as its routing table to the Data Link objects
;; 1..dls.
;;
IP_DECLARE MACRO name, router, dls, icmp
.DATA
ip_&name&_dls = dls
ip_&name&_router = router
ip_&name&_icmp = icmp
global ip_&name&_data:ip_data
.CODE
IRP idx, <1,2,3,4,5,6,7,8>
if idx le ip_&name&_dls
IP_DECLARE_HELPER name, idx
endif
endm
global ip_&name&_read_packet:near
global ip_&name&_prot_unreach:near
global ip_&name&_w_access:near
global ip_&name&_w_write:near
global ip_&name&_real_define:near
ENDM
IP_DECLARE_HELPER MACRO name, dl
global ip_&name&_dl_&dl&_read_start:near
ENDM
;;*****************************************************************************
;; IP_DEFINE name
;; IP_DEFINE defines all of the data structures needed by IP and
;; initializes them.
;;
IP_DEFINE MACRO name
call ip_&name&_real_define
ENDM
IP_REAL_DEFINE MACRO name
local around, skip
.errb <name>
ifdef ip_&name&_dls
.DATA
ip_&name&_data ip_data <>
.CODE
ip_&name&_real_define:
jmp around ;; declare the 'this node' IP packet processor
ip_&name&_read_packet:
IP_PACKET_in_AX_BX_CX_ES name
RET
ip_&name&_prot_unreach:
cmp ip_&name&_data.ip_broadcast, 0
jnz skip
mov SI, BX
IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES name
ICMP_ERROR_in_SI_ES %ip_&name&_icmp, ICMP_UNREACHABLE, ICMP_UNREACH_PROTO, name
skip:
RET
ip_&name&_w_access:
IP_REAL_W_ACCESS_in_AX_BX_CX_DL_out_AX_DI_ES name
RET
ip_&name&_w_write:
IP_REAL_W_WRITE_in_CX name, %ip_&name&_w_write
RET
around:
;; initialize the jump table
mov AX, DS ;; initialize jump table
mov ES, AX
mov DI, offset ip_&name&_data.ip_read_jmp
mov AX, offset ip_&name&_prot_unreach
mov CX, 32
rep
stosw
;; do all per DL initilization
IRP idx, <1,2,3,4,5,6,7,8>
if idx le ip_&name&_dls
IP_INIT_DL name, idx
endif
endm
RET
endif
ENDM
;;*****************************************************************************
;; IP_R_READ name, proto, code_label
;; IP_READ declares that the code starting at 'code_label' should
;; be called when a IP packet with protocol 'proto' is read in
;; The data in the IP packet is passed to the object in BX:ES the
;; protocol type in AX and the length of the data in CX.
;; When the code is done it should execute a RET instruction
;; If the source address is requires IP_R_SRC should be called
;;
IP_R_READ MACRO name, proto, code_label
.errb <code_label>
mov word ptr ip_&name&_data.ip_read_jmp+2*(proto mod 32), offset code_label
ENDM
;;*****************************************************************************
;; IP_R_SRC_in_SI_ES_out_AX_BX name
;; IP_R_SRC returns the source of the IP data packet pointed to by SI:ES
;; that was given to the IP_R_READ routine. The IP address is put in
;; AX,BX
;;
IP_R_SRC_in_SI_ES_out_AX_BX_const_CX_DX_BP_SI_DI_ES MACRO name
.errb <name>
push SI
IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES name
add SI, ip_src
mov AX, word ptr ES:[SI]
mov BX, word ptr ES:[SI+2]
pop SI
ENDM
;;*****************************************************************************
;; IP_R_BROAD_in_SI_ES name, broadcast
;; IP_R_BROAD jumps to 'broadcast' if the IP packet pointed to by SI:ES
;; is a broadcast.
;;
IP_R_BROAD_in_SI_ES_const_CX_DX_BP_SI_DI_ES MACRO name, broadcast
.errb <name>
cmp ip_&name&_data.ip_broadcast, 0
jnz broadcast
ENDM
;;*****************************************************************************
;; IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES name
;; IP_R_HEADER_in_SI_ES_out_DI returns the IP header for the packet pointed
;; to by SI:ES. This routine must only be called in the routine specified
;; in R_READ. (this is meant so that you can send ICMP packets)
;;
IP_R_HEADER_in_ES_out_SI_const_BX_CX_DX_BP_DI_ES MACRO name
.errb <name>
mov SI, word ptr ip_&name&_data.ip_read_head ;; save header pointer
ENDM
;;*****************************************************************************
;; IP_W_ACCESS_in_AX_BX_CX_DL_out_AX_DI_ES name
;; IP_W_ACCESS retrieves a buffer to write the data for an IP packet.
;; AX,BX holds the destination IP address of the packet and DL holds
;; the protocol number of the packet. The output buffer is returned
;; in DI:ES. This routine might fail if CX exceeds the MTU of the
;; interface. Thus it is only guarenteed to succeed when
;; CX <= dl_ip_min_mtu. AX is 0 if everything was successful.
;;
IP_W_ACCESS_in_AX_BX_CX_DL_out_AX_DI_ES MACRO name
local call_OK
CALL ip_&name&_w_access
ENDM
;;*****************************************************************************
;; IP_REAL_W_ACCESS is the real provider of the W_ACCESS service.
;;
IP_REAL_W_ACCESS_in_AX_BX_CX_DL_out_AX_DI_ES MACRO name
local done, jmp_table, fail, return, forme
.errb <name>
.DATA ;; declare the jump table
jmp_table dw done ;; dl 0 is undefined
IRP idx, <1,2,3,4,5,6,7,8>
if idx le ip_&name&_dls
IP_INIT_DL_JMP_TAB name, idx, write_access
endif
endm
.CODE
mov word ptr ip_&name&_data.ip_write_dst, AX ;; save address
mov word ptr ip_&name&_data.ip_write_dst+2, BX
mov byte ptr ip_&name&_data.ip_write_proto, DL
mov BP, CX ;; save CX
mov CX, BX
IP_COMPUTE_NET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES %ip_&name&_dls
ROUTE_FIND_in_AX_BX_CX_out_AX_DL_const_BP_ES %ip_&name&_router, forme, fail
mov byte ptr ip_&name&_data.ip_write_dl, DL
mov word ptr ip_&name&_data.ip_write_gate, AX
xor DH, DH ;; set up jump to proper DL
shl DX, 1
mov DI, offset jmp_table
add DI, DX
jmp [DI]
forme:
fail:
xor AX, AX
dec AX
jmp return
;; the above jump goes to one of the code fragments below
IRP idx, <1,2,3,4,5,6,7,8>
if idx le ip_&name&_dls
IP_INIT_DL_LABEL name, idx, write_access
IP_SAVE_SRC name, idx
mov CX, BP ;; restore CX
cmp CX, dl_ip_min_mtu ;; enforce length restriction
ja fail
DL_IP_W_ACCESS_in_CX_out_DI_ES_const_CX_BP idx, fail
jmp done
endif
endm
;; the above code does NOT fall through
done:
mov word ptr ip_&name&_data.ip_write_off, DI
mov word ptr ip_&name&_data.ip_write_seg, ES
add DI, size ip
xor AX, AX
return:
ENDM
IP_SAVE_SRC MACRO name, dl
mov AX, word ptr dl_ip_&dl&_ip
mov word ptr ip_&name&_data.ip_write_src, AX
mov AX, word ptr dl_ip_&dl&_ip+2
mov word ptr ip_&name&_data.ip_write_src+2, AX
ENDM
;;*****************************************************************************
;; IP_W_WRITE_in_CX name
;; IP_W_WRITE tells the IP interface to send the PACKET that is been
;; loaded into the buffer DI:ES. The length of the packet is in CX
;; note that this IP level does NOT support fragmentation, so CX better
;; be less than the dl_ip_min_mtu
;;
IP_W_WRITE_in_CX MACRO name
.errb <name>
CALL ip_&name&_w_write
ENDM
;;*****************************************************************************
;;
;; IP_REAL_W_WRITE_in_CX is the real provider of the W_WRITE service.
;; it is identical in function to IP_W_WRITE.
;;
IP_REAL_W_WRITE_in_CX MACRO name
local done, jmp_table
.errb <name>
.DATA ;; declare the jump table
jmp_table dw done ;; dl 0 is undefined
IRP idx, <1,2,3,4,5,6,7,8>
if idx le ip_&name&_dls
IP_INIT_DL_JMP_TAB name, idx, write_it
endif
endm
.CODE
les DI, dword ptr ip_&name&_data.ip_write_off
mov AX, 0045H ;; byte swapped length = 5 version = 4 tos = 0
mov BX, AX
stosw
add CX, size ip
mov AX, CX ;; the length
xchg AL, AH
add BX, AX
stosw
mov AX, word ptr ip_&name&_data.ip_write_id
adc BX, AX
stosw
inc AX
mov word ptr ip_&name&_data.ip_write_id, AX
mov AX, 0
stosw
mov AL, 100 ;; the time to live
mov AH, byte ptr ip_&name&_data.ip_write_proto
adc BX, AX
stosw
inc DI
inc DI ;; skip checksum
mov SI, offset ip_&name&_data.ip_write_src
lodsw
adc BX, AX
stosw
lodsw
adc BX, AX
stosw
mov SI, offset ip_&name&_data.ip_write_dst
lodsw
adc BX, AX
stosw
lodsw
adc BX, AX
adc BX, 0
stosw
sub DI, 10
not BX
mov AX, BX
stosw
;; set out the packet
mov AX, word ptr ip_&name&_data.ip_write_gate
xor DH, DH ;; set up jump to proper DL
mov DL, byte ptr ip_&name&_data.ip_write_dl
shl DX, 1
mov DI, offset jmp_table
add DI, DX
jmp [DI]
;; the above jump goes to one of the code fragments below
IRP idx, <1,2,3,4,5,6,7,8>
if idx le ip_&name&_dls
IP_INIT_DL_LABEL name, idx, write_it
DL_IP_W_WRITE_in_AX_CX_const_BP idx
jmp done
endif
endm
;; the above code does NOT fall through
done:
ENDM
;;*****************************************************************************
;; IP_INIT_DL name, dl
;; IP_INIT_DL initializes the data link interface 'dl'
IP_INIT_DL MACRO name, dl
local around
.errb <dl>
jmp around
;; This stuff can be compiled seperately
; IP_DL_PACKET_in_BX_ES name, dl
; DL_IP_R_RETURN dl
;; This does NOT fall through
around:
mov AX, DS ;; add the route for each directly connected interface
mov ES, AX
xor CX, CX
mov SI, offset dl_ip_&dl&_net
mov DI, offset dl_ip_&dl&_ip
ROUTE_ADD_in_CX_SI_DI_ES_const_DI_ES %ip_&name&_router
DL_IP_R_READ dl, ip_&name&_dl_&dl&_read_start ;; schedule the read
ENDM
;;*****************************************************************************
;; IP_DL_PACKET_in_BX_ES name, read_dl
;; IP_DL_PACKET_in_BX_ES does the proessing of a packet that came from
;; a data link interface BX:ES points to the begining of the IP packet.
;; this is the routeine that does the routing and if it for this node
;; calls IP_PACKET_in_BX_ES
;;
IP_DL_PACKET_in_BX_ES MACRO name, read_dl
local forme, jmp_table, drop, ip_write_sav, ip_write_gate, ip_write_size
local ip_write_sav_seg
local drop_ttl, drop_route, broad_forme, redirect, continue_forme, ip_ok
.errb <read_dl>
.DATA ;; declare the jump table
jmp_table dw drop ;; dl 0 is undefined
IRP idx, <1,2,3,4,5,6,7,8>
if idx le ip_&name&_dls
IP_INIT_DL_JMP_TAB name, idx, read_dl&_write_start
endif
endm
ip_write_size DW ?
ip_write_sav DW ?
ip_write_sav_seg DW ?
ip_write_gate DW ?
.CODE
ip_&name&_dl_&read_dl&_read_start:
mov ip_write_sav, BX
mov CX, word ptr ES:[BX+ip_length] ;; make sure length reasonable
xchg CH, CL ;; byte swap
cmp CX, dl_ip_&read_dl&_mtu
ja drop
mov ip_write_size, CX
DL_IP_IS_BROADCAST_in_BX_ES_const_AX_BX_CX_DX_BP_DI_ES read_dl
jnz broad_forme
mov BP, BX ;; save BX
mov AX, word ptr ES:[BX+ip_dst] ;; get an IP packet
mov BX, word ptr ES:[BX+ip_dst+2]
mov CX, BX
IP_COMPUTE_NET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES %ip_&name&_dls
ROUTE_FIND_in_AX_BX_CX_out_AX_DL_const_BP_ES %ip_&name&_router, forme, drop_route
mov word ptr ip_write_gate, AX
mov SI, BP ;; restore pointer
IP_DEC_TTL_in_SI_ES_const_BX_CX_DX_BP_SI_DI_ES drop_ttl
xor DH, DH ;; set up jump to proper DL
shl DX, 1
mov DI, offset jmp_table
add DI, DX
jmp [DI] ;; jump to proper DL
;; the above jump goes to one of the code fragments below
IRP idx, <1,2,3,4,5,6,7,8>
if idx le ip_&name&_dls
IP_INIT_DL_LABEL name, idx, read_dl&_write_start
if idx eq read_dl
mov word ptr ip_write_sav_seg, ES
endif
IP_DL_TEST_BROAD_in_AX idx, drop
mov BP, word ptr ip_write_sav
IP_SEND_PACKET_in_BP_ES name, read_dl, idx, ip_write_gate
if idx eq read_dl
IP_DL_TEST_FLAGS idx, NO_REDIRECT
jnz drop
mov SI, word ptr ip_write_sav
mov ES, word ptr ip_write_sav_seg
IP_DL_ADDRESS_out_AX_const_BX_CX_DX_BP_SI_DI idx
mov BX, word ptr ip_write_gate
jmp redirect
else
jmp drop
endif
endif
endm
;; the above code does NOT fall through
drop_route:
mov SI, BP
ICMP_ERROR_in_SI_ES %ip_&name&_icmp, ICMP_UNREACHABLE, ICMP_UNREACH_HOST, name
jmp drop
redirect:
ICMP_REDIRECT_in_AX_BX_SI_ES %ip_&name&_icmp, ICMP_REDIRECT_HOST, name
jmp drop
drop_ttl:
ICMP_ERROR_in_SI_ES %ip_&name&_icmp, ICMP_TIME, ICMP_TIME_TTL, name
jmp drop
broad_forme:
mov ip_&name&_data.ip_broadcast, 1
jmp continue_forme
forme:
mov ip_&name&_data.ip_broadcast, 0
continue_forme:
mov BX, ip_write_sav
mov CX, ip_write_size
DL_IP_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES read_dl, ip_ok
mov SI, BX
mov DI, offset ip_&name&_data.ip_packet
mov DX, DS
mov ES, DX
DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES read_dl
mov BX, offset ip_&name&_data.ip_packet
mov CX, ip_write_size
ip_ok:
CALL ip_&name&_read_packet
drop:
ENDM
;; this macro simply returns the first two bytes of IP address of 'mydl'
IP_DL_ADDRESS_out_AX_const_BX_CX_DX_BP_SI_DI MACRO mydl
mov AX, word ptr dl_ip_&mydl&_ip
ENDM
;; this macro tests if the flag bit 'mybit' of the DL_IP 'name' is set
IP_DL_TEST_FLAGS MACRO name, mybit
test dl_ip_&name&_flags, mybit
ENDM
;; This macro tests if the dest AX should be droped because it is a broadcast
IP_DL_TEST_BROAD_in_AX MACRO name, drop
local forward
cmp AX, word ptr dl_ip_&name&_broad+2 ;; should we forward
jnz forward
test dl_ip_&name&_flags, NO_DIR_BROAD
jnz drop
forward:
ENDM
;;*****************************************************************************
;; IP_INIT_DL_LABEL generates a code lable for use in a jump table for
;; 'name', 'dl'. 'suffix' is a unique suffix
;;
IP_INIT_DL_LABEL MACRO name, dl, suffix
ip_&name&_dl_&dl&_&suffix:
ENDM
;;*****************************************************************************
;; IP_INIT_DL_JMP_TAB generates the table entry for the entry 'name', 'dl'
;; 'suffix' is a unique suffix.
;; This is meant for use in a .DATA section
;;
IP_INIT_DL_JMP_TAB MACRO name, dl, suffix
dw ip_&name&_dl_&dl&_&suffix
ENDM
;;****************************************************************************
;; IP_SEND_PACKET sends the packet pointed to by BP:ES of from the
;; DL 'read_dl' to the dl 'write_dl'. 'gate' is an address that contains
;; the last two bytes of the IP address. This is the routine that handles
;; IP fragmentation
;;
IP_SEND_PACKET_in_BP_ES MACRO name, read_dl, write_dl, gate
local done, frag_loop, size_ok, fragment, ip_head_len
.DATA
ip_head_len DW ?
.CODE
mov CX, ES:[BP+ip_length]
xchg CH, CL
if dl_ip_&read_dl&_mtu gt dl_ip_&write_dl&_mtu ;;is fragmenting EVER needed
cmp CX, dl_ip_&write_dl&_mtu
ja fragment
endif
DL_IP_W_ACCESS_in_CX_out_DI_ES_const_CX_BP write_dl, done
mov SI, BP ;; restore SI
mov BX, CX ;; save CX
DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES read_dl
mov CX, BX ;; restore CX
mov AX, word ptr gate
DL_IP_W_WRITE_in_AX_CX_const_BP write_dl
if dl_ip_&read_dl&_mtu gt dl_ip_&write_dl&_mtu ;;is fragmenting EVER needed
jmp done
fragment:
test byte ptr ES:[SI+ip_frag], SWAPPED_IP_DONT_FRAG ;; OK to fragment?
jnz done
;; compute the header size
xor CX, CX ;; make CX hold the size of the IP header
mov CL, ES:[BP+ip_ver_size]
and CL, 0FH
shl CL, 1
shl CL, 1
mov word ptr ip_head_len, CX
mov AX, DS ;; copy the header
mov ES, AX
mov SI, BP
mov DI, offset ip_&name&_data.ip_header
DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES read_dl
mov BP, SI ;; save SI
;; fix checksum so it is correct when ip_frag = ip_len = 0
mov AX, word ptr ip_&name&_data.ip_header.ip_check
add AX, word ptr ip_&name&_data.ip_header.ip_frag
adc AX, word ptr ip_&name&_data.ip_header.ip_length
adc AX, 0
mov word ptr ip_&name&_data.ip_header.ip_check, AX
frag_loop:
mov CX, dl_ip_&write_dl&_mtu ;; ask for biggest buffer
DL_IP_W_ACCESS_in_CX_out_DI_ES_const_CX_BP write_dl, done
mov DX, word ptr ip_head_len ;; copy the header
mov CX, DX
mov SI, offset ip_&name&_data.ip_header
shr CX, 1
rep
movsw
sub DI, DX ;; make DI point to begining of the packet
mov AX, word ptr ES:[DI+ip_frag]
xchg AH, AL
mov CX, word ptr ES:[DI+ip_length]
xchg CH, CL
cmp CX, dl_ip_&write_dl&_mtu ;; can we send it
jbe size_ok
mov CX, dl_ip_&write_dl&_mtu
sub CX, DX ;; subtract the IP header length
and CX, 0FFF8H ;; make multiple of 8
add CX, DX ;; add the IP header length
or AX, IP_MORE_FRAG ;; indicate not the last
size_ok:
xchg CH, CL
mov word ptr ES:[DI+ip_length], CX
xchg AH, AL
mov word ptr ES:[DI+ip_frag], AX
mov BX, word ptr ES:[DI+ip_check] ;; fix up checksum
sub BX, CX
sbb BX, AX
sbb BX, 0
mov word ptr ES:[DI+ip_check], BX
;; set up stuff for next round
xchg CH, CL
sub CX, DX ;; subtract the IP header length
mov BX, CX
shr BX, 1
shr BX, 1
shr BX, 1
mov AX, word ptr ip_&name&_data.ip_header.ip_frag
xchg AH, AL
add AX, BX
xchg AH, AL
mov word ptr ip_&name&_data.ip_header.ip_frag, AX
mov BX, word ptr ip_&name&_data.ip_header.ip_length
xchg BH, BL
sub BX, CX
xchg BH, BL
mov word ptr ip_&name&_data.ip_header.ip_length, BX
mov SI, BP ;; restore SI
add DI, DX ;; restore DI
mov BX, CX
add BX, DX ;; BX holds total Lenght
DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES read_dl
mov BP, SI ;; save SI
mov AX, word ptr gate
mov CX, BX
DL_IP_W_WRITE_in_AX_CX_const_BP write_dl
mov BX, word ptr ip_&name&_data.ip_header.ip_length
xchg BH, BL
cmp BX, word ptr ip_head_len
ja frag_loop
endif
done:
ENDM
;;******************************************************************************
;; IP_DEC_TTL_in_BX_ES
;; IP_DEC_TTL decrements the TTL of the IP packet pointed to by SI:ES
;; and jumps to 'drop' if the TTL has expired.
;;
IP_DEC_TTL_in_SI_ES_const_BX_CX_DX_BP_SI_DI_ES MACRO drop
mov AL, byte ptr ES:[SI+ip_ttl] ;; decrement ttl
sub AL, 01 ;; can't use dec (need carry)
jbe drop
mov byte ptr ES:[SI+ip_ttl], AL
mov AX, word ptr ES:[SI+ip_check] ;; fix up checksum
add AX, 1 ;; add 1 in 1's complement
adc AX, 0
mov word ptr ES:[SI+ip_check], AX
ENDM
;;******************************************************************************
;; IP_COMPUTE_NET
;; IP_COMPUTE_NET takes an IP address in AX,BX and given the ip address
;; and the dl list 1..dls and computes the network part of the IP address
;; and returns it in AX,BX.
;;
IP_COMPUTE_NET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES MACRO dls
local done
.errb <dls>
IRP idx, <8,7,6,5,4,3,2,1>
if idx le dls
IP_CHECK_SUBNET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES idx, done
endif
endm
IP_COMP_NET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES dls
done:
ENDM
;;******************************************************************************
;; IP_COMP_NET is like IP_COMPUTE_NET but it does its computation based ONLY
;; on the Class of the IP address (No subnet checking
;;
IP_COMP_NET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES MACRO dls
local class_A, class_B, class_C
test AL, 80h ;; normal IP network interpretation
jz class_A
test AL, 40h
jz class_B
jmp class_C
class_A:
xor AH, AH
class_B:
xor BL, BL
class_C:
xor BH, BH
ENDM
;;******************************************************************************
;; IP_CHECK_SUBNET
;; Check_subnet checks if the IP address in AX,BX matches the subnet of
;; the Data link interface 'dl'. If it does, it computes the network part
;; and returns it in AX,BX and then jumps to 'success'
;;
IP_CHECK_SUBNET_in_AX_BX_out_AX_BX_const_CX_DX_BP_SI_DI_ES MACRO dl, success
local fail, mask_it
.errb <success>
cmp AL, byte ptr dl_ip_&dl&_ip
jnz fail
test AL, 80H
jz mask_it
cmp AH, byte ptr dl_ip_&dl&_ip+1
jnz fail
test AL, 40H
jz mask_it
cmp BL, byte ptr dl_ip_&dl&_ip+2
jnz fail
mask_it:
and BX, word ptr dl_ip_&dl&_mask+2
jmp success
fail:
ENDM
;;*****************************************************************************
;; IP_PACKET_in_BX_ES name
;; IP_PACKET_in_BX_ES does all the proessing of a packet that is destined
;; for this node. BX:ES points to the begining of the IP packet.
;; AX holds the hardware protocol number and CX holds the length of
;; the packet.
;; Basicly this routine just dispatches it to the proper READ routine
;;
IP_PACKET_in_AX_BX_CX_ES MACRO name
local drop
.errb <name>
test word ptr ES:[BX+ip_frag], 3FFFH ;; if fragmented
jnz drop
xor AH, AH
mov AL, byte ptr ES:[BX+ip_proto] ;; load protocol
mov word ptr ip_&name&_data.ip_read_head, BX ;; save header pointer
xor DX, DX ;; compute the size of the header
mov DL, ES:[BX+ip_ver_size]
and DL, 0FH
shl DX, 1
shl DX, 1
sub CX, DX
add BX, DX
mov DX, AX ;; jump to proper routine
and DL, 1FH
shl DX, 1
mov SI, offset ip_&name&_data.ip_read_jmp
add SI, DX
jmp [SI] ;; note this is NOT a call,
;; so when the code returns
;; it will return to the caller
;; of this routine
drop:
ENDM
;;*****************************************************************************
;; IP_ASCII_in_SI_DI_ES_out_DI converts the IP address stored at SI:DS
;; to ASCII dot notation in the buffer ENDING at DI:ES. DI:ES returns the
;; begining of the string generated.
;;
IP_ASCII_in_SI_DI_ES_out_DI_const_BX_BP_ES MACRO
local ip_loop, ip_loop_done
std ;; count down
mov CX, 4
add SI, 3
dec DI
ip_loop:
lodsb
TO_ASCII_in_AL_DI_ES_out_DI_const_BX_CX_BP_SI_ES
dec CX
jz ip_loop_done
mov AL, '.'
stosb
jmp ip_loop
ip_loop_done:
inc DI
cld ;; count up again
ENDM
;;*****************************************************************************
;; TO_ASCII converts the number in AL to ascii (decimal) and puts the resulting
;; string in the buffer whose END is pointed to by DI:ES. DI points to the
;; BEGINING of the string when it is done. THIS ROUTINE ASSUMES THE DIRECTION
;; FLAG IS COUNTING DOWN
;;
TO_ASCII_in_AL_DI_ES_out_DI_const_BX_CX_BP_SI_ES MACRO
local loop_write
mov DL, 10
loop_write: ;; write in the number
xor AH, AH
idiv DL ;; AH = AL % 10 AL = AL / 10
xchg AL, AH
add AL, 48 ;; add ascii '0'
stosb
mov AL, AH
and AL, AL
jnz loop_write
ENDM