home *** CD-ROM | disk | FTP | other *** search
- ;;*************************************************************************
- ;; 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
-