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

  1. version    equ    3
  2.  
  3. ; Packet driver to simulate Ethernet on Novell IPX protocol.
  4. ;
  5. ; Paul Kranenburg
  6. ; Department of Computer Science
  7. ; University of Leiden
  8. ; Niels Bohrweg 1
  9. ; PO Box 9512
  10. ; 2300 RA Leiden
  11. ; The Netherlands
  12. ; e-mail: pk@cs.leidenuniv.nl
  13. ;
  14. ;
  15. ; File: ipxpkt.asm
  16. ;
  17. ;
  18. ; General description:
  19. ;
  20. ; Take destination from the Ethernet packet and feed it to IPX
  21. ; in the Event Control Block Immediate Address field.
  22. ;
  23. ; IPX packets are 576 bytes at most, 30 are needed for the IPX header
  24. ; leaving 546 bytes of user data. Another 4 bytes are used to describe
  25. ; fragments.
  26. ; If NO_OF_SND_BUFS is set to 1, this yields an MTU for this driver of 528.
  27. ; (546 - 4 - sizeof(Ether header)[=14]).
  28. ; If IPX trail is used another 32 bytes are lost (MTU = 496).
  29. ;
  30. ; If NO_OF_SND_BUFS is set to 3, the Ethernet packet is broken into at most
  31. ; 3 fragments. These are tagged with a Fragment id and shipped.
  32. ;
  33. ; On reception, fragments are kept on a linked list ordered by fragment number
  34. ; and keyed by source node address and fragment id.
  35. ; An IPX event is scheduled to allow for timeout of pending reassembly queues.
  36. ;
  37. ; If all fragments are reassembled, the client is called to provide a buffer for
  38. ; the packet.
  39. ;
  40. ; [ To save on buffer space, the driver could conceivably do with some minimum
  41. ;  number of buffers and call recv_find as soon as a fragment arrives, copy
  42. ;  the contents, and only call recv_copy when all fragments have arrived. However,
  43. ;  I don't think there is a way to notify the client in case a fragment gets lost.]
  44. ;
  45. ; In this code, the number of receive buffers (NO_OF_RCV_BUFS) has been set
  46. ; to 6 (a wild guess).
  47. ; This driver has yet to be tested in a gateway under heavy load. One probably
  48. ; needs more buffers in this case.
  49. ;
  50. ; Buffer space for the receive buffers is allocated after the "end_resident"
  51. ; label.
  52. ; REMOVED 6/22/92 by adding memory allocation to the skeleton.
  53. ; There is a potential problem here: we start listening for packets
  54. ; using these buffers while still in the initialisation code, which is overlaid
  55. ; by the receive buffers. This is why interrupts are turned off wherever possible.
  56. ;
  57. ;
  58. ; CHANGELOG.
  59. ;
  60. ; 15 Feb 1991  apb
  61. ; The code for determining the ethernet address from the ipx address used
  62. ; word operations instead of byte operations in two places.
  63. ;
  64. ; 13 Feb 1991  apb
  65. ; Changed method of incorporating IPX net address into simulated ethernet
  66. ; address -- there's no need to get fancy if there is space for the entire
  67. ; net address to fit.
  68. ;
  69. ; 11 Feb 1991  apb
  70. ; Fixed usage message.
  71. ; Added message about long wait while GET_LOCAL_TARGET does its work.
  72. ; (XXX there must be a better way of doing this.)
  73. ;
  74. ; 07/16/90
  75. ; Decoupled simulated ethernet address from IPX node address in routing tables,
  76. ; allowing for unique addresses in nets like ARCNET with only a one byte
  77. ; node address.
  78. ; Thanks to Robert Roll and Reid Sweatman of the University of Utah
  79. ; for pointing this out.
  80. ; IPXPKT accepts a command line option of the from `-n [<no_bytes>]' to specify
  81. ; the number of significant bytes in the IPX node address. If less then EADDR_LEN,
  82. ; the presented ethernet address will get supplemented with some bytes from
  83. ; the IPX node address to (hopefully) create a unique address among the nodes
  84. ; in the network involved.
  85. ; If `<no_bytes>' is omitted, the number of significant bytes will be set as the
  86. ; number of bytes left in the node address after stripping leading zeroes.
  87. ;
  88. ; 07/12/90
  89. ; Reorganize initialisation; do GET_ADDESS etc., before posting LISTEN's
  90. ;
  91. ; 05/16/90
  92. ; New socket number used when TRAIL enabled (0x6181).
  93. ; Enables co-existance of original and "TRAIL" versions of packet driver.
  94. ; You can start both an old and a new experimental driver in your gateway,
  95. ; but watch those IP subnet addresses.
  96. ;
  97. ; 05/15/90
  98. ; Corrected byte-order of IPX socket.
  99. ; Socket number NOT actually changed (== 0x6180, in dynamic range)
  100. ;
  101. ; 05/15/90
  102. ; Add dummy GET_LOCAL_TARGET call to force some traffic to IPX from a bridge.
  103. ; This will get the local net address to IPX. Define TRY_GET_LOCAL_TARGET if
  104. ; you want to use this.
  105. ;
  106. ; 05/07/90
  107. ; Add statistics gathering on various table lookups.
  108. ; Compile option STAT. Use ipxstat.c for display (derivative of version 5.0 `stat.c').
  109. ;
  110. ; 05/04/90
  111. ; Fixed case of register trashing in route code.
  112. ; Add IPX 32-byte trailer for bridge routing.
  113. ; Compile option TRAIL.
  114. ;
  115. ; 05/03/90
  116. ; Add routing table.
  117. ; Net/node addresses of incoming packets are put routing table along with
  118. ; immediate address field in ecb struct.
  119. ; Outgoing packets have the their net- and immediate address looked up
  120. ; in the table with the node address as key.
  121. ; Special case: broadcast packets are sent with packet type 0x14 through
  122. ; permanent entry in routing table.
  123. ;
  124. ; 05/03/90
  125. ; **REMOVED** 07/17/90
  126. ; Add compile option to declare receive buffer space at compile time.
  127. ; Compile option NOT_SO_SAVE; if defined, buffer space is allocated beginning at
  128. ; `end_resident' else space is reserved by compiler
  129. ;
  130. ; 05/02/90
  131. ; Merge `fill_ipxhdr' into `route'.
  132. ;
  133.  
  134. ;DEBUG            EQU    1
  135. TRY_GET_LOCAL_TARGET    EQU    1
  136. STAT            EQU    1
  137. TRAIL            EQU    1
  138. ETH_CONSTR        EQU    3
  139.  
  140.     include    defs.asm
  141.  
  142. MAX_IPX_LEN    =    576        ; Maximum packet size that can be
  143.                     ; shipped through IPX
  144. ifdef TRAIL
  145. IP_socket    =    08161h        ; Socket allocated for Blue book Ether
  146.                     ; on IPX with TRAILS (BYTE-SWAPPED)
  147. else
  148. IP_socket    =    08061h        ; Socket allocated for
  149.                     ; Blue book Ether on IPX (BYTE-SWAPPED)
  150. endif
  151.  
  152. PEP        =    4        ; Packet Exchange Packet (ipx_type)
  153. GBP        =    014h        ; Global Broadcast Packet (ipx_type)
  154. RTE_TICK    =    37        ; Interval between calls to rte_ticker,
  155.                     ; 37 is approx. 2 seconds
  156.  
  157. ipx_header    struc
  158. ipx_chksum    dw    ?        ; Checksum, network byte order
  159. ipx_len        dw    ?        ; Packet length,   "
  160. ipx_prot    db    ?        ; Transport protocol
  161. ipx_type    db    ?        ; Packet type
  162. ipx_destnet    db    4 dup(?)    ; Destination network
  163. ipx_destnode    db    6 dup(?)    ; Destination node
  164. ipx_destsock    dw    ?        ; Destination socket
  165. ipx_srcnet    db    4 dup(?)    ; Source network
  166. ipx_srcnode    db    6 dup(?)    ; Source node
  167. ipx_srcsock    dw    ?        ; Source socket
  168. ifdef TRAIL
  169. ipx_trail    db    8 * 4 dup(?)    ; IPX gateway trail
  170. endif
  171. ipx_header    ends
  172.  
  173.  
  174. frag_dscr    struc
  175. frag_addr    dd    ?        ; Fragment address
  176. frag_size    dw    ?        ; Fragment size
  177. frag_dscr    ends
  178.  
  179. ecb        struc
  180. ecb_link    dd    ?        ;
  181. ecb_esr        dd    ?        ; Event Service Routine
  182. ecb_inuse    db    ?        ; In Use field
  183. ecb_cmplt    db    ?        ; Completion Code
  184. ecb_sock    dw    ?        ; Socket Number
  185. ecb_ipxwork    db    4 dup (?)    ; IPX reserved workspace
  186. ecb_drvwork    db    12 dup (?)    ; Driver reserved workspace
  187. ecb_ia        db    6 dup (?)    ; Immediate Address
  188. ecb_fragcnt    dw    ?        ; Fragment count
  189. ;ecb_dscr    =    $        ; Start of Fragment descriptor list
  190. ecb        ends
  191.  
  192. aes_ecb        struc
  193. aes_link    dd    ?        ;
  194. aes_esr        dd    ?        ; Event Service Routine
  195. aes_inuse    db    ?        ; In Use field
  196. aes_work    db    5 dup (?)    ; Driver reserved workspace
  197. aes_ecb        ends
  198.  
  199.  
  200. ether_frag    struc
  201. ef_fragno    db    ?        ; This fragment number
  202. ef_fragtot    db    ?        ; Total number of fragments comprising the packet
  203. ef_fragid    dw    ?        ; Fragment Id
  204. ether_frag    ends
  205.  
  206. queue_entry    struc
  207. q_aes        db (size aes_ecb) dup(?); AES structure, used for reassembly timeouts
  208. q_filler    db    0
  209. q_count        db    0        ; Number of fragments currently queued here
  210. q_net        db    SIZE ipx_srcnet dup(?)
  211. q_node        db    SIZE ipx_srcnode dup(?)    ; Source node
  212. q_fragid    dw    ?            ; Fragment Id
  213. q_len        dw    ?            ; Total length of user data queued here
  214. q_ecb        dd    ?            ; Ecb pointer to fragment
  215. queue_entry    ends
  216.  
  217. u_buf        struc
  218. u_ecb        db (size ecb) dup(?)
  219. u_ipx_frag    db (size frag_dscr) dup(?)
  220. u_frag_frag    db (size frag_dscr) dup(?)
  221. u_data_frag    db (size frag_dscr) dup(?)
  222. u_ipx        db (size ipx_header) dup(?)
  223. u_ether_frag    db (size ether_frag) dup(?)
  224. ;u_data        LABEL        BYTE
  225. u_buf        ends
  226.  
  227. MAX_PAYLOAD    =    MAX_IPX_LEN - SIZE ipx_header - SIZE ether_frag
  228.  
  229. ;routing table entry
  230. rt_ent        struc
  231. rt_ether    db    EADDR_LEN dup(?)    ; Ethernet address of target: lookup key
  232. rt_net        db    SIZE ipx_srcnet dup(?)    ; Net address of target
  233. rt_node        db    SIZE ipx_srcnode dup(?)    ; Node address of target
  234. rt_gate        db    SIZE ecb_ia dup(?)    ; First hop on route to above
  235. rt_x_pkt    db    ?        ; IPX packet type to send packet with
  236. ;;rt_trail    db    ?        ; This node uses IPX trail
  237. rt_age        dw    ?        ; Usage indicator for this entry
  238. rt_ent        ends
  239.  
  240. print$        macro    string
  241. ;---------------------------------------;
  242. ;  sends $ terminated string to screen  ;
  243. ;---------------------------------------;
  244.         push    dx
  245.         mov     ah,9
  246.         mov     dx,offset &string&      ; print $ terminated string
  247.         int     21h
  248.         pop    dx
  249.         endm
  250.  
  251. ; ipx function numbers
  252. OPEN_SOCKET        =    0
  253. CLOSE_SOCKET        =    1
  254. GET_LOCAL_TARGET    =    2
  255. SEND_PACKET        =    3
  256. LISTEN            =    4
  257. SCHEDULE_EVENT        =    5
  258. CANCEL_EVENT        =    6
  259. SCHEDULE_SPECIAL_EVENT    =    7
  260. GET_NODE_ADDRESS    =    9
  261. RELINQUISH        =    0Ah
  262.  
  263. call_ipx    macro    opcode,reg1,reg2,reg3,reg4,reg5,reg6,reg7,reg8
  264.         irp N, <reg1,reg2,reg3,reg4,reg5,reg6,reg7,reg8>
  265.             ifnb <N>
  266.                 push    N
  267.             endif
  268.         endm
  269.         mov    bx, opcode
  270. ;better be save here and use Code segment explicitly
  271.         call    cs:IPXentry
  272.         irp N, <reg8,reg7,reg6,reg5,reg4,reg3,reg2,reg1>
  273.             ifnb <N>
  274.                 pop    N
  275.             endif
  276.         endm
  277.         endm
  278.  
  279. ifdef STAT
  280. statinc        macro    loc
  281.         local    a
  282. ;affects flags register (NOT carry)
  283.         inc    cs:loc
  284.         jnz    a
  285.         inc    cs:loc+2
  286.     a:
  287.         endm
  288. else
  289. statinc        macro    loc
  290.         endm
  291. endif
  292.  
  293. code    segment    word public
  294.     assume    cs:code, ds:code
  295.  
  296. IPXentry    dd    ?
  297. FragmentID    dw    ?
  298.  
  299. my_net_address    db    4 dup(?)    ; contiguous 10 byte addrss-area as IPX wants it
  300. my_node_address    db    6 dup(?)
  301.  
  302. no_bytes    dw    EADDR_LEN, 0    ; number of significant bytes in IPX node address
  303.                     ; set as command line option.
  304. init_cmplt    dw    0
  305.  
  306. dummy        db    10 dup(0ffh)    ; dummy addr/socket
  307.         dw    05104h        ; what socket to use (???)
  308.         db    6 dup(?)    ; returned address
  309.  
  310.  
  311. NO_OF_FRAGMENTS    =    3
  312. NO_OF_RCV_BUFS    =    6
  313. NO_OF_SND_BUFS    =    3
  314. NO_OF_QUEUES    =    NO_OF_RCV_BUFS        ; ????
  315. NO_OF_RTES    =    30
  316.  
  317. reass_queues    queue_entry    NO_OF_QUEUES dup(<>)
  318.  
  319. rcv_bufs    u_buf        NO_OF_RCV_BUFS dup(<>)
  320. snd_bufs    u_buf        NO_OF_SND_BUFS dup(<>)
  321.  
  322. ifdef STAT
  323. ;;        org    ($ + 1) and 0fffeh
  324. ; keep ID string an even number of bytes (including terminating zero and count)
  325.         db    "RTE_TABL", 0, NO_OF_RTES
  326. endif
  327. rte        rt_ent        NO_OF_RTES dup(<>)
  328. rte_end        dw        0
  329. rte_scache    dw        0
  330. rte_rcache    dw        0
  331. rte_aes        aes_ecb        <>
  332.  
  333. ifdef STAT
  334. ;;        org    ($ + 1) and 0fffeh
  335.         db    "IPXSTAT", 0    ; keep this string an even number of bytes
  336. queue_full    dw    2 dup(0)
  337. route_drop    dw    2 dup(0)
  338. scache_miss    dw    2 dup(0)
  339. rcache_miss    dw    2 dup(0)
  340. route_loops    dw    2 dup(0)
  341. route_lookups    dw    2 dup(0)
  342. endif
  343.  
  344. ;-------------------------------------------------------------------------------
  345. ;
  346. ; local functions
  347. ;
  348. ; A NOTE on style:
  349. ;
  350. ; the functions below seem to liberally load and reload pointers into
  351. ; a register pair involving the ds segment register.
  352. ; In fact, ds almost always contains the code segment as "assumed" above.
  353. ; Also, the distinction between pointers to ecb's and ubuf's / queue's is not made
  354. ; most of the time. This is alright as long as the ecb structures remain the first
  355. ; ones declared in u_buf and queue.
  356. ; Need to work out a consistent register usage some day...
  357. ;
  358.  
  359. find_queue    proc    near
  360.     ;
  361.     ; Find/allocate a queue-entry where an ether fragment can be stored.
  362.     ; On entry: es:di -> source node address.
  363.     ;           dx == fragment Id.
  364.     ; Out: si == 0 if no queue entry available,
  365.     ;      otherwise: (ds:)si -> allocated queue-entry.
  366.     ; Must be called with interrupts disabled.
  367.  
  368.     push    cx
  369.     push    bx
  370.     mov    cx, NO_OF_QUEUES
  371.     lea    si, reass_queues
  372.     mov    bx, 0
  373.  
  374. fq_loop:
  375.     mov    al, [si].q_count
  376.     or    al, al
  377.     jnz    fq_1
  378.     or    bx, bx        ;
  379.     jne    fq_2        ; remember first entry not in use
  380.     mov    bx, si        ;
  381.     jmp    short fq_2
  382.  
  383. fq_1:
  384.     mov    ax, cx        ; can use AX in stead of `push cx'
  385.     push    si
  386.     push    di
  387.     add    si, q_net
  388.     mov    cx, SIZE q_net + SIZE q_node
  389.     cld
  390.     repe    cmpsb
  391.     pop    di
  392.     pop    si
  393.     mov    cx, ax
  394.     jne    fq_2
  395.     cmp    dx, [si].q_fragid
  396.     jne    fq_2
  397.     jmp    short fq_x
  398.  
  399. fq_2:
  400.     add    si, SIZE queue_entry
  401.     loop    fq_loop
  402.  
  403.     mov    si, bx
  404.  
  405. ifdef STAT
  406.     or    si, si
  407.     jnz    fq_stat_1
  408.     statinc    queue_full
  409. fq_stat_1:
  410. endif
  411.  
  412. fq_x:
  413.     pop    bx
  414.     pop    cx
  415.     ret
  416. find_queue    endp
  417.  
  418. enqueue        proc    near
  419.     ; Queue an etherpacket fragment on appropriate queue
  420.     ; On entry: es:si -> received ecb.
  421.     ;           cx = length of data in this fragment
  422.     ; Out: carry set if no space available.
  423.     ;      zero flag set if packet on queue complete.
  424.     ;      ds:si -> queue_entry on which fragment was queued.
  425.  
  426.     push    si
  427.     push    es
  428.     mov    ax, 0
  429.     mov    es:[si].u_ecb.ecb_link.offs, ax        ; clear link-field
  430.     mov    es:[si].u_ecb.ecb_link.segm, ax
  431.     mov    di, si                    ; es:di -> ecb
  432.     mov    dx, es:[si].u_ether_frag.ef_fragid
  433.     push    di
  434. ;    lea    di, es:[si].u_ipx.ipx_srcnode
  435.     lea    di, es:[si].u_ipx.ipx_srcnet
  436.     call    find_queue
  437.     pop    di
  438.  
  439.     or    si, si
  440.     jnz    enq_0
  441.     add    sp, 4
  442.     stc
  443.     ret
  444.  
  445. enq_0:
  446.     mov    dl, es:[di].u_ether_frag.ef_fragno
  447.     mov    dh, es:[di].u_ether_frag.ef_fragtot
  448.     cmp    [si].q_count, 0
  449.     jne    enq_3
  450.  
  451. ;this is the first fragment we receive
  452.     call    rte_enter        ; record their route
  453.     pop    [si].q_ecb.segm
  454.     pop    [si].q_ecb.offs
  455.     mov    [si].q_len, cx
  456.     mov    [si].q_count, 1
  457.     cmp    dh, 1            ;
  458.     jne    enq_1            ; short cut if fragment count == 1.
  459.     clc
  460.     ret
  461.  
  462. ;initialise queue structure a bit more...
  463. enq_1:
  464.     mov    ax, es:[di].u_ether_frag.ef_fragid
  465.     mov    [si].q_fragid, ax
  466.  
  467. ;copy source node address
  468.     mov    bx, SIZE q_net + SIZE q_node - 1
  469.  
  470. enq_2:
  471. ;    mov    al, es:[di+bx].u_ipx.ipx_srcnode
  472.     mov    al, es:[di+bx].u_ipx.ipx_srcnet
  473.     mov    ds:[si+bx].q_net, al
  474.     sub    bx, 1
  475.     jnc    enq_2
  476.  
  477.     mov    ax, cs
  478.     mov    [si].q_aes.aes_esr.segm, ax
  479.     mov    [si].q_aes.aes_esr.offs, offset reass_timeout
  480.     mov    ax, ds
  481.     mov    es, ax
  482.     mov    ax, 2            ; two ticks to timeout
  483.     call_ipx    SCHEDULE_SPECIAL_EVENT,si,dx
  484.     cmp    dh, [si].q_count
  485.     clc
  486.     ret
  487.  
  488. ; add ecb to existing queue, keep list ordered by fragment number.
  489. enq_3:
  490.     lea    ax, [si].q_ecb
  491.     push    ax            ; put link field address on stack
  492.     push    ds
  493.     les    di, [si].q_ecb
  494.  
  495. enq_4:
  496.     mov    ax, es            ; are we at end of list?
  497.     or    ax, di
  498.     jz    enq_5
  499.     cmp    dl, es:[di].u_ether_frag.ef_fragno    ; link after this frag?
  500.     jb    enq_5
  501.     add    sp, 4
  502. ;    lea    ax, es:[di].u_ecb.ecb_link
  503. ;    push    ax
  504.     push    di                    ; push `prev'-link
  505.     push    es
  506.     les    di, es:[di].u_ecb.ecb_link        ; load `next'-link
  507.     jmp    enq_4
  508.  
  509. ; enter here with two addresses on the stack:
  510. ;    1) address of ecb to link in
  511. ;    2) address of link field after which to link
  512. ; es:di contains the "next" link.
  513.  
  514. enq_5:
  515.     mov    ax, es                    ; temp = next
  516.     mov    bx, di
  517.     pop    es                    ; get prev
  518.     pop    di
  519.     pop    es:[di].segm                ; prev->next = this one
  520.     pop    es:[di].offs
  521.     les    di, es:[di]                ; load `this one'
  522.     mov    es:[di].u_ecb.ecb_link.segm, ax        ; `this one'->next = temp
  523.     mov    es:[di].u_ecb.ecb_link.offs, bx
  524.     add    [si].q_len, cx                ; update total queued data
  525.     inc    [si].q_count                ; update fragcount
  526.     cmp    dh, [si].q_count            ; return `zero' if all there
  527.     clc
  528.     ret
  529.  
  530. enqueue        endp
  531.  
  532. dequeue        proc    near
  533.     ; Send reassembled packet to client and reschedule receive buffers.
  534.     ; On entry: ds:si -> queue.
  535.  
  536.     mov    cx, [si].q_len
  537.     les    di, [si].q_ecb
  538.     les    di, es:[di].u_data_frag.frag_addr
  539.     add    di, 2 * EADDR_LEN
  540.  
  541.     mov    dl, BLUEBOOK        ;assume bluebook Ethernet.
  542.     mov    ax, es:[di]
  543.     xchg    ah, al
  544.     cmp     ax, 1500
  545.     ja    BlueBookPacket
  546.     inc    di            ;set di to 802.2 header
  547.     inc    di
  548.     mov    dl, IEEE8023
  549. BlueBookPacket:
  550.  
  551.     push    si
  552.     call    recv_find
  553.     pop    si
  554.     mov    ax, es
  555.     or    ax, di
  556.     jz    deq_2
  557.  
  558.     mov    dh, [si].q_count
  559.     mov    cx, [si].q_len
  560.     push    si            ; save our queue address
  561.     push    ds
  562.     push    di            ; save their buffer address
  563.     push    es
  564.     push    cx
  565.     lds    si, ds:[si].q_ecb
  566.     cld
  567.  
  568. ;all set, es:di -> user buffer, ds:si -> first fragment
  569. ;??? save count and source pointer for call to recv_copy
  570.  
  571. deq_1:
  572.     mov    cx, ds:[si].u_ipx.ipx_len
  573.     xchg    cl, ch
  574.     sub    cx, (SIZE ipx_header + SIZE ether_frag)
  575.     push    si
  576.     push    ds
  577.     lds    si, ds:[si].u_data_frag.frag_addr
  578.     rep    movsb
  579.     pop    ds
  580.     pop    si
  581.     lds    si, ds:[si].u_ecb.ecb_link
  582.     dec    dh
  583.     jnz    deq_1
  584.  
  585.     pop    cx            ; recover packet length and address
  586.     pop    ds            ; for completion call
  587.     pop    si            ;
  588.     call    recv_copy
  589.  
  590.     pop    ds            ; recover queue address
  591.     pop    si            ;
  592.  
  593. deq_2:
  594.     mov    ax, ds
  595.     mov    es, ax
  596.     call_ipx    CANCEL_EVENT,si
  597.  
  598.     push    si
  599.     mov    dh, [si].q_count
  600.     les    si, ds:[si].q_ecb
  601.  
  602. deq_3:
  603.     mov    bx, es:[si].ecb_link.offs
  604.     mov    cx, es:[si].ecb_link.segm
  605.     call    listen_proc
  606.     mov    si, bx
  607.     mov    es, cx
  608. ;    les    si, es:[si].u_ecb.ecb_link
  609.     dec    dh
  610.     jnz    deq_3
  611.     pop    si
  612.     mov    [si].q_count, 0
  613.     ret
  614. dequeue        endp
  615.  
  616. reass_timeout    proc    far
  617.     ; Called by AES when reassembly timeout occurs.
  618.     ; On entry: es:si pointer to ecb.
  619.     ;
  620.  
  621.     push    ds
  622.     mov    ax, cs
  623.     mov    ds, ax
  624.     push    si
  625.     push    es
  626.     mov    dh, es:[si].q_count
  627.     les    si, es:[si].q_ecb
  628.  
  629. reass_to_3:
  630.     mov    bx, es:[si].ecb_link.offs
  631.     mov    cx, es:[si].ecb_link.segm
  632.     call    listen_proc
  633.     mov    si, bx
  634.     mov    es, cx
  635.     dec    dh
  636.     jnz    reass_to_3
  637.  
  638.     pop    es
  639.     pop    si
  640.     mov    es:[si].q_count, 0
  641.  
  642.     pop    ds
  643.     ret
  644. reass_timeout    endp
  645.  
  646. receiver    proc    far
  647.     ;
  648.     ; On entry: es:si -> ecb.
  649.     ;
  650.  
  651.     push    ds
  652.     mov    ax, cs
  653.     mov    ds, ax
  654.     mov    al, es:[si].u_ecb.ecb_cmplt
  655.     or    al, al
  656.     jnz    receiver_err
  657.  
  658.     cmp    es:[si].u_ecb.ecb_fragcnt, NO_OF_FRAGMENTS
  659.     jne    receiver_err
  660.  
  661. ;IPX receives its own broadcasts because
  662. ;source and destination sockets are the same
  663. ;if ours, ignore
  664.  
  665.     mov    ax, si
  666.     mov    di, si
  667.     add    di, ecb_ia
  668.     lea    si, my_node_address
  669.     mov    cx, SIZE my_node_address
  670.     cld
  671.     repe    cmpsb
  672.     mov    si, ax
  673.     jz    receiver_x
  674.  
  675.     mov    cx, es:[si].u_ipx.ipx_len
  676.     xchg    cl, ch
  677.     sub    cx, (SIZE ipx_header + SIZE ether_frag)
  678.     jbe    receiver_err
  679.  
  680.     call    enqueue
  681.     jc    receiver_err
  682.     jnz    rec_1
  683.     call    dequeue
  684.  
  685. rec_1:
  686.     pop    ds
  687.     cli
  688.     ret
  689.  
  690. receiver_err:
  691.     call    count_in_err
  692.  
  693. receiver_x:
  694.     call    listen_proc        ; post listen again
  695.     pop    ds
  696.     cli            ; must return with interrupts disabled, says Novell.
  697.     ret
  698. receiver    endp
  699.  
  700. listen_proc    proc    near
  701.     ;
  702.     ; Post to u_buf for reception.
  703.     ; On entry: es:si -> receive-ecb
  704.     ;
  705.  
  706.     push    bx
  707.  
  708. ;fill in ecb
  709.     mov    es:[si].u_ecb.ecb_esr.offs, offset receiver
  710.     mov    ax, cs
  711.     mov    word ptr es:[si].u_ecb.ecb_esr.segm, ax
  712.     mov    es:[si].u_ecb.ecb_sock, IP_socket
  713.     call_ipx    LISTEN,es,si,di,dx,cx
  714.  
  715.     pop    bx
  716.     ret
  717.  
  718. listen_proc    endp
  719.  
  720. rte_ticker    proc    far
  721.     ;
  722.     ; ESR service routine called by AES
  723.     ; Ages all entries in routing table
  724.     ; executes entirely with disabled interrupts
  725.     ;
  726.     ; On entry: es:si -> ecb
  727.  
  728.     push    ds
  729.     mov    ax, cs
  730.     mov    ds, ax
  731.  
  732.     mov    dx, rte_end
  733.     lea    di, rte
  734.  
  735. rtick_1:
  736.     add    di, SIZE rt_ent        ; leave broadcast entry alone
  737.     cmp    di, dx
  738.     jae    rtick_done
  739.     mov    ax, [di].rt_age
  740.     add    ax, 1
  741.     jo    rtick_1
  742.     mov    [di].rt_age, ax
  743.     jmp    rtick_1
  744.  
  745. ;re-schedule ecb
  746. rtick_done:
  747.     mov    ax, RTE_TICK
  748.     call_ipx    SCHEDULE_SPECIAL_EVENT
  749.     pop    ds
  750.     ret
  751. rte_ticker    endp
  752.  
  753. rte_enter    proc    near
  754.     ;
  755.     ; Enter route to table
  756.     ; On entry: es:di -> ecb
  757.     ;
  758.     assume    ds:nothing, es:nothing
  759.  
  760.     push    bx
  761.     push    cx
  762.     push    dx
  763.     push    si
  764.     push    ds
  765.     push    di
  766.     push    es
  767.  
  768.     les    di, es:[di].u_data_frag.frag_addr
  769.     add    di, EADDR_LEN            ; es:di -> src node address
  770.     mov    bx, rte_rcache            ; global, last succesful entry
  771.     call    rte_find            ; will set DS to code seg
  772.     jc    ert_1
  773.  
  774. ifdef STAT
  775.     cmp    rte_rcache, si
  776.     je    ert_stat_1
  777.     statinc    rcache_miss
  778. ert_stat_1:
  779. endif
  780.  
  781.     mov    rte_rcache, si
  782.     jmp    ert_x                ; we already have route to src
  783.  
  784. ert_1:
  785. ;not in table, find free entry
  786. ;    mov    ax, cs
  787. ;    mov    ds, ax                ; ds == code
  788.  
  789.     lea    dx, rte
  790.     add    dx, SIZE rte            ; dx -> beyond rte
  791.     mov    bx, rte_end            ;
  792.     add    rte_end, SIZE rt_ent        ; take the chance
  793.     cmp    bx, dx                ; check whether table full
  794.     jb    ert_2
  795.     sub    rte_end, SIZE rt_ent        ; undo guess
  796.     call    kill_route            ; will leave freed entry in bx
  797.  
  798. ert_2:
  799. ;insert addresses in ecb and ipx into routing table
  800. ; $%#@, must swap registers for string operations
  801. ;
  802.     cld
  803.     mov    ax, ds
  804.     mov    cx, es
  805.     mov    es, ax
  806.     mov    ds, cx
  807.     mov    si, di                ; ds:si -> source address
  808.     mov    di, bx                ; es:di -> rt_ent
  809.  
  810.     add    di, rt_ether
  811.  
  812.     repmov  <SIZE rt_ether>
  813.  
  814.     pop     ds                ; recover ecb from stack
  815.     pop     si                ;
  816.     push    si
  817.     push    ds
  818.  
  819.     mov    ax, si
  820.  
  821.     add    si, u_ipx + ipx_srcnet        ; record source net+node
  822.     repmov    <SIZE rt_net + SIZE rt_node>
  823.  
  824.     mov    si, ax                ; restore si to start of ecb
  825.     add    si, ecb_ia            ; record immediate address
  826.     repmov    <SIZE rt_gate>
  827.  
  828.     mov    es:[bx].rt_x_pkt, PEP        ; packet type
  829.     mov    es:[bx].rt_age, 10        ; usage count (XXX)
  830.  
  831. ert_x:
  832.     pop    es
  833.     pop    di
  834.     pop    ds
  835.     pop    si
  836.     pop    dx
  837.     pop    cx
  838.     pop    bx
  839.     ret
  840. rte_enter    endp
  841.  
  842. kill_route    proc    near
  843.     ;
  844.     ; Delete entry in route table with highest rt_age field
  845.     ; Out: bx -> route entry freed
  846.     ;
  847.  
  848.     push    cx
  849.     push    dx
  850.     push    di
  851.     lea    di, rte
  852.     add    di, SIZE rt_ent        ; leave broadcast entry alone
  853.  
  854.     mov    dx, rte_end
  855.     mov    bx, di
  856.     mov    cx, 0
  857.  
  858. krt_1:
  859.     cmp    di, dx
  860.     je    krt_done
  861.     mov    ax, [di].rt_age
  862.     cmp    ax, cx
  863.     jbe    krt_2
  864.     mov    cx, ax
  865.     mov    bx, di
  866.  
  867. krt_2:
  868.     add    di, SIZE rt_ent
  869.     jmp    krt_1
  870.  
  871. krt_done:
  872. ifdef STAT
  873.     statinc    route_drop
  874. endif
  875.     pop    di
  876.     pop    dx
  877.     pop    cx
  878.     ret
  879. kill_route    endp
  880.  
  881.  
  882. rte_find    proc    near
  883.     ;
  884.     ; Find a route for address
  885.     ; On entry: es:di -> target address we are looking for (EADDR_LEN bytes)
  886.     ;           bx -> entry to start search
  887.     ; Out: ds:si -> route table entry, or carry set if not found
  888.     ;
  889.     assume    ds:code, es:nothing
  890.  
  891.     push    bx
  892.     push    dx
  893.     mov    ax, cs        ; cs == code segment
  894.     mov    ds, ax
  895.  
  896.     mov    dx, rte_end    ; global, points to first invalid rte entry
  897.     mov    ax, bx        ; ax == stopper
  898.     cld
  899.  
  900. frt_1:
  901. ifdef STAT
  902.     statinc    route_loops
  903. endif
  904.     mov    si, bx        ;
  905.     add    si, rt_ether    ; si -> rt_ether field (= key) of current rte-entry
  906.     push    di        ; save di
  907.     mov    cx, SIZE rt_ether
  908.     repe    cmpsb
  909.     pop    di
  910.     je    frt_x        ; compare ok, report succes
  911.     add    bx, SIZE rt_ent    ; next rte-entry
  912.     cmp    bx, dx
  913.     jb    frt_2
  914.     lea    bx, rte        ; end of valid entries, wrap around
  915. frt_2:
  916.     cmp    bx, ax
  917.     jne    frt_1
  918.     stc            ; back where we started, report failure
  919.  
  920. ;found, update cache and prepare output
  921. frt_x:
  922.     mov    si, bx
  923.  
  924. ifdef STAT
  925.     statinc    route_lookups
  926. endif
  927.     pop    dx
  928.     pop    bx
  929.     ret
  930. rte_find    endp
  931.  
  932. route    proc    near
  933.     ;
  934.     ; Determine where to send the packet
  935.     ; On entry: ds:si -> user data, es:di -> ecb
  936.     ;
  937.     assume    ds:nothing, es:nothing
  938.  
  939.     push    bx
  940.     push    cx
  941.     push    ds
  942.     push    si
  943.  
  944. ;find entry in routing table, in: es:di, out: ds:si -> pointer to table entry
  945.  
  946.     push    di
  947.     push    es
  948.     mov    ax, ds            ;
  949.     mov    es, ax            ; es:di -> target address
  950.     mov    di, si            ;
  951.  
  952.     mov    bx, rte_scache        ; global, last succesful entry
  953.     call    rte_find
  954.     pop    es
  955.     pop    di
  956.     jc    route_x
  957.  
  958. ifdef STAT
  959.     cmp    rte_scache, si
  960.     je    route_stat_1
  961.     statinc    scache_miss
  962. route_stat_1:
  963. endif
  964.  
  965.     mov    rte_scache, si        ; remember this entry
  966.     mov    ax, ds:[si].rt_age    ;
  967.     sub    ax, 1            ; decrement usage
  968.     jc    route_1
  969.     mov    ds:[si].rt_age, ax
  970.  
  971. route_1:
  972.     cld
  973.     mov    bx, di            ; remember ecb in BX
  974.  
  975. ifdef TRAIL
  976. ;clear ipx trail fields
  977.     add    di, u_ipx.ipx_trail
  978.     mov    ax, 0
  979.     mov    cx, (SIZE ipx_trail) / 2
  980.     rep    stosw
  981.  
  982.     mov    di, bx
  983. endif
  984.  
  985. ;fill in packet type and destination socket
  986.     mov    al, ds:[si].rt_x_pkt
  987.     mov    es:[di].u_ipx.ipx_type, al    ;PEP
  988.     mov    es:[di].u_ipx.ipx_destsock, IP_socket
  989.  
  990. ;fill in full destination adress
  991.     mov    ax, si            ; save si
  992.     add    si, rt_net
  993.     add    di, u_ipx.ipx_destnet
  994.     repmov    <SIZE ipx_destnet + SIZE ipx_destnode>
  995.     mov    si, ax            ; restore si, di
  996.     mov    di, bx            ;
  997.  
  998. ;fill in immediate address
  999.     add    di, ecb_ia
  1000.     add    si, rt_gate
  1001.     repmov    <SIZE ecb_ia>
  1002.     mov    di, bx            ;
  1003.  
  1004. route_x:
  1005.     pop    si
  1006.     pop    ds
  1007.     pop    cx
  1008.     pop    bx
  1009.     ret
  1010. route    endp
  1011.  
  1012.     public    int_no
  1013. int_no    db    0,0,0,0            ;must be four bytes long for get_number.
  1014.  
  1015.     public    driver_class, driver_type, driver_name, driver_function, parameter_list
  1016. driver_class    db    BLUEBOOK, IEEE8023, 0        ;from the packet spec
  1017. driver_type    db    1        ;from the packet spec
  1018. driver_name    db    'IPX',0        ;name of the driver.
  1019. driver_function    db    2
  1020. parameter_list    label    byte
  1021.     db    1    ;major rev of packet driver
  1022.     db    9    ;minor rev of packet driver
  1023.     db    14    ;length of parameter list
  1024.     db    EADDR_LEN    ;length of MAC-layer address
  1025.   if NO_OF_SND_BUFS eq 1
  1026.     dw    MAX_PAYLOAD - 2 * EADDR_LEN - 2    ;MTU, including MAC headers
  1027.   else
  1028.     dw    GIANT    ;MTU, including MAC headers
  1029.   endif
  1030.     dw    MAX_MULTICAST * EADDR_LEN    ;buffer size of multicast addrs
  1031.     dw    0    ;(# of back-to-back MTU rcvs) - 1
  1032.     dw    0    ;(# of successive xmits) - 1
  1033. int_num    dw    0    ;Interrupt # to hook for post-EOI
  1034.             ;processing, 0 == none,
  1035.  
  1036.     public    rcv_modes
  1037. rcv_modes    dw    4        ;number of receive modes in our table.
  1038.         dw    0,0,0,rcv_mode_3
  1039.  
  1040.     public bad_command_intercept
  1041. bad_command_intercept:
  1042. ;called with ah=command, unknown to the skeleton.
  1043. ;exit with nc if okay, cy, dh=error if not.
  1044.     mov    dh,BAD_COMMAND
  1045.     stc
  1046.     ret
  1047.  
  1048.     public    as_send_pkt
  1049. ; The Asynchronous Transmit Packet routine.
  1050. ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
  1051. ;   interrupts possibly enabled.
  1052. ; Exit with nc if ok, or else cy if error, dh set to error number.
  1053. ;   es:di and interrupt enable flag preserved on exit.
  1054. as_send_pkt:
  1055.     ret
  1056.  
  1057.     public    drop_pkt
  1058. ; Drop a packet from the queue.
  1059. ; Enter with es:di -> iocb.
  1060. drop_pkt:
  1061.     assume    ds:nothing
  1062.     ret
  1063.  
  1064.     public    xmit
  1065. ; Process a transmit interrupt with the least possible latency to achieve
  1066. ;   back-to-back packet transmissions.
  1067. ; May only use ax and dx.
  1068. xmit:
  1069.     assume    ds:nothing
  1070.     ret
  1071.  
  1072.  
  1073.     public    send_pkt
  1074. send_pkt:
  1075. ;enter with ds:si -> packet, cx = packet length.
  1076. ;exit with nc if ok, or else cy if error, dh set to error number.
  1077.     assume    ds:nothing
  1078.  
  1079.     cmp    cx,GIANT        ; Is this packet too large?
  1080.     ja    send_pkt_toobig
  1081.  
  1082.     push    es
  1083.     push    di
  1084.     mov    ax, cs
  1085.     mov    es, ax
  1086.  
  1087. ;first, compute number of fragments needed, keep in dx
  1088.     mov    dx, 0
  1089.     mov    ax, cx
  1090.  
  1091. snd_1:
  1092.     inc    dx
  1093.     sub    ax, MAX_PAYLOAD
  1094.     jnc    snd_1
  1095.  
  1096. ;can we handle this amount?
  1097.     cmp    dx, NO_OF_SND_BUFS
  1098.     jbe    snd_frags_ok
  1099.  
  1100. snd_err:
  1101.     call    count_out_err
  1102.     pop    di
  1103.     pop    es
  1104.     mov    dh, CANT_SEND
  1105.     stc
  1106.     ret
  1107.  
  1108. send_pkt_toobig:
  1109.     mov    dh,NO_SPACE
  1110.     stc
  1111.     ret
  1112.  
  1113. snd_frags_ok:
  1114.     lea    di, snd_bufs
  1115.     push    cx
  1116.     mov    cx, dx
  1117.     mov    bx, 0
  1118.     mov    al, 0
  1119.  
  1120. snd_free_chk:
  1121.     or    al, es:[di+bx].u_ecb.ecb_inuse
  1122.     add    bx, SIZE u_buf
  1123.     loop    snd_free_chk
  1124.  
  1125.     pop    cx
  1126.     or    al, al
  1127.     jnz    snd_err
  1128.  
  1129.     mov    dh, dl
  1130.     mov    dl, 1
  1131.     mov    bx, 0
  1132.     inc    FragmentID
  1133.     push    di
  1134.  
  1135. snd_next_frag:
  1136. ;
  1137. ; dh = total number of fragments to send
  1138. ; dl = current fragment
  1139. ; bx = offset into client buffer (ds:si) for this fragment
  1140. ; cx = bytes to go
  1141. ; es:di = address of current fragment's ecb
  1142. ;
  1143.  
  1144. ;determine next hop
  1145.  
  1146.     call    route        ; XXX, should be done for first fragment only!
  1147.     jnc    snd_frag1
  1148.     pop    di
  1149.     jmp    snd_err
  1150.  
  1151. snd_frag1:
  1152. ;fill in ecb
  1153.     mov    ax, 0
  1154.     mov    es:[di].u_ecb.ecb_esr.offs, ax
  1155.     mov    es:[di].u_ecb.ecb_esr.segm, ax
  1156.  
  1157.     mov    es:[di].u_ecb.ecb_sock, IP_socket
  1158.  
  1159.     mov    es:[di].u_ether_frag.ef_fragtot, dh
  1160.     mov    es:[di].u_ether_frag.ef_fragno, dl
  1161.     mov    ax, FragmentID
  1162.     mov    es:[di].u_ether_frag.ef_fragid, ax
  1163.  
  1164.     mov    ax, ds
  1165.     mov    es:[di].u_data_frag.frag_addr.segm, ax
  1166.  
  1167.     mov    ax, MAX_PAYLOAD
  1168.     sub    cx, ax
  1169.     jnc    snd_frag2
  1170.     add    ax, cx
  1171.  
  1172. snd_frag2:
  1173.     mov    es:[di].u_data_frag.frag_size, ax
  1174.     push    si
  1175.     add    si, bx
  1176.     mov    es:[di].u_data_frag.frag_addr.offs, si
  1177.     add    bx, ax
  1178.  
  1179. ;
  1180. ; es:si -> ecb to ship
  1181. ;
  1182.  
  1183.     mov    si, di
  1184.     call_ipx    SEND_PACKET,es,di,dx,cx,bx
  1185.     pop    si    ; ds:si -> client buffer once more
  1186.  
  1187.     add    di, SIZE u_buf    ; next send buffer
  1188.     inc    dl
  1189.     cmp    dl, dh
  1190.     jbe    snd_next_frag
  1191.  
  1192.     pop    di
  1193.  
  1194. ;simple timeout on sends
  1195.     mov    cx, 0ffffh
  1196.  
  1197. snd_wait:
  1198. ;wait until sends are done
  1199.     sti
  1200.     mov    bx, 0
  1201.     push    cx
  1202.     mov    ch, 0
  1203.     mov    cl, dh        ; dh still has fragment count
  1204.     mov    al, 0
  1205. snd_wait1:
  1206.     or    al, es:[di+bx].u_ecb.ecb_inuse
  1207.     add    bx, SIZE u_buf
  1208.     loop    snd_wait1
  1209.     pop    cx
  1210.  
  1211.     or    al, al
  1212.     jz    snd_done
  1213.     call_ipx    RELINQUISH,es,di,dx,cx
  1214.     loop    snd_wait
  1215.  
  1216. ;arrive here on timeout, cancel IPX sends
  1217.     mov    ch, 0
  1218.     mov    cl, dh
  1219.     mov    si, di
  1220.  
  1221. snd_cancel:
  1222.     call_ipx    CANCEL_EVENT,es,si,cx
  1223.     add    si, SIZE u_buf
  1224.     loop    snd_cancel
  1225.     jmp    snd_err
  1226.  
  1227. snd_done:
  1228. ;check completion status of send buffers
  1229.     mov    bx, 0
  1230.     mov    ch, 0
  1231.     mov    cl, dh
  1232.     mov    al, 0
  1233. snd_done1:
  1234.     or    al, es:[di+bx].u_ecb.ecb_cmplt
  1235.     add    bx, SIZE u_buf
  1236.     loop    snd_done1
  1237.  
  1238.     or    al, al
  1239.     jz    snd_ok
  1240.     jmp    snd_err
  1241.  
  1242. snd_ok:
  1243.     pop    di
  1244.     pop    es
  1245.     ret
  1246.  
  1247.     public    set_address
  1248. set_address:
  1249. ;enter with ds:si -> Ethernet address, CX = length of address.
  1250. ;exit with nc if okay, or cy, dh=error if any errors.
  1251.     assume    ds:nothing
  1252.     ret
  1253.  
  1254.  
  1255. rcv_mode_3:
  1256. ;receive mode 3 is the only one we support, so we don't have to do anything.
  1257.     ret
  1258.  
  1259.  
  1260.     public    set_multicast_list
  1261. set_multicast_list:
  1262. ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
  1263. ;  cx = number of bytes.
  1264. ;return nc if we set all of them, or cy,dh=error if we didn't.
  1265.     mov    dh,NO_MULTICAST
  1266.     stc
  1267.     ret
  1268.  
  1269.  
  1270.     public    reset_interface
  1271. reset_interface:
  1272. ;reset the interface.
  1273.     assume    ds:code
  1274.     ret
  1275.  
  1276.  
  1277. ;called when we want to determine what to do with a received packet.
  1278. ;enter with cx = packet length, es:di -> packet type, dl = packet class.
  1279.     extrn    recv_find: near
  1280.  
  1281. ;called after we have copied the packet into the buffer.
  1282. ;enter with ds:si ->the packet, cx = length of the packet.
  1283.     extrn    recv_copy: near
  1284.  
  1285. ;call this routine to schedule a subroutine that gets run after the
  1286. ;recv_isr.  This is done by stuffing routine's address in place
  1287. ;of the recv_isr iret's address.  This routine should push the flags when it
  1288. ;is entered, and should jump to recv_exiting_exit to leave.
  1289. ;enter with ax = address of routine to run.
  1290.     extrn    schedule_exiting: near
  1291.  
  1292. ;recv_exiting jumps here to exit, after pushing the flags.
  1293.     extrn    recv_exiting_exit: near
  1294.  
  1295. ;enter with dx = amount of memory desired.
  1296. ;exit with nc, dx -> that memory, or cy if there isn't enough memory.
  1297.     extrn    malloc: near
  1298.  
  1299.     extrn    count_in_err: near
  1300.     extrn    count_out_err: near
  1301.  
  1302.     public    recv
  1303. recv:
  1304. ;called from the recv isr.  All registers have been saved, and ds=cs.
  1305. ;Upon exit, the interrupt will be acknowledged.
  1306.     assume    ds:code
  1307.     ret
  1308.  
  1309.  
  1310.     public    terminate
  1311. terminate:
  1312. ;called when this driver should cease operation.
  1313.     assume    ds:nothing
  1314.  
  1315. ;close socket, outstanding listens should be cancelled automatically
  1316.     mov    dx, IP_socket
  1317.     call_ipx    CLOSE_SOCKET
  1318.  
  1319. ;    mov    ax, cs
  1320. ;    mov    es, ax
  1321. ;    mov    cx, NO_OF_RCV_BUFS
  1322. ;    lea    si, rcv_bufs
  1323. ;
  1324. ;terminate_1:
  1325. ;    call_ipx    CANCEL_EVENT,es,si,cx
  1326. ;    add    si, SIZE u_buf
  1327. ;    loop    terminate_1
  1328.  
  1329.     ret
  1330.  
  1331.  
  1332.     public    timer_isr
  1333. timer_isr:
  1334. ;if the first instruction is an iret, then the timer is not hooked
  1335.     iret
  1336.  
  1337. ;any code after this will not be kept after initialization. any code
  1338. ;after this will not be kept.  Buffers used by the program, if any,
  1339. ;are allocated from the memory between end_resident and end_free_mem.
  1340.     public end_resident,end_free_mem
  1341. end_resident    label    byte
  1342.     db    NO_OF_RCV_BUFS*MAX_PAYLOAD dup(?)
  1343. end_free_mem    label    byte
  1344.  
  1345.  
  1346.     public    usage_msg
  1347. usage_msg    db    "usage: ipxpkt [options] <packet_int_no>"
  1348.         db    " [-n [<no_bytes>]]",CR,LF,'$'
  1349.  
  1350.     public    copyright_msg
  1351. copyright_msg    db    "Packet driver for IPX, version ",'0'+(majver / 10),'0'+(majver mod 10),".",'0'+version,CR,LF
  1352.         db    "Portions Copyright 1990, P. Kranenburg",CR,LF,'$'
  1353.  
  1354. no_ipx_msg    db    "IPX not present",CR,LF, '$'
  1355. wrong_sock_msg    db    "IPX has no good socket",CR,LF, '$'
  1356. no_memory_msg    db    "Unable to allocate enough memory, look at end_resident in IPXPKT.ASM",CR,LF,'$'
  1357. longwait_msg    db    "This may take up to 30 seconds...",CR,LF,'$'
  1358. ifdef DEBUG
  1359. debugmsg1    db    "Doing a GET TARGET",CR,LF, '$'
  1360. debugmsg2    db    "Past GET TARGET",CR,LF, '$'
  1361. debugmsg3    db    "Past GET ADDRESS",CR,LF, '$'
  1362. endif
  1363.  
  1364.     extrn    set_recv_isr: near
  1365.  
  1366. ;enter with si -> argument string, di -> word to store.
  1367. ;if there is no number, don't change the number.
  1368.     extrn    get_number: near
  1369.     extrn    skip_blanks: near
  1370.  
  1371. ;-> the assigned Ethernet address of the card.
  1372.     extrn    rom_address: byte
  1373.  
  1374.     public    parse_args
  1375. parse_args:
  1376.  
  1377.     call    skip_blanks
  1378.     cmp    byte ptr [si], CR
  1379.     je    parse_args_x
  1380.     cmp    byte ptr [si], '-'
  1381.     jne    parse_err
  1382.     cmp    byte ptr [si+1],'n'    ; '-n'?
  1383.     je    parse_args_1
  1384.  
  1385. parse_err:
  1386.     stc                ;no, must be an error.
  1387.     ret
  1388.  
  1389. parse_args_1:
  1390.     add    si, 2
  1391.     call    skip_blanks
  1392.     cmp    byte ptr [si], CR
  1393.     jne    parse_args_2
  1394.     mov    no_bytes, 0ffffh    ;try heuristic
  1395.     jmp    parse_args_x
  1396.  
  1397. parse_args_2:
  1398.     mov    di,offset no_bytes
  1399.     call    get_number
  1400.     cmp    no_bytes, 0
  1401.     jb    parse_err
  1402.     cmp    no_bytes, EADDR_LEN
  1403.     ja    parse_err
  1404.  
  1405. parse_args_x:
  1406.     clc
  1407.     ret
  1408.  
  1409.  
  1410.     public    etopen
  1411. etopen:
  1412.  
  1413. ;first see if IPX is there
  1414.     mov    ax, 07A00h
  1415.     int    2fh
  1416.     cmp    al, 0ffh
  1417.     je    ipx_is_here
  1418.     mov    dx,offset no_ipx_msg
  1419.     stc
  1420.     ret
  1421.  
  1422. ipx_is_here:
  1423.     mov    ax, es
  1424.     mov    IPXentry.offs, di
  1425.     mov    IPXentry.segm, ax
  1426.  
  1427. ;close socket first, since "head" won't notify us on termination
  1428.     mov    dx, IP_socket
  1429.     call_ipx    CLOSE_SOCKET
  1430.  
  1431. ;next open socket
  1432.     mov    al, 0ffh        ; stay open until explicitly closed
  1433.     mov    dx, IP_socket
  1434.     call_ipx    OPEN_SOCKET
  1435.     or    al, 0
  1436.     jnz    wrong_socket
  1437.     cmp    dx, IP_socket
  1438.     je    good_socket
  1439.  
  1440. ;close socket and exit
  1441. wrong_socket:
  1442.     call_ipx    CLOSE_SOCKET
  1443.     mov    dx,offset wrong_sock_msg
  1444.     stc
  1445.     ret
  1446.  
  1447.  
  1448. no_memory:
  1449.     call_ipx    CLOSE_SOCKET
  1450.     mov    dx,offset no_memory_msg
  1451.     stc
  1452.     ret
  1453.  
  1454. good_socket:
  1455. ;init send buffer fragment list
  1456.     mov    ax, cs
  1457.     mov    es, ax
  1458.  
  1459.     mov    cx, NO_OF_SND_BUFS
  1460.     lea    si, snd_bufs
  1461.  
  1462. et_1:
  1463.     mov    es:[si].u_ecb.ecb_fragcnt, NO_OF_FRAGMENTS
  1464.  
  1465.     mov    bx, si            ; bx = offset ipx_header
  1466.     add    bx, u_ipx
  1467.     mov    es:[si].u_ipx_frag.frag_addr.offs, bx
  1468.     mov    es:[si].u_ipx_frag.frag_addr.segm, ax
  1469.     mov    es:[si].u_ipx_frag.frag_size, SIZE ipx_header
  1470.  
  1471.     mov    bx, si            ; bx = offset ether_frag
  1472.     add    bx, u_ether_frag
  1473.     mov    es:[si].u_frag_frag.frag_addr.offs, bx
  1474.     mov    es:[si].u_frag_frag.frag_addr.segm, ax
  1475.     mov    es:[si].u_frag_frag.frag_size, SIZE ether_frag
  1476. ;
  1477. ; NOTE: u_data_frag is initialised send_pkt with address of user data buffer
  1478. ;
  1479.     add    si, SIZE u_buf
  1480.     loop    et_1
  1481.  
  1482. ;initialise receive buffer ipx data fragment addresses
  1483. ;and start listening on each
  1484.     mov    cx, NO_OF_RCV_BUFS
  1485.     lea    si, rcv_bufs
  1486. et_2:
  1487.     mov    es:[si].u_ecb.ecb_fragcnt, NO_OF_FRAGMENTS
  1488.  
  1489.     mov    bx, si
  1490.     add    bx, u_ipx
  1491.     mov    es:[si].u_ipx_frag.frag_addr.offs, bx
  1492.     mov    es:[si].u_ipx_frag.frag_addr.segm, ax
  1493.     mov    es:[si].u_ipx_frag.frag_size, SIZE ipx_header
  1494.  
  1495.     mov    bx, si
  1496.     add    bx, u_ether_frag
  1497.     mov    es:[si].u_frag_frag.frag_addr.offs, bx
  1498.     mov    es:[si].u_frag_frag.frag_addr.segm, ax
  1499.     mov    es:[si].u_frag_frag.frag_size, SIZE ether_frag
  1500.  
  1501.     mov    dx,MAX_PAYLOAD
  1502.     call    malloc
  1503.     jnc    got_memory
  1504.     jmp    no_memory
  1505. got_memory:
  1506.     mov    es:[si].u_data_frag.frag_addr.offs, dx
  1507.     mov    es:[si].u_data_frag.frag_addr.segm, ax
  1508.     mov    es:[si].u_data_frag.frag_size, MAX_PAYLOAD
  1509.  
  1510.     add    si, SIZE u_buf
  1511.     loop    et_2
  1512.  
  1513. ;heuristic to force network traffic which seems to necessary before
  1514. ;the GET_NODE_ADDRESS call will work properly (boo,hiss)
  1515.  
  1516. ;get our address
  1517.     sti
  1518.     lea    si, my_net_address
  1519.     call_ipx    GET_NODE_ADDRESS,es,si
  1520.     cmp    byte ptr es:[si], 0
  1521.     jne    et_3
  1522.     cmp    byte ptr es:[si+1], 0
  1523.     jne    et_3
  1524.     cmp    byte ptr es:[si+2], 0
  1525.     jne    et_3
  1526.     cmp    byte ptr es:[si+3], 0
  1527.     jne    et_3
  1528.  
  1529. ifdef TRY_GET_LOCAL_TARGET
  1530. ; if the network address came back as 0:0:0:0 then do a GET_LOCAL_TARGET
  1531. ; before trying the GET_NODE_ADDRESS again.
  1532. ; XXX: There must be a better way of doing this, but for now we just
  1533. ; XXX: warn the user that it will take a long time.
  1534.     push    es
  1535.     print$    longwait_msg
  1536. ifdef DEBUG
  1537.     print$    debugmsg1
  1538. endif
  1539.     lea    si, dummy
  1540.     mov    di, si
  1541.     add    di, 12
  1542.     call_ipx    GET_LOCAL_TARGET
  1543. ifdef DEBUG
  1544.     print$    debugmsg2
  1545. endif
  1546.     pop    es
  1547.  
  1548. ;get our address
  1549.     lea    si, my_net_address
  1550.     call_ipx    GET_NODE_ADDRESS,es,si
  1551. ifdef DEBUG
  1552.     push    es
  1553.     push    si
  1554.     print$    debugmsg3
  1555.     pop    si
  1556.     pop    es
  1557. endif
  1558. endif
  1559.  
  1560. et_3:
  1561. ;initialise routing table with the broadcast address
  1562.     cld
  1563.     lea    di, rte
  1564.     mov    rte_end, di            ; rte_end = second entry
  1565.     add    rte_end, SIZE rt_ent        ;
  1566.     mov    rte_scache, di            ; rte_cache = first (and only) entry
  1567.     mov    rte_rcache, di            ; 
  1568.     mov    es:[di].rt_age, 0
  1569.     mov    es:[di].rt_x_pkt, GBP        ; broadcast packet type
  1570. ;;    mov    es:[di].rt_trail, 1        ; uses trail
  1571.  
  1572.     add    di, rt_ether            ; broadcast address
  1573.     mov    al, 0ffh
  1574.     mov    cx, SIZE rt_ether
  1575.     rep    stosb
  1576.  
  1577.     push    ds
  1578.     mov    ax, cs
  1579.     mov    ds, ax
  1580.     mov    cx, SIZE rt_net
  1581.     rep    movsb                ; net field set from my_net_address
  1582.     pop    ds
  1583.  
  1584.     mov    al, 0ffh
  1585.     mov    cx, SIZE rt_node + SIZE rt_gate
  1586.     rep    stosb                ; all FF's
  1587.  
  1588. ;schedule periodic aging of route table entries
  1589.     lea    si, rte_aes
  1590.     mov    ax, cs
  1591.     mov    es:[si].aes_esr.segm, ax
  1592.     mov    es:[si].aes_esr.offs, offset rte_ticker
  1593.     mov    ax, RTE_TICK
  1594.     call_ipx    SCHEDULE_SPECIAL_EVENT, es
  1595.  
  1596.     movseg    es,ds
  1597.     mov    di,offset rom_address
  1598.  
  1599.     cmp    init_cmplt, 1
  1600.     jnc    ga_1
  1601.     call    listen_init
  1602.     mov    init_cmplt, 1
  1603.  
  1604. ga_1:
  1605.     lea    si, my_node_address    ; first copy IPX node address
  1606.     cld
  1607.     repmov    <EADDR_LEN>
  1608.  
  1609.     mov    cx, EADDR_LEN        ; if not significant enough,
  1610.     cmp    no_bytes, 0ffffh    ; magic in no_bytes?
  1611.     jne    ga_3
  1612.     lea    bx, my_node_address    ; they don't know
  1613.     mov    dx, bx            ; figure out something for no_bytes
  1614.     add    dx, SIZE my_node_address    ; savety
  1615.     mov    no_bytes, EADDR_LEN
  1616.  
  1617. ga_2:
  1618.     cmp    byte ptr [bx], 0
  1619.     jnz    ga_3
  1620.     dec    no_bytes
  1621.     inc    bx
  1622.     cmp    bx, dx
  1623.     je    ga_3
  1624.     jmp    ga_2
  1625.  
  1626. ga_3:
  1627.     sub    cx, no_bytes        ; copy some of IPX net address
  1628.     jcxz    get_addr_x
  1629.     cmp    cx, SIZE my_net_address
  1630.     jbe    ga_4
  1631.     mov    cx, SIZE my_net_address
  1632. ga_4:
  1633.     lea    si, my_net_address
  1634.     sub    di, EADDR_LEN
  1635.  
  1636. ;next are three different methods for constructing the reported ethernet address
  1637. ;from a less-than-6-bytes-long IPX node adress and the IPX net address.
  1638. if ETH_CONSTR eq 1
  1639.  
  1640.     ; copy (the first few bytes of) my_net_address
  1641.     rep    movsb
  1642.  
  1643. elseif ETH_CONSTR eq 2
  1644.  
  1645.     ; copy (the last few bytes of) my_net_address, in reverse order
  1646. ga_21:
  1647.     mov    bx, SIZE my_net_address - 1
  1648.     mov    al, [si+bx]
  1649.     stosb
  1650.     dec    bx
  1651.     loop    ga_21
  1652.  
  1653. elseif ETH_CONSTR eq 3
  1654.  
  1655.     ; if there is enough space, copy the whole of my_net_address
  1656.     cmp    cx, SIZE my_net_address
  1657.     jl    ga_3_b
  1658.     rep    movsb
  1659.     jmp    ga_3_end
  1660.  
  1661.     ; no space for the whole of my_net_address, so go through
  1662.     ; this weird method of choosing just a few bytes to copy
  1663. ga_3_b:
  1664.     push    di
  1665.     push    si
  1666.     push    es
  1667.     mov    ax, ds
  1668.     mov    es, ax
  1669.     lea    di, dummy
  1670.     repmov    <SIZE my_net_address>
  1671.     pop    es
  1672.     pop    si
  1673.     pop    di
  1674.  
  1675.     lea    si, dummy
  1676.  
  1677. ga_3_loop:
  1678.     mov    bx, 0
  1679.     mov    dx, 0
  1680.     mov    al, 0
  1681. ga_31:
  1682.     cmp    bx, SIZE my_net_address
  1683.     jz    ga_33
  1684.     mov    ah, [si+bx]
  1685.     cmp    al, ah
  1686.     jnc    ga_32
  1687.     mov    al, ah
  1688.     mov    dx, bx
  1689. ga_32:
  1690.     inc    bx
  1691.     jmp    ga_31
  1692. ga_33:
  1693.     stosb
  1694.     mov    bx, dx
  1695.     mov    byte ptr [si+bx], 0
  1696.     loop    ga_3_loop
  1697. ga_3_end:
  1698.     
  1699. endif
  1700.  
  1701. get_addr_x:
  1702.  
  1703. ;if all is okay,
  1704.     clc
  1705.     ret
  1706.  
  1707. listen_init    proc    near
  1708. ;and start listening on each receive buffer
  1709.     push    si
  1710.     push    cx
  1711.     push    es
  1712.     mov    ax, cs
  1713.     mov    es, ax
  1714.     mov    cx, NO_OF_RCV_BUFS
  1715.     lea    si, rcv_bufs
  1716. li_1:
  1717.     call    listen_proc
  1718.     add    si, SIZE u_buf
  1719.     loop    li_1
  1720.     pop    es
  1721.     pop    cx
  1722.     pop    si
  1723.     ret
  1724. listen_init    endp
  1725.  
  1726.  
  1727.     public    print_parameters
  1728. print_parameters:
  1729.     ret
  1730.  
  1731. code    ends
  1732.  
  1733.     end
  1734.