home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / packetdrivers.tar.gz / pd.tar / src / localtlk.asm < prev    next >
Assembly Source File  |  1995-06-25  |  35KB  |  1,314 lines

  1. version    equ    3
  2.  
  3.     include    defs.asm
  4.  
  5. ; PC/FTP Packet Driver source, conforming to version 1.09 of the spec
  6. ; Katie Stevens (dkstevens@ucdavis.edu)
  7. ; Computing Services, University of California, Davis
  8. ; Portions (C) Copyright 1988 Regents of the University of California
  9.  
  10. ; This program is free software; you can redistribute it and/or modify
  11. ; it under the terms of the GNU General Public License as published by
  12. ; the Free Software Foundation, version 1.
  13. ;
  14. ; This program is distributed in the hope that it will be useful,
  15. ; but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ; GNU General Public License for more details.
  18.  
  19. ; Change History
  20. ;
  21. ; 05-90        ks    Katie Stevens (dkstevens@ucdavis.edu):
  22. ;            - Created
  23. ; 07-19-91    jgn    Jim Noble (noble_jim@po.gis.prc.com):
  24. ;            - Added Change History and documented changes
  25. ;            - Fixed a bug that caused AppleTalk network numbers to
  26. ;              be byte-swapped when printed
  27. ;            - Fixed a bug that caused the wrong buffer address to 
  28. ;              be passed to the packet receiver upcall routine
  29. ;            - Made changes in the driver information structure to 
  30. ;              match LocalTalk:  size of MAC-layer address, MTU,
  31. ;              and multicast buffer size
  32. ;            - Changed the packet buffer sizes from 1024 to 586,
  33. ;              the maximum amount of data in a DDP packet
  34. ;            - Commented-out the noop_upcall completion routine and
  35. ;              changed the completion routine address passed to
  36. ;              the AppleTalk driver to 0000:0000 for all driver
  37. ;              calls
  38. ;            - Set the status field to -1 prior to the GetNetInfo
  39. ;              AppleTalk driver call as per the recommendation of
  40. ;              the driver interface spec.
  41. ;            - Added structure definitions for short and long 
  42. ;              format DDP packets and used them when adding a
  43. ;              check to ensure that received packets are IP packets
  44. ; 07-22-91    jgn    Jim Noble (noble_jim@po.gis.prc.com):
  45. ;            - Fixed a bug that would prevent the packet driver
  46. ;              from initializing with a static address if there
  47. ;              were no dynamic addresses available
  48. ; 07-23-91    jgn    Jim Noble (noble_jim@po.gis.prc.com):
  49. ;            - Added the optional IP address to the usage message
  50. ;            - Incremented version to 3
  51. ;
  52.  
  53. code    segment    word public
  54.     assume    cs:code, ds:code
  55.  
  56. ; Definitions specific to the ATALK.SYS driver for PC LocalTalk cards:
  57. ; these include Apple LocalTalk PC Card, Sun/TOPS FlashCard
  58. ; For a complete description of the LocalTalk commands, structures and
  59. ; methods used in this driver, please refer to Apple APDA document #M7055,
  60. ; LocalTalk PC Card and Driver Preliminary Notes.
  61.  
  62. driverstring    db    'AppleTalk', 0        ; ATALK.SYS signature string
  63. dot_char    db    '.', 0            ; for IP address display
  64.  
  65. AT_INT        equ    5CH            ; Software int# for ATALK.SYS
  66.  
  67. ; General ATALK.SYS driver commands
  68. AT_INIT            equ    01H        ; Initialize driver software
  69. AT_GETNETINFO        equ    03H        ; Get driver info
  70.  
  71. ; Datagram Delivery Protocol commands for ATALK.SYS driver
  72. DDP_OPENSOCKET        equ    20H
  73. DDP_CLOSESOCKET        equ    21H
  74. DDP_WRITE        equ    22H
  75. DDP_READ        equ    23H
  76. DDP_CANCEL        equ    24H
  77.  
  78. ; Name Binding Protocol commands for ATALK.SYS driver
  79. NBP_REGISTER        equ    30H
  80. NBP_REMOVE        equ    31H
  81. NBP_LOOKUP        equ    32H
  82. NBP_CONFIRM        equ    33H
  83. NBP_CANCEL        equ    34H
  84.  
  85. ; AppleTalk Transaction Protocol commands for ATALK.SYS driver
  86. ATP_SEND_REQUEST    equ    42H
  87.  
  88. ; ATALK.SYS command qualifiers
  89. ASYNC_MASK    equ    8000H        ; Start command, then return
  90. INTR_MASK    equ    4000H        ; Wait for intr service to complete
  91.  
  92. XO_BIT        equ    20H        ; ATP - exactly once transaction
  93.  
  94. ; Structure for short format DDP packet [jgn]
  95. DDPshort struc
  96.     lap_dst        db    ?    ; destination node
  97.     lap_src        db    ?    ; source node
  98.     lap_type    db    ?    ; 1 for short format DDP packet
  99.     ddps_len    dw    ?    ; packet length
  100.     ddps_dskt    db    ?    ; destination socket
  101.     ddps_sskt    db    ?    ; source socket
  102.     ddps_type    db    ?    ; 22 for IP packets
  103. DDPshort ends
  104.  
  105. ; Structure for long format DDP packet [jgn]
  106. DDPlong struc
  107.     lap_dst        db    ?    ; destination node
  108.     lap_src        db    ?    ; source node
  109.     lap_type    db    ?    ; 2 for long format DDP packets
  110.     ddpl_len    dw    ?    ; packet length
  111.     ddpl_chksum    dw    ?    ; checksum
  112.     ddpl_dnet    dw    ?    ; destination network
  113.     ddpl_snet    dw    ?    ; source network
  114.     ddpl_dnode    db    ?    ; destination node
  115.     ddpl_snode    db    ?    ; source node
  116.     ddpl_dskt    db    ?    ; destination socket
  117.     ddpl_sskt    db    ?    ; source socket
  118.     ddpl_type    db    ?    ; 22 for IP packets
  119. DDPlong ends
  120.  
  121. ; Structure for AppleTalk node addressing
  122. AddrBlk struc
  123.     ablk_network    dw    0
  124.     ablk_nodeid    db    0
  125.     ablk_socket    db    0
  126. AddrBlk ends
  127.  
  128. ; Structure for general calls to AppleTalk driver (ATALK.SYS)
  129. InfoParams struc
  130.     atd_command    dw        AT_GETNETINFO
  131.     atd_status    dw        0
  132.     atd_compfun    segmoffs    <>
  133.     inf_network    dw        0
  134.     inf_nodeid    db        0
  135.     inf_abridge    db        0
  136.     inf_config    dw        0
  137.     inf_buffptr    segmoffs    <>
  138.     inf_buffsize    dw        0
  139. InfoParams ends
  140. ; Parameter block for general calls to AppleTalk driver (ATALK.SYS)
  141. MyInfo    InfoParams    <>
  142.  
  143. ; Address block for our gateway
  144. MyGateway    AddrBlk        <>
  145.  
  146. ; Structure for calls to AppleTalk driver (ATALK.SYS) for Datagram
  147. ; Delivery Protocol (DDP) service
  148. DDPParams struc
  149.     ddp_command    dw        0
  150.     ddp_status    dw        0
  151.     ddp_compfun    segmoffs    <>
  152.     ddp_addr    AddrBlk        <>
  153.     ddp_socket    db        0
  154.     ddp_type    db        0
  155.     ddp_buffptr    segmoffs    <>
  156.     ddp_buffsize    dw        0
  157.     ddp_chksum    db        0
  158. DDPParams ends
  159. ; Parameter blocks for AppleTalk DDP access
  160. DDPio        DDPParams    <>        ; Write on DDP socket
  161. ; 2 buffers for packet receive from ATALK.SYS
  162. DDP1inuse    db    0            ; Buffer occupied flag
  163. DDP1buffsize    dw    0            ; Buffer length during reads
  164. DDP1buffer    db    586 dup (0)        ; Buffer for DDP read [jgn]
  165. DDP2inuse    db    0            ; 2nd Buffer occupied flag
  166. DDP2buffsize    dw    0            ; 2nd Buffer length during reads
  167. DDP2buffer    db    586 dup (0)        ; 2nd Buffer for DDP read [jgn]
  168.  
  169. ; Structure for calls to AppleTalk driver (ATALK.SYS) for Name
  170. ; Binding Protocol (NBP) service
  171. NBPParams struc
  172.     nbp_command    dw        0
  173.     nbp_status    dw        0
  174.     nbp_compfun    segmoffs    <>
  175.     nbp_addr    AddrBlk        <>
  176.     nbp_toget    dw        0
  177.     nbp_buffptr    segmoffs    <>
  178.     nbp_buffsize    dw        0
  179.     nbp_interval    db        0
  180.     nbp_retry    db        0
  181.     nbp_entptr    segmoffs    <>
  182. NBPParams ends
  183. ; Parameter block for AppleTalk NBP access
  184. NBP        NBPParams    <>
  185.  
  186. ; Structure for name-to-address bind entries
  187. NBPTuple struc
  188.     tup_address    AddrBlk        <>
  189.     tup_enum    db        0
  190.     tup_name    db        99 dup(0)
  191. NBPTuple ends
  192. ; Name Binding Tuple for our IP gateway
  193. NBPt        NBPTuple    <>
  194.  
  195. ; Structure for name-to-address table
  196. NBPEntry struc
  197.     tab_next    segmoffs    <>
  198.     tab_entry    NBPTuple    <>
  199. NBPEntry ends
  200. NBPtable    NBPEntry    <>
  201.  
  202. ; Structure for calls to AppleTalk driver (ATALK.SYS) for AppleTalk
  203. ; Transaction Protocol (ATP) service
  204. ATPParams struc
  205.     atp_command    dw        0
  206.     atp_status    dw        0
  207.     atp_compfun    segmoffs    <>
  208.     atp_addrblk    AddrBlk        <>
  209.     atp_socket    db        0
  210.     atp_fill    db        0
  211.     atp_buffptr    segmoffs    <>
  212.     atp_buffsize    dw        0
  213.     atp_interval    db        0
  214.     atp_retry    db        0
  215.     atp_flags    db        0
  216.     atp_seqbit    db        0
  217.     atp_tranid    dw        0
  218.     atp_userbytes    db        4 dup(0)
  219.     atp_bdsbuffs    db        0
  220.     atp_bdsresps    db        0
  221.     atp_bdsptr    segmoffs    <>
  222. ATPParams ends
  223. ; Parameter block for AppleTalk ATP access
  224. ATP        ATPParams    <>
  225.  
  226. ; Structure for BDS elements
  227. BDSElement struc
  228.     bds_buffptr    segmoffs    <>
  229.     bds_buffsize    dw        0
  230.     bds_datasize    dw        0
  231.     bds_userbytes    db        4 dup(0)
  232. BDSElement ends
  233. ; Parameter block for our BDS element
  234. BDS        BDSElement    <>
  235.  
  236. ; Struct for IP gateway information
  237. IPGInfo struc
  238.     ipg_opcode    db        0,0,0,1    ; IPGP_ASSIGN
  239.     ipg_ipaddress    dd        0    ; our IP address
  240.     ipg_ipname    dd        0    ; nameserver IP address
  241.     ipg_ipbroad    dd        0    ; broadcast IP address
  242.     ipg_ipfile    dd        0    ; file server IP address
  243.     ipg_ipother    dd        4 dup (0)
  244.     ipg_string    db        128 dup (0), '$'
  245. IPGInfo ends
  246. ; Parameter block for info about our IP gateway
  247. IPG        IPGInfo        <>
  248.  
  249. IPG_ERROR    equ    -1
  250.  
  251. static_address    db    0, 0, 0, 0
  252. use_static    db    0
  253. test_address    db    0, 0, 0, 0
  254. temp_4bytes    db    0, 0, 0, 0
  255.  
  256. ; End of Appletalk parameter definitions
  257.  
  258. ; The following values may be overridden from the command line.
  259. ; If they are omitted from the command line, these defaults are used.
  260.  
  261.     public    int_no
  262. int_no    db    0,0,0,0            ;must be four bytes long for get_number.
  263.  
  264.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  265. driver_class    db    5,0        ;from the packet spec
  266. driver_type    db    1        ;from the packet spec
  267. driver_name    db    'LocalTalk',0    ;name of the driver.
  268. driver_function    db    2
  269. parameter_list    label    byte
  270.     db    1    ;major rev of packet driver
  271.     db    9    ;minor rev of packet driver
  272.     db    14    ;length of parameter list
  273.     db    4    ;length of MAC-layer address [jgn]
  274.     dw    586    ;MTU, including MAC headers [jgn]
  275.     dw    0    ;buffer size of multicast addrs [jgn]
  276.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  277.     dw    0    ;(# of successive xmits) - 1
  278. int_num    dw    0    ;Interrupt # to hook for post-EOI
  279.             ;processing, 0 == none,
  280.  
  281.     public    rcv_modes
  282. rcv_modes    dw    4        ;number of receive modes in our table.
  283.         dw    0,0,0,rcv_mode_3
  284.  
  285.     public bad_command_intercept
  286. bad_command_intercept:
  287. ;called with ah=command, unknown to the skeleton.
  288. ;exit with nc if okay, cy, dh=error if not.
  289.     mov    dh,BAD_COMMAND
  290.     stc
  291.     ret
  292.  
  293.     public    as_send_pkt
  294. ; The Asynchronous Transmit Packet routine.
  295. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  296. ;   interrupts possibly enabled.
  297. ; Exit with nc if ok, or else cy if error, dh set to error number.
  298. ;   es:di and interrupt enable flag preserved on exit.
  299. as_send_pkt:
  300.     ret
  301.  
  302.     public    drop_pkt
  303. ; Drop a packet from the queue.
  304. ; Enter with es:di -> iocb.
  305. drop_pkt:
  306.     assume    ds:nothing
  307.     ret
  308.  
  309.     public    xmit
  310. ; Process a transmit interrupt with the least possible latency to achieve
  311. ;   back-to-back packet transmissions.
  312. ; May only use ax and dx.
  313. xmit:
  314.     assume    ds:nothing
  315.     ret
  316.  
  317.     public    send_pkt
  318. send_pkt:
  319. ;enter with es:di->upcall routine, (0:0) if no upcall is desired.
  320. ;  (only if the high-performance bit is set in driver_function)
  321. ;enter with ds:si -> packet, cx = packet length.
  322. ;if we're a high-performance driver, es:di -> upcall.
  323. ;exit with nc if ok, or else cy if error, dh set to error number.
  324.     assume    ds:nothing
  325. ; send packet to AppleTalk/DDP/IP gateway
  326.     ; load info about the packet we are sending
  327.     mov    DDPio.ddp_buffptr.offs, si
  328.     mov    DDPio.ddp_buffptr.segm, ds    ; DDPio.buffptr -> IP packet
  329.     mov    DDPio.ddp_buffsize, cx        ; DDPio.buffsize = packet len
  330.  
  331.     ; send all packets to the IP gateway
  332.     mov    cx, (size AddrBlk)        ; DDPio.ddp_addr = MyGateway
  333.     mov    ax, cs
  334.     mov    ds, ax
  335.     mov    es, ax
  336.     mov    si, offset MyGateway
  337.     mov    di, offset DDPio.ddp_addr
  338.     rep    movsb
  339.  
  340.     mov    bx, offset DDPio
  341.     call    doATint                ; Ask ATALK.SYS to send packet
  342.  
  343.     cmp    DDPio.ddp_status, 00H        ; Packet sent okay?
  344.     je    send_ret            ; Yes, status is good
  345.                         ; No, status gives error
  346. send_err:
  347.     call    count_out_err
  348.     mov    dh, CANT_SEND            ; set error flag
  349.     stc
  350.     ret
  351.  
  352. send_ret:
  353.     clc                    ; packet sent successfully
  354.     ret
  355.  
  356.     public    set_address
  357. set_address:
  358. ;enter with ds:si -> Ethernet address, CX = length of address.
  359. ;exit with nc if okay, or cy, dh=error if any errors.
  360.     assume    ds:nothing
  361.     mov    dh, BAD_COMMAND
  362.     stc
  363.     ret
  364.  
  365.  
  366. rcv_mode_3:
  367. ;receive mode 3 is the only one we support, so we don't have to do anything.
  368.     ret
  369.  
  370.  
  371.     public    set_multicast_list
  372. set_multicast_list:
  373. ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
  374. ;  cx = number of bytes.
  375. ;return nc if we set all of them, or cy,dh=error if we didn't.
  376.     mov    dh,NO_MULTICAST
  377.     stc
  378.     ret
  379.  
  380.  
  381.     public    terminate
  382. terminate:
  383.     push    ds
  384.     push    cs
  385.     pop    ds
  386.  
  387. terminate_write:
  388.     ; close the DDP socket
  389.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  390.     mov    bx, offset DDPio
  391.     call    doATint
  392.  
  393.     mov    NBP.nbp_command, NBP_REMOVE
  394.     mov    NBP.nbp_entptr.offs, offset NBPtable.tab_entry.tup_name
  395.     mov    NBP.nbp_entptr.segm, ds
  396.     mov    bx, offset NBP
  397.     call    doATint
  398.  
  399.     pop    ds
  400.     ret
  401.  
  402.     public    reset_interface
  403. reset_interface:
  404. ;reset the interface.
  405.     assume    ds:code
  406.     ret
  407.  
  408.  
  409. ;called when we want to determine what to do with a received packet.
  410. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  411.     extrn    recv_find: near
  412.  
  413. ;called after we have copied the packet into the buffer.
  414. ;enter with ds:si ->the packet, cx = length of the packet.
  415.     extrn    recv_copy: near
  416.  
  417. ;call this routine to schedule a subroutine that gets run after the
  418. ;recv_isr.  This is done by stuffing routine's address in place
  419. ;of the recv_isr iret's address.  This routine should push the flags when it
  420. ;is entered, and should jump to recv_exiting_exit to leave.
  421. ;enter with ax = address of routine to run.
  422.     extrn    schedule_exiting: near
  423.  
  424. ;recv_exiting jumps here to exit, after pushing the flags.
  425.     extrn    recv_exiting_exit: near
  426.  
  427.     extrn    count_in_err: near
  428.     extrn    count_out_err: near
  429.  
  430.     public    recv
  431. recv:
  432. ;called from the recv isr.  All registers have been saved, and ds=cs.
  433. ;Upon exit, the interrupt will be acknowledged.
  434. ;NOTE: this packet driver merely makes calls to another hardware
  435. ;driver, ATALK.SYS. ATALK.SYS handles the hardware interrupt service;
  436. ;ATALK.SYS then calls this packet driver with FAR subroutine calls.
  437. ;the ATALK.SYS FAR subroutine is recv_at_upcall
  438.     assume    ds:nothing
  439.     ret
  440.  
  441. ;*******************************************
  442.  
  443. ; [jgn] Null completion routine is not needed.  Just specify 0000:0000 as the
  444. ; address of the completion routine for no call.
  445. ;
  446. ; NULL completion routine for ATALK.SYS drivers calls
  447. ;noop_upcall proc far
  448. ;    ret
  449. ;noop_upcall endp
  450.  
  451. ;First half routine for DDP socket.
  452. ;ATALK.SYS calls this routine when a packet is received.
  453. ;ATALK.SYS assumes we are a far procedure.
  454. ;    AH = socket
  455. ;    CX = size of data packet
  456. ;    DS:BX = address of buffer
  457. preview_upcall proc far
  458.     assume    ds:nothing
  459.  
  460. ;    maximum packet we can receive is 586 bytes [jgn]
  461.     cmp    cx, 586                ; Max size of DDP data field [jgn]
  462.     ja    preview_drop
  463.  
  464. ;    Is it an IP packet?  DDP type should be 22 [jgn]
  465.     cmp    byte ptr ds:[bx].lap_type, 1    ; Is it a short DDP packet?
  466.     jne    ddp_long            ; No, must be long DDP
  467.     cmp    byte ptr ds:[bx].ddps_type, 22    ; Is it an IP packet?
  468.     jne    preview_drop            ; No, refuse packet
  469.     jmp    preview_buff1
  470. ddp_long:
  471.     cmp    byte ptr ds:[bx].ddpl_type, 22    ; Is it an IP packet?
  472.     jne    preview_drop            ; No, refuse packet
  473.  
  474. preview_buff1:
  475.     cmp    DDP1inuse, 00H
  476.     jne    preview_buff2
  477.     mov    DDP1inuse, 01H
  478.  
  479. ;    repeat buffer size back to ATALK.SYS in CX
  480. ;    ask ATALK.SYS driver to pass us the buffer at DS:BX
  481. ;    tell ATALK.SYS address of 2nd half routine in ES:DX
  482.     movseg    ds,cs
  483.     mov    bx, offset DDP1buffer        ; ds:bx->buffer
  484.     movseg    es,cs
  485.     mov    dx, offset recv_at_upcall    ; es:dx->2nd half routine
  486.     jmp    preview_ret
  487.  
  488. preview_buff2:
  489.     cmp    DDP2inuse, 00H
  490.     jne    preview_drop
  491.     mov    DDP2inuse, 01H
  492.  
  493. ;    repeat buffer size back to ATALK.SYS in CX
  494. ;    ask ATALK.SYS driver to pass us the buffer at DS:BX
  495. ;    tell ATALK.SYS address of 2nd half routine in ES:DX
  496.     movseg    ds,cs
  497.     mov    bx, offset DDP2buffer        ; ds:bx->buffer
  498.     movseg    es,cs
  499.     mov    dx, offset recv_at_upcall    ; es:dx->2nd half routine
  500.     jmp    preview_ret
  501.  
  502.  
  503. preview_drop:
  504. ;    ask ATALK.SYS to drop the packet
  505.     call    count_in_err
  506.     mov    cx, 00h
  507.  
  508. preview_ret:
  509.     ret
  510. preview_upcall endp
  511.  
  512. ;Second half routine for DDP socket.
  513. ;ATALK.SYS calls this routine when the packet has been copied to our buffer.
  514. ;ATALK.SYS assumes we are a far procedure.
  515. ;    CX = size of data packet
  516. ;    DS:BX = address of buffer
  517. recv_at_upcall proc far
  518.     assume    ds:nothing
  519.  
  520. recv_buff1:
  521.     cmp    bx, offset DDP1buffer
  522.     jne    recv_buff2
  523.  
  524. ;    check if we have a client waiting for packets
  525. ;    pass to recv_find    es:di->driver_type, cx=#bytes in packet
  526.     mov    DDP1buffsize, cx
  527.     mov    di, offset driver_type
  528.     movseg    es,cs
  529.     mov    dl,cs:driver_class
  530.     call    recv_find
  531.  
  532. ;    es:di->client buffer, or es:di=0 means drop the packet
  533.     mov    ax, es
  534.     or    ax, di
  535.     je    recv_pass1
  536.  
  537. ;    copy ds:si->es:di for cx bytes
  538.     push    es                ; save the client buffer
  539.     push    di                ; address (es:di) [jgn]
  540.     movseg    ds,cs
  541.     mov    si, offset DDP1buffer
  542.     mov    cx, DDP1buffsize
  543.     rep    movsb
  544.  
  545. ;    tell receiver copy has been made; ds:si->the packet, cx=length
  546.     pop    si                ; restore the client buffer
  547.     pop    ds                ; address into ds:si [jgn]
  548.     mov    cx, DDP1buffsize
  549.     call    recv_copy
  550.  
  551. recv_pass1:
  552. ;    first buffer is free for use again
  553.     mov    DDP1inuse, 00H
  554.     jmp    recv_ret
  555.  
  556.  
  557. recv_buff2:
  558.     cmp    bx, offset DDP2buffer
  559.     jne    recv_ret
  560.  
  561. ;    check if we have a client waiting for packets
  562. ;    pass to recv_find    es:di->driver_type, cx=#bytes in packet
  563.     mov    DDP2buffsize, cx
  564.     mov    di, offset driver_type
  565.     movseg    es,cs
  566.     call    recv_find
  567.  
  568. ;    es:di->client buffer, or es:di=0 means drop the packet
  569.     mov    ax, es
  570.     or    ax, di
  571.     je    recv_pass2
  572.  
  573. ;    copy ds:si->es:di for cx bytes
  574.     push    es                ; save the client buffer
  575.     push    di                ; address (es:di) [jgn]
  576.     movseg    ds,cs
  577.     mov    si, offset DDP2buffer
  578.     mov    cx, DDP2buffsize
  579.     rep    movsb
  580.  
  581. ;    tell receiver copy has been made; ds:si->the packet, cx=length
  582. ;    push    es
  583.     pop    si                ; restore the client buffer
  584.     pop    ds                ; address into ds:si [jgn]
  585. ;    mov    si, offset DDP2buffer
  586.     mov    cx, DDP2buffsize
  587.     call    recv_copy
  588. recv_pass2:
  589. ;    second buffer is now free for use
  590.     mov    DDP2inuse, 00H
  591.  
  592. recv_ret:
  593.     ret
  594. recv_at_upcall endp
  595.  
  596. ;*******************************************
  597.  
  598. ; Call DOS software interrupt for AppleTalk
  599. ; caller must set ds:bx -> parameter block for ATALK.SYS
  600. doATint:
  601.     int    AT_INT                ; Interrupt ATALK.SYS driver
  602.     ret
  603.  
  604.  
  605.  
  606.     public    timer_isr
  607. timer_isr:
  608. ;if the first instruction is an iret, then the timer is not hooked
  609.     iret
  610.  
  611. ;any code after this will not be kept after initialization. Buffers
  612. ;used by the program, if any, are allocated from the memory between
  613. ;end_resident and end_free_mem.
  614.     public end_resident,end_free_mem
  615. end_resident    label    byte
  616. end_free_mem    label    byte
  617. ;****************************************************************************
  618.  
  619.     public    usage_msg
  620. usage_msg    db    "usage: localtlk [options] <packet_int_no> [ <IP address> ]",CR,LF,'$' ; [jgn]
  621.  
  622.     public    copyright_msg
  623. copyright_msg    db    "Packet driver for Apple LocalTalk PC Card, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  624.         db    "Portions Copyright 1990, Regents of the University of California",CR,LF,'$'
  625.  
  626. no_atalk_sys_msg:
  627.     db    "Couldn't locate ATALK.SYS -- packet driver not installed",CR,LF,'$'
  628. atalk_sys_found_msg:
  629.     db    "ATALK.SYS driver located at software interrupt ",'$'
  630. inf_nodeid_name:
  631.     db    "Attaching to AppleTalk network as node ",'$'
  632. inf_abridge_name:
  633.     db    "AppleTalk network bridge is node ",'$'
  634. ddp_failed_msg:
  635.     db    "Datagram Delivery Protocol socket open failed; return status: ",'$'
  636. ddp_wrong_socket_msg:
  637.     db    "Datagram Delivery Protocol failed; unable to aquire requested socket",CR,LF,'$'
  638. ddp_open_msg:
  639.     db    "Datagram Delivery Protocol open on socket ",'$'
  640. atalk_open_msg:
  641.     db    "Attached to AppleTalk network as (net:node:sock): ",'$'
  642. nbp_no_gateway_msg:
  643.     db    "NBP: IPGATEWAY lookup failed; return status: ",'$'
  644. nbp_ipg_addr_msg:
  645.     db    "IPGATEWAY located on AppleTalk network as (net:node:sock): ",'$'
  646. atp_no_gateway_msg:
  647.     db    "ATP: IPGATEWAY transport setup failed; return status: ",'$'
  648. ipg_gateway_err_msg:
  649.     db    "IP Gateway error: ",'$'
  650. myip_addr_msg:
  651.     db    "My IP address: ",'$'
  652. ns_ip_addr_msg:
  653.     db    "Name Server IP address: ",'$'
  654. bd_ip_addr_msg:
  655.     db    "Broadcast IP address: ",'$'
  656. fs_ip_addr_msg:
  657.     db    "File Server IP address: ",'$'
  658. opcode_msg:
  659.     db    "IPG opcode: ",'$'
  660. nbp_no_register_msg:
  661.     db    "NBP: failed, couldn't register our name; return status: ",'$'
  662. ddp_cant_recv:
  663.     db    "DDP: couldn't initiate read on socket; return status: ",'$'
  664. test_arg_msg:
  665.     db    "Test IP arg parsing: ",'$'
  666. null_msg    db    '$'
  667.  
  668. ipgateway_name:
  669.     db    01H, '=', 09H, "IPGATEWAY", 01H, '*', '0'
  670. myip_name:
  671.     db    09H, "IPADDRESS", 01H, '*', '0'
  672. myip_name_len    equ    12
  673.  
  674. ; Temporary storage for calls to print_number
  675. dtemp    dw    ?,0
  676.  
  677.     extrn    set_recv_isr: near
  678.  
  679. ;enter with si -> argument string, di -> wword to store.
  680. ;if there is no number, don't change the number.
  681.     extrn    get_number: near
  682.  
  683. ;enter with ds:dx -> argument string, ds:di -> dword to print.
  684.     extrn    print_number: near
  685.  
  686. ;enter with al = char to display
  687.     extrn    chrout: near
  688. ;enter with ax,dx holding 32 bits to display in decimal (ax holds low word)
  689.     extrn    decout: near
  690.     extrn    byteout: near
  691.     extrn    wordout: near
  692.  
  693.     extrn    skip_blanks: near
  694.  
  695. ;enter with si -> argument string, di -> word to store.
  696. ;if there is no number, don't change the number.
  697.     extrn    get_number: near
  698.  
  699. ;called with ds:si -> immediately after the entry_point
  700.     public    parse_args
  701. parse_args:
  702.     call    skip_blanks
  703.     lodsb
  704.     cmp    al, CR
  705.     je    no_more_args
  706.     cmp    al, '['                ; check for square brackets
  707.     je    past_brackets
  708.     dec    si                ; not a bracket, back up
  709. past_brackets:
  710.     mov    di, offset temp_4bytes        ; get first IP address byte
  711.     call    get_number
  712.     mov    byte ptr test_address, cl
  713.     lodsb
  714.     cmp    al, '.'
  715.     jne    no_more_args
  716.  
  717.     mov    di, offset temp_4bytes        ; get second IP address byte
  718.     call    get_number
  719.     mov    byte ptr test_address+1, cl
  720.     lodsb
  721.     cmp    al, '.'
  722.     jne    no_more_args
  723.  
  724.     mov    di, offset temp_4bytes        ; get third IP address byte
  725.     call    get_number
  726.     mov    byte ptr test_address+2, cl
  727.     lodsb
  728.     cmp    al, '.'
  729.     jne    no_more_args
  730.  
  731.     mov    di, offset temp_4bytes        ; get first IP address byte
  732.     call    get_number
  733.     mov    byte ptr test_address+3, cl
  734.  
  735. ;    mov    dx, offset test_arg_msg
  736. ;    mov    di, offset test_address
  737. ;push    si
  738. ;    call    print_ip_addr
  739. ;pop    si
  740.  
  741.     mov    ax, word ptr test_address
  742.     mov    word ptr static_address, ax
  743.     mov    ax, word ptr test_address+2
  744.     mov    word ptr static_address+2, ax
  745.     mov    use_static, 01H
  746.  
  747.     lodsb
  748.     cmp    al, ']'
  749.     je    arg_return
  750.  
  751. ;exit with nc if all went well, cy otherwise.
  752. no_more_args:
  753.     dec    si
  754. arg_return:
  755.     clc
  756.     ret
  757.  
  758.  
  759. ; Initialize our interface to the ATALK.SYS driver.
  760. ; NOTE: this initialization code is modeled after the PC/IP LocalTalk
  761. ; driver written by Dan Lanciani (ddl@harvard.harvard.edu); the PCIP
  762. ; software package can found at husc6.harvard.edu:pub/pcip/pcip.tar.Z
  763.     public    etopen
  764. etopen:
  765.     assume    ds:code
  766.  
  767. ; ATALK.SYS driver may be loaded at a software interrupt somewhere
  768. ; between 5CH and 70H. Locate ATALK.SYS driver by scanning for signature.
  769. isATLoaded:                    ; Look for ATALK.SYS driver
  770.     cld
  771.     call    ATGetInt            ; Load start of intr range
  772.     mov    dx, ax                ; Save start value in DX
  773. chkloop:
  774.     cmp    dx, 70H                ; Scanned all possible vectors?
  775.     jne    checkstring            ; No, check this vector
  776.     xor    ax, ax                ; Yes, driver not found
  777.     jmp    chksplit            ; Skip ahead to return
  778. checkstring:
  779.     mov    bx, dx                ; Load intr# for scan
  780.     shl    bx, 1                ; Multiply by 2 (for seg bytes)
  781.     shl    bx, 1                ; Multiply by 2 (for off bytes)
  782.     xor    ax, ax
  783.     mov    es, ax                ; Lowest page of memory
  784.     lds    si, es:[bx]            ; Load vector for scan intr#
  785.     mov    ax, ds                ; Load segment this scan intr#
  786.     or    ax, si                ; OR with off this scan intr#
  787.     jz    keepchecking            ; Keep checking if no bits
  788.     sub    si, 16                ; Signature is just before code
  789.     mov    di, offset driverstring        ; Load compare string
  790.     mov    cx, 9                ; Load length of compare string
  791.     movseg    es,cs
  792.     repe    cmpsb                ; Compare ds:si to es:di
  793.     jne    keepchecking            ; Keep checking if not matched
  794.     call    ATGetInt            ; Matched, get INT# again
  795.     cmp    ax, dx                ; INT# already set properly?
  796.     jz    chksplit            ; Yes, use this INT#
  797.                         ; No, we found INT# by scanning
  798.     call    ATPatch                ; Modify code to match scan
  799.     call    ATGetInt            ; Retrieve final INT#
  800.     jmp    chksplit            ; Skip ahead to return
  801.  
  802. keepchecking:                    ; Havent found ATALK.SYS driver
  803.     inc    dx                ; Check next possible INT#
  804.     jmp    chkloop                ; Loop back to check next INT#
  805.  
  806. chksplit:                    ; Done with scan for ATALK.SYS
  807.     cmp    ax, 00H                ; ATALK.SYS driver found?
  808.     jne    atalk_sys_found            ; Yes, skip ahead to continue
  809.  
  810.     mov    dx, offset no_atalk_sys_msg    ; No, ATALK.SYS not loaded
  811.     jmp    error_wrt            ; Skip ahead to report error
  812.  
  813. atalk_sys_found:                ; ATALK.SYS driver found
  814.     movseg    ds,cs
  815.     mov    dtemp, dx            ; Report intr# of ATALK.SYS
  816.     mov    di, offset dtemp
  817.     mov    dx, offset atalk_sys_found_msg
  818.     call    print_number
  819.  
  820. ; We need to establish our Appletalk node
  821. get_our_info:                    ; Get info params from ATALK
  822.     mov    MyInfo.atd_command, AT_GETNETINFO
  823.     mov    MyInfo.atd_status, -1        ; As per PC LocalTalk spec. [jgn]
  824.     mov    MyInfo.atd_compfun.offs, 0    ; No completion routine [jgn]
  825.     mov    MyInfo.atd_compfun.segm, 0
  826.     mov    bx, offset MyInfo
  827.     call    doATint
  828.  
  829.     cmp    MyInfo.atd_status, 00H        ; Already initialized?
  830.     je    get_ddp_socket            ; Yes, skip ahead
  831.  
  832.     mov    MyInfo.atd_command, AT_INIT    ; No, initialize our node
  833.     mov    MyInfo.atd_compfun.offs, 0    ; No completion routine [jgn]
  834.     mov    MyInfo.atd_compfun.segm, 0
  835.     mov    bx, offset MyInfo
  836.     call    doATint
  837.  
  838. ; We need to establish our AppleTalk/DDP socket
  839. get_ddp_socket:                    ; Open a DDP socket
  840.     mov    DDPio.ddp_command, DDP_OPENSOCKET
  841.     mov    DDPio.ddp_compfun.offs, 0    ; No completion routine [jgn]
  842.     mov    DDPio.ddp_compfun.segm, 0
  843.     mov    DDPio.ddp_buffptr.offs, offset preview_upcall
  844.     mov    DDPio.ddp_buffptr.segm, cs
  845.     mov    DDPio.ddp_socket, 72        ; ask for experimental sock#
  846.     mov    DDPio.ddp_type, 22        ; ask for IP socket type
  847.     mov    bx, offset DDPio            ; ds:bx-> DDP param block
  848.     call    doATint                ; ask ATALK.SYS for a socket
  849.  
  850.     cmp    DDPio.ddp_status, 00H        ; error return from ATALK.SYS?
  851.     je    chk_ddp_socket            ; no, skip ahead to continue
  852.                         ; yes, no socket for us
  853.     mov    ax, DDPio.ddp_status
  854.     mov    dtemp, ax
  855.     mov    di, offset dtemp
  856.     mov    dx, offset ddp_failed_msg
  857.     call    print_number            ; report error and stat return
  858.     jmp    error_ret
  859.  
  860. ;**** do we really require socket 72?
  861. chk_ddp_socket:                    ; check the socket we opened
  862.     cmp    DDPio.ddp_socket, 72        ; did we get the one requested?
  863.     je    ddp_ready            ; yes, socket is as expected
  864.                         ; no, but must have socket 72
  865.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  866.     mov    bx, offset DDPio
  867.     call    doATint                ; close the assigned socket
  868.  
  869.     mov    dx, offset ddp_wrong_socket_msg    ; load error msg
  870.     jmp    error_wrt            ; skip ahead to display and ret
  871.  
  872. ddp_ready:                    ; DDP socket 72 is ready
  873.     mov    DDPio.ddp_command, DDP_WRITE    ; Use param block for WRITE now
  874.  
  875. ; AppleTalk node and DDP socket have been established
  876.     mov    ax, MyInfo.inf_network
  877.     mov    word ptr dtemp, ax
  878.     mov    al, MyInfo.inf_nodeid
  879.     mov    ah, DDPio.ddp_socket
  880.     mov    byte ptr dtemp+2, al
  881.     mov    byte ptr dtemp+3, ah
  882.     mov    di, offset dtemp
  883.     mov    dx, offset atalk_open_msg
  884.     call    print_at_addr            ; display AppleTalk node info
  885.     mov    ax, 00H
  886.     mov    dtemp+2, ax
  887.  
  888. ; We need an IP gateway node
  889. nbp_ipgateway:                    ; Locate our IP gateway node
  890.     movseg    ds,cs
  891.     mov    NBP.nbp_command, NBP_LOOKUP
  892.     mov    NBP.nbp_compfun.offs, 0        ; No completion routine [jgn]
  893.     mov    NBP.nbp_compfun.segm, 0
  894.     mov    NBP.nbp_toget, 01H
  895.     mov    NBP.nbp_buffptr.offs, offset NBPt
  896.     mov    NBP.nbp_buffptr.segm, ds
  897.     mov    NBP.nbp_buffsize, (size NBPTuple)
  898.     mov    NBP.nbp_interval, 5
  899.     mov    NBP.nbp_retry, 12
  900.     mov    NBP.nbp_entptr.offs, offset ipgateway_name
  901.     mov    NBP.nbp_entptr.segm, ds
  902.     mov    bx, offset NBP
  903.     call    doATint                ; do name-bind lookup
  904.  
  905.     cmp    NBP.nbp_status, 00H        ; status return=error?
  906.     jne    nbp_no_gateway            ; yes, report error and exit
  907.  
  908.     cmp    NBP.nbp_toget, 01H
  909.     je    atp_setup
  910.  
  911. nbp_no_gateway:                    ; NBP lookup failed
  912.     mov    ax, NBP.nbp_status
  913.     mov    dtemp, ax
  914.     mov    di, offset dtemp
  915.     mov    dx, offset nbp_no_gateway_msg    ; display error msg
  916.     call    print_number
  917.  
  918.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  919.     mov    bx, offset DDPio
  920.     call    doATint                ; close the assigned socket
  921.  
  922.     jmp    error_ret            ; skip ahead to return
  923.  
  924. ; We need a transport layer to the IP gateway
  925. atp_setup:
  926.     mov    cx, (size AddrBlk)        ; MyGateway = NBPt.tup_addr
  927.     movseg    es,cs
  928.     mov    si, offset NBPt.tup_address
  929.     mov    di, offset MyGateway
  930.     rep    movsb
  931.  
  932.     mov    di, offset NBPt.tup_address    ; Display our gateway node
  933.     mov    dx, offset nbp_ipg_addr_msg
  934.     call    print_at_addr
  935.  
  936.     cmp    use_static, 00H            ; Do we have a static address? [jgn]
  937.     je    bds_setup            ; No, don't change anything
  938.     mov    IPG.ipg_opcode+3, 3        ; Yes, change to IPG_SERVER
  939.  
  940. bds_setup:
  941.     mov    BDS.bds_buffptr.offs, offset IPG
  942.     mov    BDS.bds_buffptr.segm, ds
  943.     mov    BDS.bds_buffsize, (size IPGInfo)
  944.  
  945.     mov    ATP.atp_command, ATP_SEND_REQUEST
  946.     mov    ATP.atp_compfun.offs, 0        ; No completion routine [jgn]
  947.     mov    ATP.atp_compfun.segm, 0
  948.     mov    cx, (size AddrBlk)        ; ATP.atp_addr = NBPt.tup_addr
  949.     movseg    es,cs
  950.     mov    si, offset NBPt.tup_address
  951.     mov    di, offset ATP.atp_addrblk
  952.     rep    movsb
  953.     mov    ATP.atp_buffptr.offs, offset IPG
  954.     mov    ATP.atp_buffptr.segm, ds
  955.     mov    ATP.atp_buffsize, (size IPGInfo)
  956.     mov    ATP.atp_interval, 05H
  957.     mov    ATP.atp_retry, 05H
  958.     mov    ATP.atp_flags, XO_BIT
  959.     mov    ATP.atp_bdsbuffs, 01H
  960.     mov    ATP.atp_bdsptr.offs, offset BDS
  961.     mov    ATP.atp_bdsptr.segm, ds
  962.     mov    bx, offset ATP
  963.     call    doATint
  964.  
  965.     cmp    ATP.atp_status, 00H        ; status return=error?
  966.     jne    atp_no_gateway            ; yes, report error and exit
  967.  
  968.     cmp    ATP.atp_bdsbuffs, 01H
  969.     je    chk_ip_opcode
  970.  
  971. atp_no_gateway:                    ; ATP setup failed
  972.     mov    ax, ATP.atp_status
  973.     mov    dtemp, ax
  974.     mov    di, offset dtemp
  975.     mov    dx, offset atp_no_gateway_msg    ; display error msg
  976.     call    print_number
  977.  
  978.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  979.     mov    bx, offset DDPio
  980.     call    doATint                ; close the assigned socket
  981.  
  982.     jmp    error_ret            ; skip ahead to return
  983.  
  984. chk_ip_opcode:
  985.     cmp    IPG.ipg_opcode.offs, IPG_ERROR    ; opcode is 32 bit
  986.     jne    save_ipaddr            ; check one word at a time
  987.     cmp    IPG.ipg_opcode.segm, IPG_ERROR    ; error from IP gateway?
  988.     jne    save_ipaddr            ; no, transport established
  989.                         ; yes, ATP setup failed
  990.     mov    dx, offset ipg_gateway_err_msg    ; display IPG error msg
  991.     mov    ah, 9
  992.     int    21H
  993.     mov    dx, offset IPG.ipg_string
  994.     mov    ah, 9
  995.     int    21H
  996.     mov    al, 13                ; display CR-LF
  997.     call    chrout
  998.     mov    al, 10
  999.     call    chrout
  1000.  
  1001.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  1002.     mov    bx, offset DDPio
  1003.     call    doATint                ; close the assigned socket
  1004.  
  1005.     jmp    error_ret
  1006.  
  1007. ; AppleTalk/IP transport layer established
  1008. save_ipaddr:
  1009.     mov    dx, offset myip_addr_msg
  1010.     cmp    use_static, 00H
  1011.     jne    show_static
  1012. show_dynamic:
  1013.     mov    di, offset IPG.ipg_ipaddress
  1014.     jmp    show_ipaddr
  1015. show_static:
  1016.     mov    di, offset static_address
  1017. show_ipaddr:
  1018.     call    print_ip_addr
  1019.  
  1020.     mov    dx, offset ns_ip_addr_msg
  1021.     mov    di, offset IPG.ipg_ipname
  1022.     call    print_ip_addr
  1023.  
  1024.     mov    dx, offset bd_ip_addr_msg
  1025.     mov    di, offset IPG.ipg_ipbroad
  1026.     call    print_ip_addr
  1027.  
  1028.     mov    dx, offset fs_ip_addr_msg
  1029.     mov    di, offset IPG.ipg_ipfile
  1030.     call    print_ip_addr
  1031.  
  1032. ; We need to register ourself with the AppleTalk Name Binding Agent
  1033. nbp_register_ourself:
  1034.     mov    al, MyInfo.inf_nodeid
  1035.     mov    NBPtable.tab_entry.tup_address.ablk_nodeid, al
  1036.     mov    al, DDPio.ddp_socket
  1037.     mov    NBPtable.tab_entry.tup_address.ablk_socket, al
  1038.  
  1039.     ; print our IP address in our NBP table entry
  1040.     mov    bx, offset NBPtable.tab_entry.tup_name
  1041.     inc    bx
  1042.     xor    dx, dx
  1043.     cmp    use_static, 00H
  1044.     jne    reg_static1
  1045. reg_dynamic1:
  1046.     mov    dl, byte ptr IPG.ipg_ipaddress
  1047.     jmp    reg_format1
  1048. reg_static1:
  1049.     mov    dl, byte ptr static_address
  1050. reg_format1:
  1051.     call    decstr
  1052.     mov    al, dot_char
  1053.     mov    byte ptr ds:[bx], al
  1054.     inc    bx
  1055.     cmp    use_static, 00H
  1056.     jne    reg_static2
  1057. reg_dynamic2:
  1058.     mov    dl, byte ptr IPG.ipg_ipaddress+1
  1059.     jmp    reg_format2
  1060. reg_static2:
  1061.     mov    dl, byte ptr static_address+1
  1062. reg_format2:
  1063.     call    decstr
  1064.     mov    al, dot_char
  1065.     mov    ds:[bx], al
  1066.     inc    bx
  1067.     cmp    use_static, 00H
  1068.     jne    reg_static3
  1069. reg_dynamic3:
  1070.     mov    dl, byte ptr IPG.ipg_ipaddress+2
  1071.     jmp    reg_format3
  1072. reg_static3:
  1073.     mov    dl, byte ptr static_address+2
  1074. reg_format3:
  1075.     call    decstr
  1076.     mov    al, dot_char
  1077.     mov    ds:[bx], al
  1078.     inc    bx
  1079.     cmp    use_static, 00H
  1080.     jne    reg_static4
  1081. reg_dynamic4:
  1082.     mov    dl, byte ptr IPG.ipg_ipaddress+3
  1083.     jmp    reg_format4
  1084. reg_static4:
  1085.     mov    dl, byte ptr static_address+3
  1086. reg_format4:
  1087.     call    decstr
  1088.  
  1089.     mov    ax, bx
  1090.     sub    ax, offset NBPtable.tab_entry.tup_name
  1091.     sub    ax, 1
  1092.     mov    NBPtable.tab_entry.tup_name, al
  1093.  
  1094.     mov    cx, myip_name_len    ; append IPADDR command to our IP
  1095.     movseg    es,cs
  1096.     mov    si, offset myip_name    ; ds:si -> source
  1097.     mov    di, bx            ; es:di -> dest
  1098.     rep    movsb
  1099.  
  1100.     ; Register our name with NBP agent
  1101.     mov    NBP.nbp_command, NBP_REGISTER
  1102.     mov    NBP.nbp_compfun.offs, 0        ; No completion routine [jgn]
  1103.     mov    NBP.nbp_compfun.segm, 0
  1104.     mov    NBP.nbp_buffptr.offs, offset NBPtable
  1105.     mov    NBP.nbp_buffptr.segm, ds
  1106.     mov    NBP.nbp_interval, 01H
  1107.     mov    NBP.nbp_retry, 03H
  1108.     mov    bx, offset NBP
  1109.     call    doATint
  1110.  
  1111.     cmp    NBP.nbp_status, 00H
  1112.     je    atinit_done
  1113.  
  1114. nbp_no_register:
  1115.     mov    ax, NBP.nbp_status
  1116.     mov    dtemp, ax
  1117.     mov    di, offset dtemp
  1118.     mov    dx, offset nbp_no_register_msg    ; display error msg
  1119.     call    print_number
  1120.  
  1121.     mov    DDPio.ddp_command, DDP_CLOSESOCKET
  1122.     mov    bx, offset DDPio
  1123.     call    doATint                ; close the assigned socket
  1124.  
  1125.     jmp    error_ret            ; skip ahead to return
  1126.  
  1127. ;**** LocalTalk PC Card initialized, ready to TSR
  1128. atinit_done:
  1129.     movseg    ds,cs
  1130.     clc
  1131.     ret
  1132.  
  1133. ;**** Got an error while initializing LocalTalk PC Card
  1134. error_wrt:                    ; Display an error message
  1135.     movseg    ds,cs
  1136.     stc
  1137.     ret
  1138. error_ret:                ; Board not initialized
  1139.     mov    dx,offset null_msg    ;error message already printed.
  1140.     stc
  1141.     ret
  1142.  
  1143.     public    print_parameters
  1144. print_parameters:
  1145. ;echo our command-line parameters
  1146.     ret
  1147.  
  1148. ;*******************************************
  1149.  
  1150. ; Modify ATALK.SYS interrupt number in doATint code (self-modifying code!)
  1151. ATPatch:
  1152.     mov    al, dl                ; Load new interrupt number
  1153.     movseg    es,cs
  1154.     lea    bx, doATint            ; es:bx=offset of doATint code
  1155.     inc    bx                ; skip to operator for INT
  1156.     mov    es:[bx], al            ; modify the code
  1157.     ret
  1158.  
  1159. ; Get ATALK.SYS interrupt number
  1160. ATGetInt:
  1161.     movseg    es,cs
  1162.     lea    bx, doATint            ; es:bx=offset of doATint code
  1163.     inc    bx                ; skip to operator for INT
  1164.     mov    al, es:[bx]            ; load operator for INT
  1165.     xor    ah, ah                ; zero high byte
  1166.     ret                    ; return INT# to caller
  1167.  
  1168. ;*******************************************
  1169.  
  1170. ;*******************************************
  1171.  
  1172. ; caller must set ds:si -> dest for string, dx 16-bit value to sprint
  1173. decstr:
  1174.     mov    di,dx
  1175.     cmp    dx, 0
  1176.     jne    decstr_nonzero
  1177.     mov    al,'0'            ;yes - easier to just print it, than
  1178.     jmp    chrstr            ;  to eliminate all but the last zero.
  1179. decstr_nonzero:
  1180.  
  1181.     xor    ax,ax            ;start with all zeroes in al,bx,bp
  1182.     mov    bp,ax
  1183.  
  1184.     mov    cx,16            ;16 bits in one 16 bit registers.
  1185. decstr_1:
  1186.     rcl    di,1
  1187.     xchg    bp,ax
  1188.     call    addbit
  1189.     xchg    bp,ax
  1190.     adc    al,al
  1191.     daa
  1192.     loop    decstr_1
  1193.  
  1194.     mov    cl,'0'            ;prepare to eliminate leading zeroes.
  1195.     call    bytestr            ;output the first two.
  1196.     mov    ax,bp
  1197.     jmp    wordstr            ;output the next four.
  1198.  
  1199. addbit:    adc    al,al
  1200.     daa
  1201.     xchg    al,ah
  1202.     adc    al,al
  1203.     daa
  1204.     xchg    al,ah
  1205.     ret
  1206.  
  1207. ;print the char in al at ds:bx
  1208. chrstr:
  1209.     mov    byte ptr [bx], al
  1210.     inc    bx
  1211.     ret
  1212.  
  1213. wordstr:
  1214.     push    ax
  1215.     mov    al,ah
  1216.     call    bytestr
  1217.     pop    ax
  1218. bytestr:
  1219.     mov    ah,al
  1220.     shr    al,1
  1221.     shr    al,1
  1222.     shr    al,1
  1223.     shr    al,1
  1224.     call    digstr
  1225.     mov    al,ah
  1226. digstr:
  1227.     and    al,0fh
  1228.     add    al,90h    ;binary digit to ascii hex digit.
  1229.     daa
  1230.     adc    al,40h
  1231.     daa
  1232.     cmp    al,cl            ;leading zero?
  1233.     je    digstr_1
  1234.     mov    cl,-1            ;no more leading zeros.
  1235.     jmp    chrstr
  1236. digstr_1:
  1237.     ret
  1238.  
  1239. ; caller must set ds:dx -> argument string, ds:di -> AddrBlk struct
  1240. print_at_addr:
  1241. ;enter with dx -> dollar terminated name of number, di ->dword.
  1242. ;exit with the number printed and the cursor advanced to the next line.
  1243.     mov    ah,9            ;print the name of the number.
  1244.     int    21h
  1245.     mov    ax, [di].ablk_network    ;print the network number
  1246.     xchg    ah, al            ; byte-swap network number [jgn]
  1247.     mov    dx, 00H
  1248.     push    di
  1249.     call    decout
  1250.     pop    di
  1251.     mov    al, ':'
  1252.     call    chrout
  1253.     xor    ax, ax
  1254.     mov    al, [di].ablk_nodeid    ; print the nodeid number
  1255.     push    di
  1256.     call    decout
  1257.     pop    di
  1258.     mov    al, ':'
  1259.     call    chrout
  1260.     xor    ax, ax
  1261.     mov    al, [di].ablk_socket    ; print the socket number
  1262.     call    decout
  1263.     mov    al,CR
  1264.     call    chrout
  1265.     mov    al,LF
  1266.     call    chrout
  1267.     ret
  1268.  
  1269. ; caller must set ds:dx -> argument string, ds:di -> 32 bit ip address
  1270. print_ip_addr:
  1271. ;enter with dx -> dollar terminated name of number, di ->dword.
  1272. ;exit with the number printed and the cursor advanced to the next line.
  1273.     mov    ah,9            ;print the name of the number.
  1274.     int    21h
  1275.     mov    al, '['
  1276.     call    chrout
  1277.     xor    ax, ax
  1278.     mov    al, [di]        ;print first byte in decimal.
  1279.     mov    dx, 00H
  1280.     push    di
  1281.     call    decout
  1282.     pop    di
  1283.     mov    al, '.'
  1284.     call    chrout
  1285.     xor    ax, ax
  1286.     mov    al, [di+1]        ; print second byte in decimal
  1287.     push    di
  1288.     call    decout
  1289.     pop    di
  1290.     mov    al, '.'
  1291.     call    chrout
  1292.     xor    ax, ax
  1293.     mov    al, [di+2]        ; print third byte in decimal
  1294.     push    di
  1295.     call    decout
  1296.     pop    di
  1297.     mov    al, '.'
  1298.     call    chrout
  1299.     xor    ax, ax
  1300.     mov    al, [di+3]        ; print fourth byte in decimal
  1301.     call    decout
  1302.     mov    al, ']'
  1303.     call    chrout
  1304.     mov    al,CR
  1305.     call    chrout
  1306.     mov    al,LF
  1307.     call    chrout
  1308.     ret
  1309.  
  1310. code    ends
  1311.  
  1312.     end
  1313.  
  1314.