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
/
ATALK.INC
< prev
next >
Wrap
Text File
|
1992-06-09
|
24KB
|
665 lines
;;*****************************************************************************
;; atalk.inc atalk.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.
;;
;;*****************************************************************************
;;
;; atalk.inc contains the DL_IP interface for the Appletalk protocols.
;; That is this module contains the code that wraps IP packets up into
;; appletalk packets before sending them out, and unencapsulates incomming
;; IP packets. As far has IP is concerned this is just a DL_IP interface
;;
;; This module assumes that there is a Apple localtalk card (or Flashcard)
;; installed in the computer and the Appletalk drivers have been loaded
;; (atalk.sys or atalk.exe). This module does not implement appletalk,
;; it just calls the driver with wrapped up IP packets.
;;
;; ATP_DECLARE name, interupt, task
;; ATP_DEFINE name, ip_address, ip_mask
;; ATP_DL_IP_R_READ name, code_label
;; ATP_DL_IP_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES name, ok
;; ATP_DL_IP_RETURN name
;; ATP_DL_IP_W_ACCESS_in_CX_out_DI_ES_const_CX_BP name, fail
;; ATP_DL_IP_W_WRITE_in_AX_CX_const_BP name, broadcast
;; ATP_DL_IP_IS_BROADCAST_in_BX_ES_const_AX_BX_CX_DX_BP_DI_ES name
;; ATP_DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES name
;;
;; Variables Provided by this module (READ ONLY!!!!)
;;
;; atp_&name&_declared 1 if this object has been declared
;; dl_ip_&name&_ip the IP address
;; dl_ip_&name&_mask the network mask
;; dl_ip_&name&_net the network (IP addr bitwize AND ip_mask)
;; dl_ip_&name&_broad the network broadcast address
;; dl_ip_&name&_flags A word exclusively for IP use
;; dl_ip_&name&_metric The interface metric (for routing use)
;; dl_ip_&name&_mtu the Maximum transmission unit (packet size)
;;
;;*****************************************************************************
;;*****************************************************************************
;; data storage needed by this module
include at.inc ;; FLASHCARD interface defs
atp_w_q_entry STRUC
atp_q_wparam DDPParams <> ;; this MUST be first
atp_q_end DW ?
atp_w_q_entry ENDS
atp_arp_entry STRUC
atp_NBP_lookup NBPparams <> ;; THIS MUST BE FIRST
atp_NBT_lookup NBPTuple <>
atp_ip_lookup db 4 DUP (0) ;; IP address to look up
atp_buff_lookup db 64 DUP (0) ;; buffer to hold NBP name to look up
atp_arp_entry ENDS
ATP_R_QUEUE_SIZE = 3 ;; size of the read queue
atp_r_q_entry STRUC
atp_q_rparam DDPParams <> ;; this must be first
atp_q_rbuff DB 590 DUP (0) ;; stuff needed for read
atp_r_q_entry ENDS
atp_data STRUC
atp_DDP_param_in DDPParams <>
atp_Info_param InfoParams <> ;; stuff needed for initilization
atp_NBP_myip NBPparams <>
atp_NBTE_myip NBPTabEntry <>
atp_r_queue DW ?
atp_data ENDS
;;*****************************************************************************
;; ATP_DECLARE name, interupt, task
;; ATP_DECLARE declares all the external defintions for the ATP object
;;
ATP_DECLARE MACRO name, interupt, task, wqueuesize, wbuffsize, num_zones
.errb <wbuffsize>
atp_&name&_declared = 1
atp_&name&_interupt = interupt
atp_&name&_task = task
atp_&name&_wqueuesize = wqueuesize
atp_&name&_wbuffsize = wbuffsize
atp_&name&_wbuff = name*100+1
atp_&name&_wqueue = name*100+2
atp_&name&_arptab = name*100+3
ifb <num_zones>
atp_&name&_nzones = 3
else
atp_&name&_nzones = num_zones
endif
atp_&name&_zbuff_len = atp_&name&_nzones*16+5
dl_ip_&name&_mtu = 578
.DATA
global dl_ip_&name&_ip:dword
global dl_ip_&name&_mask:dword
global dl_ip_&name&_net:dword
global dl_ip_&name&_broad:dword
global dl_ip_&name&_flags:word
global dl_ip_&name&_metric:word
global atp_&name&_data:atp_data
global atp_&name&_read:word
global atp_&name&_arps:atp_arp_entry
global atp_&name&_wbuffer:byte
global atp_&name&_rqueue:atp_r_q_entry
dl_ip_&name&_haddr = (atp_&name&_data.atp_Info_param.inf_network)
.CODE
global atp_&name&_continue:near
global atp_&name&_real_define:near
BUFF_DECLARE %atp_&name&_wbuff, wbuffsize, atp_&name&_wbuffer
QUEUE_DECLARE %atp_&name&_wqueue, wqueuesize, %(size atp_w_q_entry)
ARP_TAB_DECLARE %atp_&name&_arptab
ENDM
;;*****************************************************************************
;; ATP_DEFINE name, ip_address, ip_mask, fail
;;
ATP_DEFINE MACRO name, ip_address, ip_mask, zones, fail
ifdef atp_&name&_declared
mov AX, word ptr ip_address ;; copy over params
mov BX, 0FFFFH ;; Force our assumtion
mov word ptr dl_ip_&name&_ip, AX
mov word ptr dl_ip_&name&_net, AX
mov word ptr dl_ip_&name&_broad, AX
mov word ptr dl_ip_&name&_mask, BX
mov AX, word ptr ip_address+2
mov BX, word ptr ip_mask+2
mov word ptr dl_ip_&name&_ip+2, AX
mov word ptr dl_ip_&name&_mask+2, BX
and AX, BX
mov word ptr dl_ip_&name&_net+2, AX
not BX
or AX, BX
mov word ptr dl_ip_&name&_broad+2, AX
mov SI, offset zones
call atp_&name&_real_define
or AX, AX
jnz fail
endif
ENDM
ATP_REAL_DEFINE_in_SI_out_AX MACRO name
local start, around, null_read, declare_failure, no_zone, arp_init
local r_init, stat_success, fail
.errb <zones>
ifdef atp_&name&_declared
.DATA
atp_&name&_data atp_data <> ;; create storage needed
atp_&name&_read DW ?
atp_&name&_wbuffer DB atp_&name&_wbuffsize dup (0)
atp_&name&_rqueue atp_r_q_entry ATP_R_QUEUE_SIZE dup (<>)
dl_ip_&name&_ip DD ?
dl_ip_&name&_mask DD ?
dl_ip_&name&_net DD ?
dl_ip_&name&_broad DD ?
dl_ip_&name&_flags DW ?
dl_ip_&name&_metric DW ?
atp_&name&_arps atp_arp_entry atp_&name&_nzones dup (<>)
DW 0 ;; space for a final marker
DW 0 ;; space for a final marker
.CODE
jmp around
start:
ATP_TASK name
;; this does NOT fall through
null_read:
ATP_DL_IP_R_RETURN name
;; this does NOT fall through
around:
atp_&name&_real_define:
;; INITIALIZE THE APPLETALK STUFF
ATP_CHECK_DRIVER name, fail
mov BX, offset atp_&name&_data.atp_Info_param
mov word ptr [BX+inf_command], ATGetNetInfo
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES name
cmp word ptr [BX+inf_status], 0
jz stat_success
mov AL, byte ptr dl_ip_&name&_ip+3
or AL, 80H
mov byte ptr [BX+inf_nodeid], AL
mov BX, offset atp_&name&_data.atp_Info_param
mov word ptr [BX+inf_command], ATInit
mov word ptr [BX+inf_status], -1
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES name
cmp word ptr [BX+inf_status], 0
jnz fail
mov word ptr [BX+inf_command], ATGetNetInfo ;; try again
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES name
stat_success:
mov BX, offset atp_&name&_data.atp_DDP_param_in ;; close in case it
mov word ptr [BX+ddp_command], DDPCloseSocket ;; was open (that is
mov byte ptr [BX+ddp_socket], 72 ;; we did not reboot)
mov byte ptr [BX+ddp_type], 22
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES name
mov BX, offset atp_&name&_data.atp_DDP_param_in ;; open read/write sock
mov word ptr [BX+ddp_command], DDPOpenSocket
mov byte ptr [BX+ddp_socket], 72
mov byte ptr [BX+ddp_type], 22
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES name
cmp word ptr [BX+ddp_status], 0
jnz fail
;; Set up stuff for resolving IP addreses (ARP)
mov DX, atp_&name&_nzones
mov BX, offset atp_&name&_arps
arp_init:
mov word ptr [BX+nbp_command], 0 ;; mark the end of the arp list
mov word ptr [BX+nbp_status], -205
and byte ptr [SI], 1FH ;; cap length at 31
jz no_zone
mov word ptr [BX+nbp_command], NBPLookup+AsyncMask
mov byte ptr [BX+nbp_toget], 1
mov byte ptr [BX+nbp_interval], 1
mov byte ptr [BX+nbp_retry], 1
mov AX, BX
add AX, atp_NBT_lookup
mov word ptr [BX+nbp_buffptr.buff_off], AX
mov AX, DS
mov word ptr [BX+nbp_buffptr.buff_seg], AX
mov word ptr [BX+nbp_buffsize], 64
mov AX, DS
mov ES, AX
mov DI, BX
add DI, atp_buff_lookup+16
mov AX, 9 + ('I' * 256)
stosw
mov AX, 'P' + ('A' * 256)
stosw
mov AX, 'D' + ('D' * 256)
stosw
mov AX, 'R' + ('E' * 256)
stosw
mov AX, 'S' + ('S' * 256)
stosw
xor CX, CX
mov CL, [SI]
inc CX
rep
movsb
mov AX, DS
mov word ptr [BX+nbp_entptr.buff_seg], AX
mov AX, word ptr dl_ip_&name&_ip
mov word ptr [BX+atp_ip_lookup], AX
no_zone:
add BX, size atp_arp_entry
dec DX
jnz arp_init
mov word ptr [BX+nbp_command], 0 ;; mark the end of the arp list
ATP_DECLARE_IP_ADDRESS name, dl_ip_&name&_ip, fail
mov BX, offset atp_&name&_rqueue
mov atp_&name&_data.atp_r_queue, BX
mov CX, ATP_R_QUEUE_SIZE
r_init:
mov word ptr [BX+atp_q_rparam.ddp_command], DDPRead+AsyncMask
mov byte ptr [BX+atp_q_rparam.ddp_socket], 72
mov byte ptr [BX+atp_q_rparam.ddp_type], 22
mov word ptr [BX+atp_q_rparam.ddp_buffsize], 590
mov AX, BX
add AX, atp_q_rbuff
mov word ptr [BX+atp_q_rparam.ddp_buffptr+buff_off], AX
mov AX, DS
mov word ptr [BX+atp_q_rparam.ddp_buffptr+buff_seg], AX
mov word ptr [BX+atp_q_rparam.ddp_status], -1
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES name
add BX, size atp_r_q_entry
dec CX
jnz r_init
TASK_DEFINE %atp_&name&_task, start ;; start the task
mov word ptr atp_&name&_read, offset null_read
BUFF_DEFINE %atp_&name&_wbuff
QUEUE_DEFINE %atp_&name&_wqueue
ARP_TAB_DEFINE %atp_&name&_arptab
xor AX, AX ;; success return
RET
fail:
xor AX, AX ;; fail return
dec AX
RET
endif
ENDM
;;****************************************************************************
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES MACRO name
push ds
push es
int atp_&name&_interupt
pop es
pop ds
ENDM
;;******************************************************************************
;; DL_IP_R_READ name, code_label
;; DL_IP_R_READ declares that the code starting at 'code_label'
;; should be called whenever a IP packet is read. BX:ES is initilized
;; to the begining of the IP packet before 'code_lable' is called
;; The code at 'code_label' should call ARP_DL_IP_R_RETURN when it
;; is done processing the packet.
;; This procedure can only be called once per 'name'
;;
ATP_DL_IP_R_READ MACRO name, code_label
.errb <code_label>
mov word ptr atp_&name&_read, offset code_label
ENDM
;;******************************************************************************
;; DL_IP_R_CONT_in_BX_CX_ES name, ok
;; DL_IP_R_CONT determines if the packet returned by R_READ in BX:ES
;; of length CX is continuous. If it is it jumps to 'ok' otherwise
;; it just returns
;;
ATP_DL_IP_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES MACRO name, ok
.errb <ok>
jmp ok ;; it is always continuous
ENDM
;;******************************************************************************
;; DL_IP_R_RETURN name
;; DL_IP_R_RETURN should be executed by the READ routine to signal
;; that it is done processing the packet.
;;
ATP_DL_IP_R_RETURN MACRO name
.errb <name>
jmp atp_&name&_continue
ENDM
;;******************************************************************************
;; DL_IP_IS_BROADCAST_in_BX_ES name
;; DL_IP_IS_BROADCAST_in_BX_ES determines if the packet pointed to
;; by BX:ES is a broadcast and sets the zero flag if it is NOT a
;; broadcast
;;
ATP_DL_IP_IS_BROADCAST_in_BX_ES_const_AX_BX_CX_DX_BP_DI_ES MACRO name
.errb <name>
cmp AX, AX ;; fake it and always say it NOT a broadcast
ENDM
;;******************************************************************************
;; DL_IP_W_ACCESS returns a pointer to an output buffer for a IP (network)
;; packet. The buffer is at least min(CX, dl_ip_mtu) bytes long. The
;; pointer is returned in DI. If there is no buffer available
;; this routine jumps to 'no_buffer'
;;
ATP_DL_IP_W_ACCESS_in_CX_out_DI_ES_const_CX_BP MACRO name, no_buffer
local dequeued, dequeue_loop
;; release the entries of any packets that have been sent
dequeue_loop:
QUEUE_HEAD_out_SI_const_AX_BX_CX_DX_BP_DI_ES %atp_&name&_wqueue, dequeued
cmp [SI+atp_q_wparam+ddp_status], 0
jg dequeued
mov DI, [SI+atp_q_end]
BUFF_FREE_in_DI_const_AX_BX_CX_DX_BP_SI_DI_ES %atp_&name&_wbuff
QUEUE_DEQUEUE_in_SI_const_AX_BX_CX_DX_BP_DI_ES %atp_&name&_wqueue
jmp dequeue_loop
dequeued:
;; check if there is space for the next one to go out
BUFF_CHECK_in_CX_out_SI_DI_const_BX_CX_DX_BP_ES %atp_&name&_wbuff, no_buffer
mov DI, SI
mov SI, DS
mov ES, SI
ENDM
;;******************************************************************************
;; DL_IP_W_WRITE_in_AX_CX name, broadcast
;; DL_IP_W_WRITE actually signals the link layer to write a packet to the
;; network. The packet is assumed to be in the buffer returned by
;; DL_IP_W_ACCESS. CX is the length of the packet to send. AX holds the
;; last two bytes of the IP address to send the packet to. (notice we are
;; assuming a host portion of less than 16 bits). if 'broadcast' is not
;; blank, then the packet is written to the broadcast address. AX is
;; ignored in this case
;;
ATP_DL_IP_W_WRITE_in_AX_CX_const_BP MACRO name, broadcast
local done, got_haddr, wait_loop
ATP_ARP_GET_in_AX_out_SI_const_CX_BP_DI_ES name, done
mov DX, SI ;; save hardware address
BUFF_CHECK_in_CX_out_SI_DI_const_BX_CX_DX_BP_ES %atp_&name&_wbuff, done
mov BX, DI
QUEUE_ENQUEUE_out_DI_const_BX_CX_DX_BP_SI_ES %atp_&name&_wqueue, done
xchg BX, DI
BUFF_GET_in_DI_const_AX_BX_CX_DX_BP_SI_DI_ES %atp_&name&_wbuff
mov [BX+atp_q_end], DI
mov [BX+atp_q_wparam+ddp_buffptr+buff_off], SI
mov [BX+atp_q_wparam+ddp_buffsize], CX
mov word ptr [BX+atp_q_wparam.ddp_command], DDPWrite+AsyncMask
mov AX, DS
mov word ptr [BX+atp_q_wparam.ddp_buffptr+buff_seg], AX
mov byte ptr [BX+atp_q_wparam.ddp_socket], 72
mov byte ptr [BX+atp_q_wparam.ddp_type], 22
mov word ptr [BX+atp_q_wparam.ddp_status], -1
mov SI, DX
mov AX, [SI] ;; set hardware address
mov word ptr [BX+atp_q_wparam.ddp_addr.network], AX
mov AX, [SI+2]
mov word ptr [BX+atp_q_wparam.ddp_addr.nodeid], AX
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES name
done:
ENDM
;;******************************************************************************
;; DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI interface
;; DL_IP_COPY_in_CX_SI_DI_ES copys a packet from the input buffer (pointed
;; to by SI and the segement register given in IF_DECLARE) to an output
;; buffer (pointed to by DI and dest_reg) of length CX. It assumes the
;; output buffer is contiguous. (and the caller shouldn't care if the
;; input buffer is contiguous) COPY updates the pointers SI and DI
;; to the end of the packet, and COPY could be called again if CX is not
;; the total packet length (Note that CX MUST be even if you care about
;; SI, and DI being updated properly)
;;
ATP_DL_IP_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES MACRO name
.errb <name>
inc CX
shr CX, 1
rep
movsw
ENDM
;;******************************************************************************
;; ATP_TASK is the read task that reads the next packet from the interface
;; and dispatches it to the next higher protocol layer
;;
ATP_TASK MACRO name
local done, inside
.errb <name>
.errb <task>
mov BX, atp_&name&_data.atp_r_queue
add BX, size atp_r_q_entry
cmp BX, offset atp_&name&_rqueue + ((size atp_r_q_entry)*ATP_R_QUEUE_SIZE)
jb inside
mov BX, offset atp_&name&_rqueue
inside:
mov atp_&name&_data.atp_r_queue, BX
cmp [BX+atp_q_rparam.ddp_status], 0
jg done ;; no packet yet
jl atp_&name&_continue ;; error, resubmit the read
mov CX, [BX+atp_q_rparam.ddp_buffsize]
add BX, atp_q_rbuff
mov AX, DS
mov ES, AX
jmp word ptr atp_&name&_read
atp_&name&_continue:
mov BX, atp_&name&_data.atp_r_queue
mov word ptr [BX+atp_q_wparam.ddp_buffsize], 590
mov word ptr [BX+atp_q_wparam.ddp_status], -1
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES name
done:
TASK_RETURN %atp_&name&_task
ENDM
;;*****************************************************************************
;; ATP_ARP_GET finds the hardware address for the IP address with the last
;; two bytes in AX, and puts a pointer to the hardware address in SI.
;; This routine jumps to 'fail' if it cannot find the hardware address
;; (for ATP a hardware address is a AddrBlk structure)
;;
ATP_ARP_GET_in_AX_out_SI_const_CX_BP_DI_ES MACRO name, fail
local no_reply, chkstatus, arp_loop, done
.errb <fail>
ARP_TAB_GET_in_AX_out_SI_const_AX_BX_CX_BP_DI_ES %atp_&name&_arptab
jz done ;; got the address
;; set up the arp calls
mov BX, offset atp_&name&_arps
chkstatus:
cmp [BX+nbp_status], 0
jg fail
jnz no_reply
dec word ptr [BX+nbp_status]
mov DX, AX ;; save AX
mov AX, DS
mov ES, AX
mov SI, BX ;; save BX
mov BX, word ptr [BX+atp_ip_lookup+2]
mov AX, word ptr dl_ip_&name&_ip
LOG_PRINT_INET_in_AX_BX %mylog,L_ATALK,L_DEBUG,<Localtalk arp reply for IP address >
xchg BX, SI ;; restore BX, save AX
add BX, atp_NBT_lookup.ent_address
mov AX, [BX]
xchg AH, AL
LOG_PRINT_REG_HEX %mylog,L_ATALK,L_DEBUG,<Locatalk address Net >, AX
mov AX, [BX+2]
LOG_PRINT_REG_HEX %mylog,L_ATALK,L_DEBUG,<Locatalk address socket:node >, AX
mov AX, SI ;; restore AX
ARP_TAB_ADD_in_AX_BX_ES_out_SI_const_BX_DX_BP_DI_ES %atp_&name&_arptab
sub BX, atp_NBT_lookup.ent_address
cmp DX, word ptr [BX+atp_ip_lookup+2]
jz done ;; a hit!!
mov AX, DX
no_reply:
add BX, size atp_arp_entry
cmp [BX+nbp_command], 0
jnz chkstatus
mov BX, word ptr dl_ip_&name&_ip
xchg AX, BX
LOG_PRINT_INET_in_AX_BX %mylog,L_ATALK,L_DEBUG,<Localtalk arp lookup >
mov AX, BX
mov BX, offset atp_&name&_arps
arp_loop:
mov word ptr [BX+atp_ip_lookup+2], AX
push AX
mov AX, DS
mov ES, AX
mov DI, BX
add DI, atp_buff_lookup+16
mov BP, DI
mov SI, BX
add SI, atp_ip_lookup
IP_ASCII_in_SI_DI_ES_out_DI_const_BX_BP_ES
mov AX, BP
sub AX, DI
dec DI
mov [DI], AL
mov word ptr [BX+nbp_entptr.buff_off], DI
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES name
pop AX
add BX, size atp_arp_entry
cmp [BX+nbp_command], 0
jnz arp_loop
jmp fail ;; we dont have the address
done:
ENDM
;;*****************************************************************************
;; ATP_DECLARE_IP_ADDRESS registers the ip address at the address 'ip_address'
;; it jumps to 'fail' if it was not successful
ATP_DECLARE_IP_ADDRESS MACRO name, ip_address, fail
local success
;; declare my IP address to the world
mov BX, offset atp_&name&_data.atp_NBTE_myip ;; Set up NB Table entry
mov SI, offset atp_&name&_data.atp_Info_param
xor AX, AX
mov AL, [SI+inf_nodeid] ;; node ID
mov [BX+tab_tuple.ent_address.nodeid], AL
mov AL, 72
mov [BX+tab_tuple.ent_address.socket], AL
mov AX, DS
mov ES, AX
mov SI, offset ip_address
mov DI, offset atp_&name&_data.atp_NBTE_myip.tab_tuple.ent_name+16
mov BX, DI
IP_ASCII_in_SI_DI_ES_out_DI_const_BX_BP_ES
mov SI, DI
sub BX, DI
mov CX, BX
mov DI, offset atp_&name&_data.atp_NBTE_myip.tab_tuple.ent_name
mov AL, CL
stosb
rep
movsb
mov AX, 9 + ('I' * 256)
stosw
mov AX, 'P' + ('A' * 256)
stosw
mov AX, 'D' + ('D' * 256)
stosw
mov AX, 'R' + ('E' * 256)
stosw
mov AX, 'S' + ('S' * 256)
stosw
mov AX, 1 + ('*' * 256)
stosw
mov BX, offset atp_&name&_data.atp_NBP_myip ;; Set up NBP command
mov word ptr [BX+nbp_command], NBPRegister
mov SI, offset atp_&name&_data.atp_NBTE_myip
mov word ptr [BX+nbp_buffptr.buff_off], SI
mov SI, DS
mov word ptr [BX+nbp_buffptr.buff_seg], SI
mov byte ptr [BX+nbp_interval], 1
mov byte ptr [BX+nbp_retry], 3
mov word ptr [BX+nbp_status], -205
CALL_ATP_in_BX_out_AX_const_BX_CX_DX_BP_SI_DI_ES name
cmp word ptr [BX+nbp_status], 0
jnz fail
ENDM
;;***************************************************************************
;; ATP_CHECK_DRIVER does some (weak) checks to see of the appletalk driver
;; has been installed. If not it jumps to 'fail'
;;
ATP_CHECK_DRIVER MACRO name, fail
xor AX, AX
mov ES, AX
mov DI, offset atp_&name&_interupt*4+2
mov AX, ES:[DI]
cmp AX, 100H ;; Segment register must be above 4K
jb fail
cmp AX, 0C000H ;; and less then C0000H
ja fail
ENDM