home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msr313src.tar.gz / msr313src.tar / msnpdi.asm < prev    next >
Assembly Source File  |  1993-07-12  |  57KB  |  1,743 lines

  1.     NAME    MSNPDI
  2. ; File MSNPDI.ASM
  3. ; Packet Driver and ODI interface 
  4. ;
  5. ;  Copyright (C) 1985, 1993, Trustees of Columbia University in the 
  6. ;  City of New York.  Permission is granted to any individual or institution
  7. ;  to use this software as long as it is not sold for profit.  This copyright
  8. ;  notice must be retained.  This software may not be included in commercial
  9. ;  products without written permission of Columbia University.
  10. ;
  11. ;  Permission is granted to use this file as a guide in developing commercial
  12. ;  products. If substantial portions are used crediting the source is 
  13. ;  recommended.
  14. ;
  15. ; Written by Joe R. Doupnik, Utah State University, Logan Utah 84322
  16. ;  jrd@cc.usu.edu, jrd@usu.Bitnet.
  17. ;
  18. ; Packet Driver reference:
  19. ; "PC/TCP Version 1.09 Packet Driver Specification", FTP Software, Inc.,
  20. ;  September-14-1989.
  21. ;
  22. ; ODI references:
  23. ; "Open Data-Link Interface Developer's Guide for DOS Network Layer Protocol 
  24. ;  Stacks", Novell Inc, document number 100-001218-001 (1992, but no printed 
  25. ;  date).
  26. ; "Open Data-Link Interface Developer's Guide for NetWare v3.1x Server 
  27. ;  Driver Protocol Stacks", Novell Inc, document number 100-001196-00, v1.0,
  28. ;  19 Sept 1991.
  29. ; "Open Data-Link Interface LAN Driver Developer's Guide for DOS", Novell Inc,
  30. ;  document number 107-000010-001, Revision i, 13 Nov 1990.
  31. ;
  32. ; C language interface presumes the Small memory model and Microsoft C.
  33. ; Assembler is MS MASM v6.
  34. ;
  35. ; These procedures interface between ODI or a Packet Driver and the main
  36. ; protocol stack to both send and receive packets. The upper levels provide
  37. ; and receive packets framed as Ethernet_II (Blue Book/DIX), and receive
  38. ; ARP information particular to the physical frames involved. Conversion of
  39. ; this internal form to the actual framing method on the wire is done by ODI.
  40. ; The receive buffer is external to this routine. Received packets are linked
  41. ; into the buffer on an order of arrival basis (and sized to fit). High level
  42. ; reception has to poll the receive buffer queue. Transmitted packets are 
  43. ; operated with a single external buffer, and sending blocks until the lower 
  44. ; level driver material is ready for us. Initialization, status, attachment, 
  45. ; and disengagment procedures are here.
  46. ; External int kpdint is used by pdinit() to select between Packet Driver
  47. ; and ODI interfaces. Call pdinit() to initialize the system, then call
  48. ; pdaccess() to register each desired frame TYPE, call pdclose() to release
  49. ; each frame TYPE.
  50. ; Packet senders call pkt_send() directly.
  51. ; Packet receivers examine the external packet buffer for packets.
  52. ; ARP information is returned in external ints arp_hardware (hardware ARP
  53. ; type code) and MAC_len (length of MAC address, in bytes). See table below
  54. ; for the possible pairs.
  55. ; Packet Driver usage is limited to Ethernet_II/DIX and SLIP. ODI usage is
  56. ; at least Ethernets, Token Ring, Arcnet, and others untested here.
  57. ; Edit history
  58. ; 27 August 1992 version 3.13
  59. ; Last edit
  60. ; 22 May 1993
  61.  
  62. getintv        equ    35h        ; DOS get interrupt vector to es:bx
  63. dos        equ    21h
  64. lf        equ    0ah
  65. fopen        equ    3dh        ; DOS file operations
  66. fclose        equ    3eh
  67. fread        equ    3fh
  68.  
  69. pdgetinfo    equ    1        ; Packet Driver functions
  70. pd_access     equ    2
  71. pd_release    equ    3
  72. pd_send        equ    4
  73. pd_get_address    equ    6
  74. eaddr_len    equ    6        ; length of an Ethernet address
  75. ETH_MSS        equ    1046        ; Correlate with msntcp.h
  76. IF_EII        equ    1        ; Ethernet II interface type
  77. IF_SLIP        equ    6        ; SLIP interface type, RFC1055
  78.  
  79. link    struc                ; receiver buffer link structure
  80.     flag    db    0        ; buffer use flag
  81.     bufnum    db    0        ; buffer write sequence number
  82.     count    dw    0        ; count of bytes to follow
  83. link    ends
  84. linksize equ    4            ; bytes in link structure
  85.  
  86. ; Novell ODI material, based on LSL v1.2.
  87. ; Most of these header structures were taken from Novell file ODI.INC,
  88. ; and parts have been tailored for Kermit. Information on the "new" item in
  89. ; the lookahead structure is compliments of Novell, private correspondence.
  90.  
  91. ;  Event Control Block Structure
  92. ECBstruct    struc
  93.     nextlink    dd    0        ; leave intact
  94.     prevlink    dd    0        ; leave intact
  95.     status        dw    0        ; general status
  96.     esr        dd    0        ; addr of event service routine
  97.     stackid        dw    0        ; protocol stack ident
  98.     protid        db    6 dup (0)    ; sending only
  99.     boardnum    dw    0        ; sending, MILD board number
  100.     immaddr        db    6 dup (0)    ; MAC destination address
  101.     driverws    db    4 dup (0)    ; their work space
  102.     protocolws    dw    4 dup (0)    ; our work space
  103.     datalen        dw    0        ; total length of sent buffer
  104.     fragcount    dw    1        ; number of buffer pieces
  105.     frag1addr    dw    0,0        ; seg:offset of first buffer
  106.     frag1len    dw    0        ; length of first buf frag
  107. ECBstruct    ends                ; 26 words
  108.  
  109. ;  Look Ahead Structure
  110. LookAheadStruc    struc
  111.     LMediaHeaderPtr    dd    0        ; pointer to MAC header
  112.     LookAheadPtr    dd    0        ; pointer to pkt Data
  113.     LookAheadLen    dw    0        ; length of pkt Data field
  114.     LProtID        db    6 dup (0)    ; protocol ident
  115.     LBoardNum    dw    -1        ; logical board of rcv'd pkt
  116.     DataLookAheadDataSize dd 0    ; new field, exists if bit 7 of the 
  117.             ; Driver's Configuration Table Mode Flags is set.
  118. LookAheadStruc    ends
  119.  
  120. ;  Rx Destination Address Type (First byte of ECB.DriverWS)
  121. ECB_DIRECT        equ    00h        ;Physical destination address
  122. ECB_MULTICAST        equ    01h        ;Multicast destination address
  123. ECB_BROADCAST        equ    03h        ;Broadcast destination address
  124.  
  125. ;  System Error Code Definitions
  126. LSLERR_OUT_OF_RESOURCES    equ    8001h
  127. LSLERR_BAD_PARAMETER    equ    8002h
  128. LSLERR_NO_MORE_ITEMS    equ    8003h
  129. LSLERR_ITEM_NOT_PRESENT    equ    8004h
  130. LSLERR_FAIL        equ    8005h
  131. LSLERR_RX_OVERFLOW    equ    8006h
  132. LSLERR_CANCELLED    equ    8007h
  133. LSLERR_BAD_COMMAND    equ    8008h
  134. LSLERR_DUPLICATE_ENTRY    equ    8009h
  135. LSLERR_NO_SUCH_HANDLER    equ    800ah
  136. LSLERR_NO_SUCH_DRIVER    equ    800bh
  137.  
  138. ;  LSL MLID Services Function Codes
  139. MLIDSUP_GET_ECB                   equ    0
  140. MLIDSUP_RETURN_ECB             equ    1
  141. MLIDSUP_DEFRAG_ECB           equ    2
  142. MLIDSUP_SCHEDULE_AES_EVENT     equ    3
  143. MLIDSUP_CANCEL_AES_EVENT       equ    4
  144. MLIDSUP_GET_INTERVAL_MARKER    equ    5
  145. MLIDSUP_DEREGISTER_MLID           equ    6  
  146. MLIDSUP_HOLD_RECV_EVENT           equ    7  
  147. MLIDSUP_START_CRITICAL_SECTION    equ    8  
  148. MLIDSUP_END_CRITICAL_SECTION       equ    9  
  149. MLIDSUP_CRITICAL_SECTION_STATUS    equ    10 
  150. MLIDSUP_SERVICE_EVENTS              equ    11
  151. MLIDSUP_SEND_COMPLETE              equ    14 
  152. MLIDSUP_ADD_PID            equ    15
  153. MLIDSUP_GET_STACK_ECB        equ    16
  154.  
  155. ;  LSL Protocol Stack Services Function Codes
  156. PROTSUP_GET_ECB                equ    0
  157. PROTSUP_RETURN_ECB            equ    1
  158. PROTSUP_SCHEDULE_AES_EVENT         equ    3
  159. PROTSUP_CANCEL_EVENT            equ    4
  160. PROTSUP_GET_INTERVAL_MARK        equ    5
  161. PROTSUP_REGISTER_STACK            equ    6  
  162. PROTSUP_DEREGISTER_STACK        equ    7  
  163. PROTSUP_REGISTER_DEFAULT_STACK        equ    8  
  164. PROTSUP_DEREGISTER_DEFAULT_STACK    equ    9  
  165. PROTSUP_REGISTER_PRESCAN_STACK        equ    10 
  166. PROTSUP_DEREGISTER_PRESCAN_STACK    equ    11 
  167. PROTSUP_SEND_PACKET            equ    12 
  168. PROTSUP_GET_PROTNUM_FROM_NAME        equ    16 
  169. PROTSUP_GET_PID_PROTNUM_MLIDNUM        equ    17 
  170. PROTSUP_GET_MLID_CTL_ENTRY        equ    18 
  171. PROTSUP_GET_PROTO_CTL_ENTRY        equ    19 
  172. PROTSUP_GET_LSL_STATS            equ    20 
  173. PROTSUP_BIND_STACK_TO_MLID        equ    21 
  174. PROTSUP_UNBIND_STACK_FROM_MLID        equ    22 
  175. PROTSUP_ADD_PID                equ    23 
  176. PROTSUP_RELINQUISH_CONTROL        equ    24 
  177. PROTSUP_GET_LSL_CONFIG            equ    25
  178.  
  179. ;  LSL General Services Function Codes
  180. GENSERV_ALLOC_MEMORY        equ    0
  181. GENSERV_FREE_MEMORY        equ    1
  182. GENSERV_REALLOC_MEMORY        equ    2
  183. GENSERV_MEMORY_STATISTICS    equ    3
  184. GENSERV_ADD_MEMORY_TO_POOL    equ    4
  185. GENSERV_ADD_GENERAL_SERVICE    equ    5
  186. GENSERV_REMOVE_GENERAL_SERVICE    equ    6
  187. GENSERV_GET_NETCFG_PATH        equ    7
  188.  
  189. ;  LSL Configuration Table
  190. LSLConfigurationStructure    struc
  191.     LConfigTableMajorVer    db    1
  192.     LConfigTableMinorVer    db    0
  193.     LNumLSLRxBuffers    dd    0
  194.     LRxBufferSize        dd    0    ;Buffer size NOT including ECB struc size
  195.     LMajorVersion        db    0
  196.     LMinorVersion        db    0
  197.     LConfigTableReserved    db    16 dup (0)
  198. LSLConfigurationStructure    ends
  199.  
  200. ;  MLID Control Commands
  201. GET_MLID_CONFIGURATION        equ    0
  202. GET_MLID_STATISTICS        equ    1
  203. ADD_MULTICAST_ADDRESS        equ    2
  204. DELETE_MULTICAST_ADDRESS    equ    3
  205. MLID_SHUTDOWN            equ    5
  206. MLID_RESET            equ    6
  207. CREATE_CONNECTION        equ    7
  208. REMOVE_CONNECTION        equ    8
  209. SET_LOOK_AHEAD_SIZE        equ    9
  210. DRIVER_POLL            equ    12
  211.  
  212. ;  MLID Configuration Table Structure
  213. MLIDConfigurationStructure    struc
  214.     MSignature        db    'HardwareDriverMLID',8 dup (' ')
  215.     MConfigTableMajorVer    db    1
  216.     MConfigTableMinorVer    db    11
  217.     MNodeAddress        db    6 dup (?)
  218.     MModeFlags        dw    ?
  219.     MBoardNumber        dw    ?
  220.     MBoardInstance        dw    ?
  221.     MMaxPacketSize        dw    ?
  222.     MBestDataSize        dw    ?
  223.     MWorstDataSize        dw    ?
  224.     MCardLongName        dd    ?
  225.     MCardShortName        dd    ?        ; visible board name
  226.     MFrameString        dd    ?
  227.     MReserved0        dw    0        ;Must be set to 0
  228.     MFrameID        dw    ?
  229.     MTransportTime        dw    ?
  230.     MRouteHandler        dd    ?        ;Only for Token-Ring
  231.     MLookAheadSize        dw    ?
  232.     MLineSpeed        dw    ?        ;In Mbps or Kbps
  233.     MReserved1        db    8 dup (0)    ;Must be set to 0
  234.     MMLIDMajorVer        db    ?
  235.     MMLIDMinorVer        db    ?
  236.     MFlags            dw    ?
  237.     MSendRetries        dw    ?
  238.     MLink            dd    ?
  239.     MSharingFlags        dw    ?
  240.     MSlot            dw    ?
  241.     MIOAddress1        dw    ?
  242.     MIORange1        dw    ?
  243.     MIOAddress2        dw     ?
  244.     MIORange2        dw    ?
  245.     MMemoryAddress1        dd    ?
  246.     MMemorySize1        dw    ?
  247.     MMemoryAddress2        dd    ?
  248.     MMemorySize2        dw    ?
  249.     MIntLine1        db    ?
  250.     MIntLine2        db    ?
  251.     MDMALine1        db    ?
  252.     MDMALine2        db    ?
  253. MLIDConfigurationStructure    ends
  254.  
  255. ;  MLID Config Table 'MFlags' bit definitions.
  256. EISA    equ    01h            ;EISA Bus
  257. ISA     equ    02h            ;PC/AT Bus
  258. MCA     equ    04h            ;PS/2 MCA Bus
  259. Len_Info equ    40h            ; pkt data length in lookahead info
  260.  
  261. ;  MLID Config Table 'MModeFlags' bit definitions (no promiscuous mode).
  262. MRealDriverBit        equ    0001h
  263. MUsesDMABit        equ    0002h
  264. MGuaranteedDeliveryBit    equ    0004h        ;100% reliable on transmits
  265. MMulticastBit        equ    0008h
  266. MNeedsPollingBit    equ    0020h
  267. MRawSendBit        equ    0040h
  268.  
  269. ; Registered Stack structure, used during registration only
  270. StackInfoStruc    struc
  271.     StackNamePtr        dd    ip_string    ; ptr to short name
  272.     StackReceiveHandler    dd    ip_rcvr     ; rcv routine
  273.     StackControlHandler    dd    pcontrol    ; control routine
  274. StackInfoStruc    ends
  275.  
  276. ;  Protocol Control Commands
  277. GET_STACK_CONFIGURATION        equ    0
  278. GET_STACK_STATISTICS        equ    1
  279. BIND_TO_MLID            equ    2
  280. UNBIND_FROM_MLID        equ    3
  281. INFORM_MLID_DEREGISTERED    equ    4
  282.  
  283. ;  Protocol Configuration Table
  284. ProtocolConfigStructure    struc
  285.     PConfigTableMajorVer    db    1
  286.     PConfigTableMinorVer    db    0
  287.     PProtocolLongName    dd    plname
  288.     PProtocolShortName    dd    psname        ; "KERMIT"
  289.     PProtocolMajorVer    db    3         ; MSK v3.13
  290.     PProtocolMinorVer    db    13
  291.     PConfigTableReserved    db    16 dup (0)
  292. ProtocolConfigStructure    ends
  293.  
  294. ;  Protocol Statistics Table
  295. ProtocolStatStructure    struc
  296.     PStatTableMajorVer    db    1
  297.     PStatTableMinorVer    db    0
  298.     PNumGenericCounters    dw    3        ; just those below
  299.     PValidCounterMask    dd    111b        ; bitfield, 3 valids
  300.     PTotalTxPackets        dw    2 dup (0)
  301.     PTotalRxPackets        dw    2 dup (0)
  302.     PIgnoredRxPackets    dw    2 dup (0)
  303.     PNumCustomCounters    dw    0        ; none
  304. ProtocolStatStructure    ends
  305.  
  306. pinfo    struc                ; per protocol local data for ecb
  307.     pstack    dw    0        ; StackID
  308.     pprotid    db    6 dup (0)    ; ProtID
  309.     pboard    dw    0        ; boardnum
  310. pinfo    ends
  311.  
  312. _TEXT    SEGMENT  WORD PUBLIC 'CODE'
  313. _TEXT    ENDS
  314. _DATA    SEGMENT  WORD PUBLIC 'DATA'
  315. _DATA    ENDS
  316. CONST    SEGMENT  WORD PUBLIC 'CONST'
  317. CONST    ENDS
  318. _BSS    SEGMENT  WORD PUBLIC 'BSS'
  319. _BSS    ENDS
  320. DGROUP    GROUP    CONST, _BSS, _DATA
  321.     ASSUME  CS: _TEXT, DS: DGROUP, SS: DGROUP, ES:NOTHING
  322.  
  323. _DATA      SEGMENT
  324.     extrn    _pktbuf_wrote:word, _pktwnum:byte, _kpdint:word
  325.     extrn    _eth_addr:byte, _arp_hardware:word, _MAC_len:word
  326.     extrn    _mss:word
  327.  
  328. pdsignature    db    'PKT DRVR'    ; signature of a Packet Driver
  329. if_type        dw    0        ; interface type
  330. if_class    db    0        ; interface class
  331. if_num        db    0        ; interface number
  332. if_func        db    0        ; interface functionality
  333. if_version    dw    0        ; interface version
  334. iptype        db    8,0        ; IP packet type
  335. iptypelen    equ    $-iptype    ; length of type field for iptype
  336. pktbufoff    dw    0        ; offset of packet buffer
  337. SLIPmac        dw    0,0,2        ; fake SLIP dest Ethernet address
  338.                     ; ODI material
  339. useodi        db    0        ; non-zero if using ODI for transport
  340. lslsig        db    'LINKSUP$'    ; LSL presence signature
  341. lslsiglen    equ    $-lslsig
  342. lslinit        dd    0        ; LSL init entry point
  343.                     ; LSL entry structure, do not separate
  344. lslsupport    dd    0        ; LSL protocol support API entry point
  345. lslservice    dd    0        ; LSL general services API entry point
  346.  
  347. mlidcont     dd    0        ; MLID Control entry point
  348.  
  349. ecbr_qty    equ    4        ; number of receive ECB's to allocate
  350. maketab    MACRO                ; macro to make receiver ecbs
  351. cnt = 0
  352.     rept ecbr_qty - 1
  353.     ecbstruct <,,,odircmp>
  354. cnt = cnt + 1
  355.     endm
  356. ENDM
  357. ecbr        ecbstruct <,,,odircmp>    ; first receiver ECB
  358.         maketab            ; make table of the other ecbr's
  359. ecbx        ecbstruct <,,,odixcmp>    ; one ECB for transmission
  360. ecbr_busy    db     ecbr_qty dup (0) ; our ecbr locks
  361. ecbx_busy    db    0        ; non-zero if ECBx owned by ODI
  362. ecbr_num    dw    0        ; temp to hold index of ecbr/ecbr_busy
  363. rcvtype        dw    0        ; temp, holds protocol TYPE for rcv
  364. pconfig     ProtocolConfigStructure <>    ; as the name says
  365. pstats        ProtocolStatStructure <>    ; protocol statistics
  366. registerstk     StackInfoStruc <>    ; bound stack setup structure
  367. plname        db 13,'MS-DOS Kermit',0    ; cnt, protocol stack long name, null
  368. protword     db 8,'PROTOCOL',0    ; three NET.CFG keywords for Kermit
  369. psname        db 6,'KERMIT',0        ; cnt, protocol stack short name, null
  370. bindword     db 4,'BIND',0        ; third keyword
  371. ip_type        equ    0008h        ; Protocol TYPEs, big endian/net order
  372. arp_type    equ    0608h
  373. rarp_type    equ    3580h
  374. ip_string     db    2,'IP',0    ; strings to match in NET.CFG file
  375. arp_string    db    3,'ARP',0    ;  to select pkt TYPEs
  376. rarp_string    db    4,'RARP',0    ;  RARP is optional
  377. ip_stackid    pinfo    <>        ; StackID, Protid, boardnum 
  378. arp_stackid    pinfo    <>        ;  for each protocol
  379. rarp_stackid    pinfo    <>
  380. bcast        db    6 dup (0ffh)    ; Broadcast address, for reception
  381. readnetcfg    db    0        ; non-zero if have read NET.CFG
  382. useboard    dw    -1        ; board to be used, -1 = not inited
  383. bdname        db    0,16 dup (0)    ; length, 15 text, null, bound board
  384. tells_len    db    0        ; if MLID tells pkt len for lookahead
  385. tempb        db    0
  386. temp        dw    0
  387. ; parallel lists of NetWare ODI frame types, address lengths, ARP idents
  388. frame_type    db    2,3,4,5,6,7, 9,10,11,14,15,16,23,27,28
  389. num_frames    equ    ($ - frame_type)
  390. frame_adlen    db    6,6,6,6,6,6, 1,6, 6, 1, 6, 6, 6, 0, 0
  391. hardware_type    db    1,6,6,6,6,12,4,6, 6, 7, 6, 6, 0, 0, 0
  392. _DATA      ENDS
  393.  
  394. ; ODI Frame types, frame strings, length (bytes) of a MAC level address:
  395. ; type    frame string        MAC_len   hardware    comments
  396. ; 0    VIRTUAL_LAN        0    0    no MAC header used
  397. ; 1    LOCALTALK        6    11    Apple (Ether/Tokentalk is 802)
  398. ; 2    ETHERNET_II        6    1    Blue Book
  399. ; 3    ETHERNET_802.2        6    6    802.3 with 802.2 wrap
  400. ; 4    TOKEN-RING        6    4    802.5 with 802.2 wrap
  401. ; 5    ETHERNET_802.3        6    6    802.3 "raw", old Novell
  402. ; 6    802.4            6    6    Token Bus
  403. ; 7    NOVELL_PCN2          6    12    Novell's IBM PCnet2
  404. ; 8    GNET              6    4    Gateway, assumed TRN-like
  405. ; 9    PRONET-10        1     4    Proteon TRN-like
  406. ; 10    ETHERNET_SNAP        6    1    802.3 with 802.2+SNAP
  407. ; 11    TOKEN-RING_SNAP        6    6    802.5 with 802.2+SNAP
  408. ; 12    LANPAC_II        6    ?    Racore
  409. ; 13    ISDN            6    ?    telco
  410. ; 14    NOVELL_RX-NET        1    7    Arcnet-like
  411. ; 15    IBM_PCN2_802.2        6    12    IBM PCnet2 with 802.2
  412. ; 16    IBM_PCN2_SNAP        6    12    IBM PCnet2,802.2+SNAP
  413. ; 17    OMNINET/4        ?    ?    Corvus
  414. ; 18    3270_COAXA        ?    ?    Harris
  415. ; 19    IP            ?    ?    tunneled
  416. ; 20    FDDI_802.2        6    ?
  417. ; 21    IVDLAN_802.9        6    ?    Commtex
  418. ; 22    DATACO_OSI        ?    ?    Dataco
  419. ; 23    FDDI_SNAP        6    6    802.7, with 802.2+SNAP
  420. ; 27    SLIP            0    0    SLIP, IP over serial link
  421. ; 28    PPP            0    0    PPP, IP over PPP serial link
  422. ;
  423. ;      ARP hardware field, from RFC 1060
  424. ;     Type   Description                 
  425. ;     ----   -----------                
  426. ;    1    Ethernet (10Mb)
  427. ;    2    Experimental Ethernet (3Mb)
  428. ;    3    Amateur Radio AX.25
  429. ;    4    Proteon ProNET Token Ring
  430. ;    5    Chaos
  431. ;       6    IEEE 802 Networks
  432. ;       7    ARCNET
  433. ;       8    Hyperchannel
  434. ;       9    Lanstar
  435. ;      10    Autonet Short Address
  436. ;      11    LocalTalk
  437. ;      12    LocalNet (IBM PCNet or SYTEK LocalNET)
  438.  
  439. _TEXT    segment
  440.  
  441. pktdrvr    proc    near            ; Packet Driver interrupt invokation
  442. PKTDRVI:int    60h        ; Interrupt number, modified by startup code
  443.     ret
  444. pktdrvr    endp
  445.  
  446. ; pdinit(ðeraddress)
  447. ; Initialize Packet Driver or ODI for use by this program. Stores Ethernet
  448. ; address (or MAC address). _kpdint is 0 to scan first for a Packet Driver
  449. ; interrupt and fall back to search for ODI, or is a number 60h..7fh to
  450. ; target only that PD interrupt, or is 'DO' to target only ODI. If a PD is
  451. ; used then _kpdint is modified to be the found interrupt value.
  452. ; A 6 byte MAC level address is returned for convenience, even for SLIP. 
  453. ; If the machine is an XT or Windows enhanced mode is active then do not
  454. ; use the ODI code at this time (no Int 2Fh, no bridge between real and
  455. ; protected mode virutal machines).
  456. ; Returns 1 for success, 0 for failure.
  457.  
  458.     public    _pdinit
  459. _pdinit    proc    near
  460.     push    bp
  461.     mov    bp,sp
  462.     push    es
  463.     push    si
  464.     push    di
  465.     push    ds
  466.     mov    ax,dgroup
  467.     mov    ds,ax
  468.     mov    ax,[bp+4+0]        ; get offset of pktbuf
  469.     mov    pktbufoff,ax        ; save locally
  470.     mov    cx,60h            ; interrupt range
  471.     cmp    _kpdint,0        ; user value given for PD Int?
  472.     je    pdinit1            ; e = no
  473.     mov    cx,_kpdint        ; use it
  474.     mov    _kpdint,0        ; assume no user value
  475. pdinit1:cmp    _kpdint,'DO'        ; special indicator to use ODI?
  476.     je    short pdinit2        ; do ODI
  477.     mov    ah,getintv        ; get interrupt vector to es:bx
  478.     mov    al,cl            ; vector number
  479.     int    dos
  480.     mov    si,offset dgroup:pdsignature ; look for signature
  481.     push    cx
  482.     mov    cx,size pdsignature    ; length of string
  483.     mov    di,bx
  484.     add    di,3            ; sig starts 3 bytes from entry point
  485.     cld
  486.     repe    cmpsb            ; compare bytes
  487.     pop    cx
  488.     je    pdinit3            ; e = found a match
  489.     cmp    _kpdint,0        ; user value given?
  490.     jne    pdinit2            ; ne = yes, so fail
  491.     inc    cx
  492.     cmp    cx,80h            ; at end of range?
  493.     jna    pdinit1            ; na = not yet, try another int
  494.                     ; no Packet Driver found
  495. pdinit2:call    odichk            ; see if ODI is available
  496.     jc    pdinit5            ; c = no
  497.     mov    useodi,1        ; say using ODI
  498.     mov    _kpdint,'DO'        ; signal ODI via PD interrupt variable
  499.     mov    if_class,1        ; say Ethernet_II for internal work
  500.     mov    di,[bp+4+2]        ; get offset of user's buffer
  501.     mov    cx,eaddr_len        ; length of address provided
  502.     mov    si,offset DGROUP:SLIPmac ; get fake Ethernet address
  503.     cld                ;  in case code wants it early
  504.     push    ds
  505.     pop    es
  506.     push    di
  507.     rep    movsb            ; copy to user buffer
  508.     mov    cx,ecbr_qty
  509.     mov    di,offset DGROUP:ecbr_busy ; clear receive ecb busy flags
  510.     xor    al,al
  511.     rep    stosb
  512.     pop    di
  513.     clc
  514. pdinit5:jmp    pdret            ; exit (carry set is failure)
  515.                      ; Packet Driver details
  516. pdinit3:mov    byte ptr PKTDRVI+1,cl    ; force in new PD interrupt, code mod
  517.     mov    _kpdint,cx        ; remember interrupt number
  518.                     ; find Ethernet address
  519.     mov    ah,pdgetinfo        ; get Packet Driver information
  520.     mov    al,0ffh
  521.     xor    bx,bx            ; optional handle
  522.     push    ds            ; this call changes ds and si
  523.     push    si
  524.     call    pktdrvr            ; call the Packet Driver
  525.     pop    si
  526.     pop    ds
  527.     jc    pdret            ; c = failure
  528. pdinit6:mov    if_type,dx        ; save details for access calls
  529.     mov    if_class,ch
  530.     mov    if_num,cl
  531.     mov    if_func,al
  532.     mov    if_version,bx
  533.     mov    ah,pd_access        ; access packets
  534.     mov    al,ch            ; Ethernet class
  535.     mov    bx,dx            ; type
  536.     mov    dl,cl            ; interface number
  537.     mov    cx,iptypelen        ; type length for iptype
  538.     mov    si,offset dgroup:iptype    ; address of TYPE
  539.     mov    di,cs
  540.     mov    es,di
  541.     mov    di,offset pdrcvr    ; ES:DI is our Packet Driver receiver
  542.     call    pktdrvr
  543.     jc    pdret            ; c = failure
  544.     mov    bx,ax            ; put returned handle in BX
  545.     mov    _arp_hardware,0001h    ; Type 1 hardware, Ethernet
  546.     mov    _MAC_len,6        ; 6 bytes of MAC level address
  547.     mov    ax,DGROUP        ; our data segment
  548.     mov    es,ax            ; segment of Ethernet address buffer
  549.     mov    di,[bp+4+2]        ; get offset of user's buffer
  550.     mov    cx,eaddr_len        ; length of address wanted
  551.     cmp    if_class,IF_SLIP    ; interface class of SLIP?
  552.     jne    pdinit4            ; ne = no
  553.     mov    si,offset DGROUP:SLIPmac ; get fake Ethernet address
  554.     cld
  555.     push    di            ; save in case PD actually uses it
  556.     rep    movsb            ; copy to user buffer
  557.     pop    di
  558.     mov    _arp_hardware,0        ; no hardware type
  559.     mov    _MAC_len,0        ; no MAC level address
  560.     mov    _mss,1006-44        ; set SLIP max frame size too
  561. pdinit4:mov    ah,pd_get_address    ; get the Ethernet address
  562.     push    bx            ; save handle
  563.     call    pktdrvr            ; get Ethernet address to es:di buf
  564.     pop    bx
  565.     pushf                ; save carry flag
  566.     mov    ah,pd_release        ; release this Type, bx has handle
  567.     call    pktdrvr
  568.     popf                ; recover carry flag
  569. pdret:    mov    ax,1            ; return C status, 1 for success
  570.     jnc    pdret1
  571.     xor    ax,ax            ; 0 for failure
  572. pdret1:    pop    ds            ; success
  573.     pop    di
  574.     pop    si
  575.     pop    es
  576.     mov    sp,bp            ; restore stack
  577.     pop    bp            ; recover bp reg
  578.     ret
  579. _pdinit    endp
  580.  
  581. ; int pdinfo(& int version, & int class, & int pdtype, & int number,
  582. ;  & int functionality)
  583. ; Get Packet Driver pedigree
  584.     public    _pdinfo
  585. _pdinfo    proc    near
  586.     push    bp
  587.     mov    bp,sp
  588.     push    di
  589.     push    cx
  590.     push    bx
  591.     push    ax            ; save al for later use
  592.     mov    di,[bp+4+0]
  593.     mov    bx,if_version
  594.     mov    [di],bx            ; return version
  595.     mov    al,if_class        ; class
  596.     xor    ah,ah
  597.     mov    di,[bp+4+2]
  598.     mov    [di],ax            ; return as an int
  599.     mov    di,[bp+4+4]
  600.     mov    dx,if_type
  601.     mov    [di],dx            ; type
  602.     mov    di,[bp+4+6]
  603.     xor    ch,ch
  604.     mov    cl,if_num
  605.     mov    [di],cx            ; interface number, as an int
  606.     pop    ax            ; recover al
  607.     mov    di,[bp+4+8]
  608.     xor    ah,ah
  609.     mov    al,if_func
  610.     mov    [di],ax            ; functionality, as an int
  611.     mov    ax,1            ; C style exit status, 1 = success
  612.     pop    bx
  613.     pop    cx
  614.     pop    di
  615.     pop    bp
  616.     ret
  617. _pdinfo    endp
  618.  
  619. ; int pdclose(int handle)
  620. ; Close a Packet Driver or ODI handle.
  621. ; Returns (in AX) 1 if successful, else 0.
  622.     public    _pdclose
  623. _pdclose    proc    near
  624.     push    bp
  625.     mov    bp,sp
  626.     push    bx
  627.     mov    bx,[bp+4+0]        ; handle
  628.     cmp    useodi,0        ; using ODI?
  629.     je    pdclos2            ; e = no
  630.     mov    ax,bx            ; get handle
  631.     call    odiunbind        ; unbind from LSL and MLID
  632.     jmp    short pdclos3
  633.  
  634. pdclos2:mov    ah,pd_release        ; release_type
  635.     call    pktdrvr
  636.  
  637. pdclos3:mov    ax,1            ; assume success
  638.     jnc    pdclos1            ; nc = success
  639.     xor    ax,ax            ; 0 for failure
  640. pdclos1:pop    bx
  641.     pop    bp
  642.     ret
  643. _pdclose    endp
  644.  
  645. ; int pdaccess(char *type, int typelen, int *handle)
  646. ; Register access for packet TYPE with the Packet Driver or ODI
  647. ; Provides a handle for the TYPE.
  648. ; Returns 1 for success, 0 for failure.
  649.     public    _pdaccess
  650. _pdaccess proc    near
  651.     push    bp
  652.     mov    bp,sp
  653.     push    es
  654.     push    si
  655.     push    di
  656.     push    ds
  657.     push    es
  658.     mov    ax,dgroup        ; set up data segment addressibility
  659.     mov    ds,ax
  660.     mov    al,if_class        ; interface class (frame)
  661.     mov    bx,if_type        ; interface type (vendor)
  662.     mov    dl,if_num        ; interface number (board number)
  663.     xor    dh,dh
  664.     mov    si,[bp+4+0]        ; get offset of packet TYPE buffer
  665.     mov    cx,[bp+4+2]        ; typelen (length of buf contents)
  666.     cmp    useodi,0        ; using ODI?
  667.     je    pdacc8            ; e = no
  668.     mov    ax,[si]            ; provide TYPE
  669.     call    odibind            ; Bind to a virtual board
  670.     jc    pdacc1            ; c = fail, error code in AX
  671.     jmp    short pdacc9        ; store handle returned in AX
  672.  
  673. pdacc8:    cmp    if_class,IF_SLIP    ; SLIP?
  674.     jne    pdacc3            ; ne = no
  675.     xor    cx,cx            ; TYPE len = 0 means accept all types
  676. pdacc3:    mov    di,cs            ; ES:DI is our Packet Driver receiver
  677.     mov    es,di
  678.     mov    di,offset pdrcvr    ; local receiver
  679.     mov    ah,pd_access        ; set access
  680.     call    pktdrvr
  681.     jc    pdacc1            ; c = failure
  682. pdacc9:    mov    si,[bp+4+4]        ; offset of handle
  683.     mov    [si],ax            ; return the handle
  684. pdacc1:    mov    ax,1            ; C level status, 1 = success
  685.     jnc    pdacc2            ; nc = success
  686.     xor    ax,ax            ; 0 = failure
  687. pdacc2:    pop    es
  688.     pop    ds
  689.     pop    di
  690.     pop    si
  691.     pop    es
  692.     pop    bp
  693.     ret
  694. _pdaccess endp
  695.  
  696. ; int pkt_send(char *buffer, int length)
  697. ; returns 1 on success, 0 on failure
  698. ; Send a packet.
  699.     public    _pkt_send
  700. _pkt_send    proc    near
  701.     push    bp
  702.     mov    bp,sp
  703.     push    es
  704.     push    ds
  705.     push    si
  706.     push    di            ; don't trust lower levels on regs
  707.     push    cx
  708.     mov    ax,dgroup        ; segment of outgoing buffer
  709.     mov    ds,ax            ;  will be DS:SI for Packet Driver
  710.     mov    si,[bp+4+0]        ; buffer's offset (seg is dgroup)
  711.     mov    cx,[bp+4+2]        ; buffer's length
  712.  
  713.     cmp    useodi,0        ; using ODI?
  714.     je    pktsen5            ; e =no, use PD
  715. pktsen3:cmp    ecbx_busy,0        ; is ODI transmit done yet?
  716.     je    pktsen4            ; e = yes, else we can't touch it yet
  717.     mov    bx,PROTSUP_RELINQUISH_CONTROL
  718.     call    lslsupport        ; give time to LSL
  719.     jmp    short pktsen3        ; wait for done
  720. pktsen4:call    odixmt            ; do LSL transmit with DS:SI and CX
  721.     sti                ; interrupts back on (xmt turns off)
  722.     jmp    short pktsen1        ; done (AX non-zero if error)
  723. ; Note that checking for transmission errors is not readily done with async
  724. ; sending, so we cross our fingers and hope for the best.
  725.                     ;
  726.                     ; Packet Driver sending
  727. pktsen5:mov    ah,pd_send        ; send packet (buffer = ds:si)
  728.     call    pktdrvr            ; invoke Packet Driver
  729.                     ; common exit
  730. pktsen1:mov    ax,1            ; return C level success (1)
  731.     jnc    pktsen2            ; nc = success
  732.     xor    ax,ax            ; else C level failure (0)
  733. pktsen2:pop    cx
  734.     pop    di
  735.     pop    si
  736.     pop    ds
  737.     pop    es
  738.          pop    bp
  739.     ret
  740. _pkt_send endp
  741.  
  742. ; Our Packet Driver receiver, far called only by the Packet Driver and our
  743. ; local ODI code (odircvr and odircmp).
  744. ; Packet buffer linked list -
  745. ;    each link is    db flag        ; 1 = free, 2 = in use, 4 = allocated
  746. ;                    ;  but not in use yet, 0 = end of buf,
  747. ;                    ;  8 = read but not freed.
  748. ;            db _pktwnum    ; sequential number of pkt written
  749. ;            dw count    ; length of data field
  750. ;            db count dup (?) ; the allocated data field
  751. ;    The head of the chain has a link like all others.
  752. ;    The end of the chain has a link with flag == 0 and count = -BUFISZE
  753. ;    to point to the beginning of the buffer (circular).
  754. ;    Packet buffer garbage collection is done after a buffer has been
  755. ;    transferred to us, and does so by relinking adjacent free blocks.
  756. ; _pktbuf_wrote is used to remember the link where the last write occurred
  757. ; and should be initialized to the tail link to point the next write to
  758. ; the beginning of the buffer.
  759. ; The Packet Driver and our ODI routines call this first with AX = 0 to 
  760. ; obtain a buffer pointer in ES:DI from us (0:0 if we refuse the pkt) with 
  761. ; CX = packet size, and again later with AX = 1 to post completion.
  762.  
  763. pdrcvr    proc    far            ; Packet Driver receiver
  764.     or    ax,ax            ; kind of request (0, 1)
  765.     jz    pdrcvr1            ; z = first, get-a-buffer
  766.     ; Second upcall, packet has xfered, DS:SI set by caller to buffer
  767.     pushf                ; save interrupt status
  768.     cli                ; interrupts off
  769.      push    ds
  770.     push    si
  771.     push    bx
  772.     push    ax            ; assume DS:SI is one of our buffers
  773.     mov    ax,DGROUP
  774.     mov    ds,ax            ; set ds to our data segment
  775.     or    si,si            ; is it legal (from first upcall)?
  776.     jz    pdrcvr11        ; z = no, ignore this call
  777.     sub    si,linksize        ; backup to link info
  778.     cmp    byte ptr [si].flag,4    ; is this buffer allocated (4)?
  779.     jne    pdrcvr8            ; ne = no, do cleanups and quit
  780.     mov    byte ptr [si].flag,2    ; flag = 2 for buffer is now ready
  781.     mov    si,pktbufoff         ; start of packet buffer
  782.                     ; join contiguous free links
  783. pdrcvr8:mov    al,[si].flag        ; flags byte
  784.     cmp    al,1            ; is link free?
  785.     jne    pdrcvr10        ; ne = no, look for a free link
  786. pdrcvr9:mov    bx,[si].count        ; count (length) of this link
  787.     mov    al,[bx+si+linksize].flag; flag of following link
  788.     cmp    al,1             ; is next link free?
  789.     jne    pdrcvr10        ; ne = no, look for free link
  790.     mov    ax,[bx+si+linksize].count ; count taken from next link
  791.     add    ax,linksize        ;  plus the next link's info field
  792.     add    [si].count,ax        ; add it to this count (merge links)
  793.     jmp    short pdrcvr9        ; re-examine this new longer link
  794.  
  795. pdrcvr10:or    al,al            ; end of list?
  796.     jz    pdrcvr11        ; z = yes
  797.     add    si,[si].count        ; look at next link (add count)
  798.     add    si,linksize        ; and link info
  799.     jmp    short pdrcvr8        ; keep looking
  800. pdrcvr11:pop    ax
  801.     pop    bx
  802.     pop    si
  803.     pop    ds
  804.     popf
  805.     ret
  806.  
  807. pdrcvr1:pushf
  808.     cli
  809.     push    ds            ; First upcall, provide buffer ptr
  810.     push    dx            ; return buffer in ES:SI
  811.     push    cx
  812.     mov    di,dgroup        ; get local addressibility
  813.     mov    ds,di
  814.     mov    es,di            ; packet buffer is in same group
  815.     mov    di,_pktbuf_wrote    ; where last write occurred
  816.     or    di,di            ; NULL?
  817.     jz    pdrcvr4            ; z = yes, write nothing
  818.     mov    dl,100            ; retry counter, breaks endless loops
  819.     cmp    [di].flag,1        ; is this link free?
  820.     je    pdrcvr5            ; e = yes, use it
  821.  
  822. pdrcvr2:add    di,[di].count        ; point at next link (add count and
  823.     add    di,linksize        ;  link overhead)
  824.     dec    dl            ; loop breaker count down
  825.     or    dl,dl
  826.     jz    pdrcvr4            ; z = in an endless loop, exit
  827.     cmp    [di].flag,1        ; is this link free (1)?
  828.     je    pdrcvr5            ; e = yes, setup storage
  829.     cmp    di,_pktbuf_wrote     ; have we come full circle?
  830.     jne    pdrcvr2            ; ne = no, keep looking
  831. pdrcvr4:pop    cx
  832.     pop    dx
  833.     pop    ds            ; failure or buffer not available (0)
  834.     xor    ax,ax            ; return what we received in ax
  835.     xor    di,di            ; return ES:DI as null to reject
  836.     mov    es,di
  837.     popf
  838.     ret
  839.                     ; this link is free
  840. pdrcvr5:cmp    cx,ETH_MSS+40+12 +20    ; LARGEST PACKET WE ACCEPT
  841.     ja    pdrcvr4            ; a = too large, decline it
  842.     add    cx,2            ; defense for 8/16 bit xfr mistakes
  843.     mov    ax,[di].count        ; length of available data space
  844.     cmp    ax,cx            ; cx is incoming size, enough space?
  845.     jl    pdrcvr2            ; l = no, go to next link
  846.     mov    [di].flag,4        ; mark link flag as being alloc'd (4)
  847.     mov    dh,_pktwnum         ; write pkt sequencer number
  848.     mov    [di].bufnum,dh        ; store in buffer, permits out of
  849.     inc    _pktwnum        ;  temporal order deliveries
  850.     mov    _pktbuf_wrote,di    ; remember where we wrote last
  851.     sub    ax,cx            ; allocated minus incoming packet
  852.     cmp    ax,60+linksize        ; enough for new link and miminal pkt?
  853.     jl    pdrcvr6            ; l = not enough for next pkt
  854.     mov    [di].count,cx        ; update space really used
  855.     push    di            ; save this link pointer
  856.     add    di,linksize        ; plus current link info
  857.     add    di,cx            ; plus space used = new link point
  858.     sub    ax,linksize        ; available minus new link info
  859.     mov    [di].flag,1        ; mark new link as free (1)
  860.     mov    [di].count,ax        ; size of new free data area
  861.     pop    di            ; return to current link
  862. pdrcvr6:add    di,linksize        ; point at data portion
  863. pdrcvr7:xor    ax,ax            ; return what we received in ax
  864.     pop    cx
  865.     pop    dx
  866.     pop    ds            ; ES:DI is the pkt buffer address
  867.     popf                ; CX is size of requested buffer
  868.     ret
  869. pdrcvr    endp
  870.  
  871. ; Check for XT machines or Windows enhanced mode. Return carry set if either
  872. ; is true, else carry clear.
  873. chkxtwin proc    near
  874.     mov    ax,sp            ; do push sp test for XT vs AT/386
  875.     push    sp            ; XT pushes sp-2, AT's push old sp
  876.     pop    cx            ; recover pushed value, clean stack
  877.     xor    ax,cx            ; same?
  878.     je    chkxtw1            ; e = yes, AT and above    
  879.     stc
  880.     ret                ; XT, don't do Int 2fh check
  881. chkxtw1:push    es
  882.     mov    ah,getintv        ; check for valid Int 2Fh handler
  883.     mov    al,2fh            ; vector 2fh
  884.     int    dos            ; to es:bx
  885.     mov    ax,es
  886.     pop    es
  887.     or    ax,bx            ; check if vector exists
  888.     jnz    chkxtw2            ; nz = yes
  889.     stc
  890.     ret
  891.  
  892. chkxtw2:mov    ax,1683h        ; Windows 3, get current virt machine
  893.     int    2fh
  894.     cmp    ax,1683h        ; virtual machine, if any
  895.     je    chkxtw3            ; e = no Windows, ok to proceed
  896.     stc
  897.     ret
  898. chkxtw3:clc                ; neither XT nor Windows enhanced mode
  899.     ret
  900. chkxtwin endp
  901.  
  902. ; Begin Novell ODI support routines
  903. ; Note that while we use Ethernet_II (6 dest, 6 source, 2 TYPE bytes) to/from
  904. ; internal consumers the frame format to/from ODI is in the hands of ODI.
  905. ; Hopefully this will permit TCP/IP operation over all supported frame types.
  906. ; ARP/RARP packets are sized to the frame in use.
  907. ;
  908. ; Check for LSL presence, and if present then get entry points.
  909. ; Returns carry set if failure, else carry clear.
  910. ; This procedure is closely modeled upon the Novell example.
  911. odichk    proc    near
  912.     cmp    useodi,0        ; already inited?
  913.     je    odichk0            ; e = no
  914.     clc
  915.     ret
  916. odichk0:call    chkxtwin        ; check for XTs or Windows
  917.     jnc    odichk5            ; nc = neither, continue
  918.     ret                ; return failure
  919. odichk5:push    es
  920.     mov    ah,getintv        ; get LSL via multiplexer interrupt
  921.     mov    al,2fh            ; vector 2fh
  922.     int    dos            ; to es:bx
  923.     mov    ax,es
  924.     or    ax,bx            ; check if vector exists
  925.     jnz    odichk1            ; nz = yes
  926.     pop    es
  927.     stc
  928.     ret
  929.  
  930. odichk1:mov    ax,0c000h        ; look at multiplexer slots c0 et seq
  931.     push    si
  932.     push    di
  933. odichk2:push    ax
  934.     int    2fh
  935.     cmp    al,0ffh            ; is slot in use?
  936.     pop    ax
  937.     je    odichk4            ; e = yes, check for LSL being there
  938. odichk3:inc    ah            ; next slot
  939.     or    ah,ah            ; wrapped?
  940.     jnz    odichk2            ; nz = no, keep looking
  941.     pop    di
  942.     pop    si
  943.     pop    es
  944.     stc                ; not found, fail
  945.     ret
  946.  
  947. odichk4:mov    di,si            ; es:si should point to "LINKSUP$"
  948.     mov    si,offset DGROUP:lslsig    ; expected signature
  949.     mov    cx,lslsiglen        ; length
  950.     cld
  951.     repe    cmpsb            ; check for signature
  952.     jne    odichk3            ; ne = no match, try next Int 2fh slot
  953.     mov    word ptr lslinit,bx    ; found entry, save init entry point
  954.     mov    ax,es            ;  returned in es:bx
  955.     mov    word ptr lslinit+2,ax
  956.     mov    ax,ds
  957.     mov    es,ax            ; get LSL main support/service addrs
  958.     mov    si,offset DGROUP:lslsupport ; address of LSL entry point array
  959.     mov    bx,2            ; request support/service entry points
  960.         ; fills in far addresses of lslsupport and lslservice routines
  961.     call    lslinit            ; call LSL initialization routine
  962.     pop    di
  963.     pop    si
  964.     pop    es
  965.     clc                ; success
  966.     ret
  967. odichk    endp
  968.  
  969. ; Bind a protocol TYPE to an ODI virtual board.
  970. ; Enter with TYPE (big endian/network order) in AX.
  971. ; Packet reception begins immediately upon a successful bind.
  972. ; Uses NET.CFG if information is available.
  973. ; Obtain StackID (our ident to the LSL), ProtID (ident of LSL's decoder),
  974. ; and boardnumber (the logical board), then bind to start reception. Do for
  975. ; one of our protocols.
  976. ; Returns PD handle (TYPE) in AX and carry clear upon success, else carry set.
  977. odibind proc    near
  978.     push    ax
  979.     push    bx
  980.     push    si
  981.     push    di
  982.     push    es
  983.     mov    bx,DGROUP
  984.     mov    es,bx
  985.     cmp    ax,ip_type            ; IP, 0x0008h?
  986.     jne    odibind1            ; ne = no
  987.     mov    ax,offset DGROUP:ip_string    ; put IP string in request
  988.     mov    bx,offset ip_rcvr        ; set address of receiver esr
  989.     mov    di,offset DGROUP:ip_stackid    ; set address of stackid struc
  990.     jmp    short odibind3
  991.  
  992. odibind1:cmp    ax,arp_type            ; ARP, 0x0608?
  993.     jne    odibind2            ; ne = no
  994.     mov    ax,offset DGROUP:arp_string
  995.     mov    bx,offset arp_rcvr
  996.     mov    di,offset DGROUP:arp_stackid
  997.     jmp    short odibind3
  998.  
  999. odibind2:cmp    ax,rarp_type            ; RARP, 0x3580?
  1000.     je    odibind2a            ; e = yes
  1001.     jmp    odibindx            ; ne = no, fail
  1002. odibind2a:mov    ax,offset DGROUP:rarp_string
  1003.     mov    bx,offset rarp_rcvr
  1004.     mov    di,offset DGROUP:rarp_stackid
  1005.  
  1006. odibind3:mov    word ptr registerstk.StackNamePtr,ax ; insert ptr to string
  1007.     mov    word ptr registerstk.StackReceiveHandler,bx  ; setup esr addr
  1008.  
  1009. ; Note: to use Prescan or Default registrations delete StackNamePtr & StackID.
  1010. ; StackID is not used with these latter methods, and their reception begins
  1011. ; at registration rather than at bind (so this area would be redesigned).
  1012.     mov    bx,PROTSUP_REGISTER_STACK ; register the protocol by name
  1013.     mov    si,offset DGROUP:registerstk ; registration form pointer
  1014.     push    di            ; save ptr to xxx_stackid storage
  1015.     call    lslsupport        ; call LSL with the address in es:si
  1016.     pop    di
  1017.     jz    odibind3a        ; z = success
  1018.     jmp    odibindx        ; nz = failure
  1019. odibind3a:mov    [di].pstack,bx        ; save returned StackID (LSL's handle
  1020.                     ;  for our protocol stack)
  1021.     cmp    readnetcfg,0        ; have read NET.CFG for BIND info?
  1022.     jne    odibind4        ; ne = yes
  1023.     mov    useboard,-1        ; clear board-to-use word
  1024.     call    getbind            ; find Kermit's bind board in NET.CFG
  1025.     inc    readnetcfg        ; say have read the file
  1026.     cmp    word ptr bdname,256*'#'+2 ; is board name #<digit>?
  1027.     jne    odibind4        ; ne = no, assume regular driver name
  1028.     mov    al,bdname+2        ; get ascii digit
  1029.     sub    al,'1'            ; remove ascii bias (external=1 based)
  1030.     xor    ah,ah            ;  but we are zero based internally
  1031.     cmp    al,8            ; arbitrary limit of 8 boards
  1032.     ja    odibind4        ; a = out of range, ignore value
  1033.     mov    useboard,ax        ; and make this the board number
  1034.     mov    bdname,0        ; and don't use bdname as a name
  1035. odibind4:mov    [di].pboard,0        ; assume board zero to start loop
  1036.     mov    ax,useboard        ; board to be used, if any
  1037.     or    ax,ax            ; boards 0 and up are legal
  1038.     jl    odibind5        ; l = no board found yet, search
  1039.     mov    [di].pboard,ax        ; specify board, get ProtID
  1040.  
  1041. odibind5:mov    bx,PROTSUP_GET_MLID_CTL_ENTRY    ; get MLID control entry
  1042.     mov    ax,[di].pboard        ; for this board
  1043.     push    di
  1044.     call    lslsupport        ; call LSL for the address to es:si
  1045.     pop    di
  1046.     mov    word ptr mlidcont,si
  1047.     mov    word ptr mlidcont+2,es    ; MLID control routine
  1048.     jz    odibind7        ; z=success, have a board to work with
  1049.     cmp    ax,LSLERR_NO_MORE_ITEMS ; out of items?
  1050.     je    odibind5a        ; e = yes, no more boards
  1051.       cmp    ax,LSLERR_ITEM_NOT_PRESENT ; other boards may exist?
  1052.     je    odibind7        ; e = yes
  1053. odibind5a:jmp    odibindx        ; fail
  1054.  
  1055. odibind7:mov    bx,PROTSUP_GET_PID_PROTNUM_MLIDNUM ; get ProtID from StackID
  1056.     mov    ax,[di].pstack        ; StackID
  1057.     mov    cx,[di].pboard        ;  and assumed board number
  1058.     mov    si,dgroup
  1059.     mov    es,si            ; set es:di to the ProtID buffer
  1060.     lea    si,[di].pprotid        ;  in our storage slot per protocol
  1061.     push    di
  1062.     call    lslsupport        ; ask LSL for the ProtID string
  1063.     pop    di            ;  to that 6-byte buffer
  1064.     jz    odibind9        ; z = success, found a recognizer
  1065.     cmp    useboard,0        ; has a board been pre-identified?
  1066.     jge    odibind5a        ; ge = yes, so the matchup failed
  1067.     inc    [di].pboard        ; next board
  1068.     jmp    short odibind5        ; keep looking for a board
  1069.  
  1070. odibind9:mov    bx,GET_MLID_CONFIGURATION ; get MLID config ptr to es:si
  1071.     mov    ax,[di].pboard
  1072.     call    mlidcont        ; call MLID control routine
  1073.     jnz    odibindx        ; nz = failure
  1074.     cmp    bdname,0        ; was a board name bound via BIND?
  1075.     je    odibin10        ; e = no, don't check on it
  1076.     push    es            ; save pointer to MLID config table
  1077.     push    di
  1078.     push    si
  1079.     les    di,es:[si].MCardShortName ; get short name of this board
  1080.     lea    si,bdname        ; desired board name string
  1081.     mov    cl,bdname        ; length of desired board name
  1082.     inc    cl            ; include length byte
  1083.     xor    ch,ch
  1084.     cld
  1085.     repe    cmpsb            ; compare  len,string  for both
  1086.     pop    si
  1087.     pop    di
  1088.     pop    es
  1089.     je    odibin10        ; e = found desired board
  1090.     inc    [di].pboard        ; try next board
  1091.     jmp    short odibind5        ; keep looking for the desired board
  1092.  
  1093. odibin10:mov    ax,[di].pboard        ; get current board number
  1094.     mov    useboard,ax        ; remember for next protocol
  1095.     mov    ax,es:[si].MWorstDataSize ; max header, leaving this size
  1096.     sub    ax,20+20+4        ; minus IP and TCP header
  1097.     cmp    ax,ETH_MSS        ; smaller than our default?
  1098.     jae    odibin10a        ; ae = no, stay with our default
  1099.     mov    _mss,ax            ; set new operational value
  1100. odibin10a:mov    bx,es:[si].MFrameID    ; frame ident, for get_hwd
  1101.     call    get_hwd            ; get hardware specifics
  1102.     or    bx,bx            ; returned _MAC_len, if any
  1103.     jnz    odibin11        ; nz = found match
  1104.     mov    bx,6            ;  else default to 6 bytes
  1105. odibin11:push    es
  1106.     push    si            ; save config pointer
  1107.     lea    si,es:[si].MNodeAddress    ; point to address in config struct
  1108.     push    ds            ; save ds
  1109.     push    di
  1110.     mov    di,offset DGROUP:_eth_addr; where our MAC address is stored
  1111.     mov    ax,ds
  1112.     mov    cx,es
  1113.     mov    es,ax
  1114.     mov    ds,cx
  1115.     cld
  1116.     mov    cx,bx            ; MAC address length, bytes
  1117.     rep    movsb            ; copy MAC address to global array
  1118.     pop    di
  1119.     pop    ds
  1120.     pop    si            ; recover configuration table pointer
  1121.     pop    es
  1122.     mov    tells_len,0        ; presume no lookahead data length
  1123.     test    es:[si].MFlags,Len_Info    ; capas bit for length provided (new)
  1124.     jz    odibin12        ; z = does not provide
  1125.     inc    tells_len        ; say provides length
  1126.  
  1127. odibin12:mov    bx,PROTSUP_BIND_STACK_TO_MLID    ; Bind stack to MLID
  1128.     mov    ax,[di].pstack        ; StackID
  1129.     mov    cx,[di].pboard        ; board number
  1130.     call    lslsupport        ; bind our protocol stack to board
  1131.     jnz    odibindx        ; nz = failure
  1132.     pop    es            ; received packets can interrupt now
  1133.     pop    di
  1134.     pop    si
  1135.     pop    bx
  1136.     pop    ax
  1137.     clc
  1138.     ret
  1139. odibindx:pop    es
  1140.     pop    di
  1141.     pop    si
  1142.     pop    bx
  1143.     pop    ax
  1144.     stc                ; say failure
  1145.     ret
  1146. odibind endp
  1147.  
  1148. ; Worker for odibind. Find NET.CFG, extract name of board driver from pair of
  1149. ; lines reading as below (Protocol must be in column 1, bind must be indented)
  1150. ; Protocol Kermit            Kermit's main section header
  1151. ;   bind  <board_driver_name>        indented, without the <> signs
  1152. ;or
  1153. ; Protocol Kermit
  1154. ;   bind #<digit>            selects DOS driver load order (from 1)
  1155. ;
  1156. ; Examples -
  1157. ; Protocol Kermit
  1158. ;   bind exos
  1159. ;or
  1160. ; Protocol Kermit
  1161. ;   bind #2
  1162. ;            and elsewhere there is the board driver section:
  1163. ; Link Driver exos
  1164. ;
  1165. ; If found put the board driver name in array bdname, as length byte, string,
  1166. ; then a null. If not found make length byte bdname be zero. We treat NET.CFG
  1167. ; as case insensitive.
  1168. ; Unless we use the special Kermit section then LSL will assign to us the
  1169. ; first board loaded by DOS supporting the frame kind of our protocol.
  1170. ; Link Driver section line "Protocol name type frame"  simply associates a
  1171. ; frame kind with the name and type, but not with a board. L.D. section line
  1172. ; frame <frame kind> attaches that frame kind to the board, if it fits.
  1173. ; Kermit uses "name" in the above line to pinpoint a protocol, not a board.
  1174. getbind    proc    near
  1175.     mov    bdname,0        ; clear board name length
  1176.     push    ds
  1177.     mov    bx,GENSERV_GET_NETCFG_PATH ; get fully formed NET.CFG name
  1178.     call    lslservice        ;  from LSL general services to ds:dx
  1179.     jz    getbin1            ; z = success
  1180.     pop    ds            ; fail
  1181.     ret
  1182. getbin1:mov    ah,fopen        ; open file NET.CFG
  1183.     mov    al,40h            ;  for reading, deny none
  1184.     int    dos            ; returns file handle in ax
  1185.     pop    ds
  1186.     mov    temp,ax            ; save handle for getbyte
  1187.     jnc    getbin2            ; nc = success
  1188.     ret                ; carry set for failure
  1189.  
  1190. getbin2:mov    bx,1            ; subscript, at start of a line
  1191.  
  1192. getbin3:call    getbyte            ; read a byte, uppercased
  1193.     jnc    getbin4            ; nc = success
  1194.     ret                ; c = end of file
  1195. getbin4:cmp    protword[bx],al        ; compare to "PROTOCOL"
  1196.     jne    getbin5            ; ne = failure, scan for end of line
  1197.     inc    bx
  1198.     cmp    bl,protword        ; length, matched all bytes?
  1199.     jbe    getbin3            ; be = no, match more
  1200.     jmp    short getbin6        ; ae = yes, next phrase
  1201.     ret                ; fail out 
  1202.  
  1203. getbin5:cmp    al,LF            ; end of a line?
  1204.     je    getbin2            ; e = yes, scan for PROTOCOL again
  1205.     call    getbyte
  1206.     jnc    getbin5            ; keep consuming line material
  1207.     ret                ; fail out at end of file
  1208.                     ; Short Name following "PROTOCOL"
  1209. getbin6:call    getbyte            ; get separator char, discard
  1210.     jnc    getbin7
  1211.     ret                ; c = eof
  1212. getbin7:call    getbyte            ; read short name of protocol
  1213.     jnc    getbin7a        ; nc = text
  1214.     ret                ; return on eof
  1215. getbin7a:cmp    al,' '            ; white space?
  1216.     jbe    getbin7            ; be = yes, stay in this state
  1217.     mov    bx,1            ; subscript
  1218. getbin8:cmp    psname[bx],al        ; compare to our protocol short name
  1219.     jne    getbin5            ; ne = failure, scan for end of line
  1220.     cmp    bl,psname        ; matched all bytes?
  1221.     jae    getbin9            ; ae = yes, next phrase
  1222.     inc    bx
  1223.     call    getbyte            ; get next byte to match
  1224.     jnc    getbin8            ; nc = not eof yet
  1225.     ret
  1226.  
  1227. getbin9:call    getbyte            ; go to next line, enforce whitespace
  1228.     jc    getbin20        ; c = eof
  1229.     cmp    al,LF            ; end of a line?
  1230.     jne    getbin9            ; ne = no, scan for end of line
  1231.     call    getbyte            ; look for whitespace
  1232.     jc    getbin20        ; c = eof
  1233.     cmp    al,'#'            ; comment line?
  1234.     je    getbin9            ; e = yes, get next line
  1235.     cmp    al,' '            ; required whitespace?
  1236.     ja    getbin5            ; a = no, start over
  1237.  
  1238. getbin10:call    getbyte            ; look for keyword "BIND"
  1239.     jc    getbin20
  1240.     cmp    al,' '            ; white space?
  1241.     jbe    getbin10        ; be = yes, stay in this state
  1242.     mov    bx,1            ; subscript
  1243. getbin11:cmp    bindword[bx],al        ; compare to "BIND"
  1244.     jne    getbin5            ; ne = failure, start over
  1245.     cmp    bl,bindword        ; matched all bytes?
  1246.     jae    getbin12        ; ae = yes, next phrase
  1247.     call    getbyte
  1248.     jc    getbin20        ; c = eof
  1249.     inc    bx
  1250.     jmp    short getbin11        ; keep reading
  1251.  
  1252. getbin12:call    getbyte            ; skip white space before board name
  1253.     jc    getbin20            
  1254.     cmp    al,' '            ; white space?
  1255.     jbe    getbin12        ; be = yes, skip it
  1256.  
  1257. getbin13:mov    bl,bdname        ; board name, length byte, starts at 0
  1258.     xor    bh,bh
  1259.     inc    bl
  1260.     mov    bdname,bl        ; update length of board driver name
  1261.     xor    ah,ah            ; get a null
  1262.     mov    word ptr bdname[bx],ax    ; store as board short name,null
  1263.     cmp    bx,15            ; legal limit on short name?
  1264.     jbe    getbin14        ; be = ok
  1265.     mov    bdname,ah        ; illegal, clear board name length
  1266.     jmp    getbin15        ; and quit
  1267. getbin14:call    getbyte
  1268.     jc    getbin20        ; reached eof, is ok
  1269.            cmp    al,' '            ; usable text?
  1270.     ja    getbin13        ; a = yes, else stop storing name
  1271. getbin15:call    getbyte            ; read to eof so file is closed
  1272.     jnc    getbin15        ; nc = got a char
  1273. getbin20:ret    
  1274. getbind    endp
  1275.  
  1276. ; Worker for getbind. Delivers one byte per call from NET.CFG, upper cased.
  1277. ; Returns carry set and NET.CFG file closed at end of file.
  1278. ; Temp has NET.CFG file handle, tempb is our one byte buffer for disk i/o.
  1279. getbyte    proc    near
  1280.     mov    dx,offset tempb        ; ds:dx points to start of buffer
  1281.     mov    ah,fread        ; read from file to buffer
  1282.     mov    cx,1            ; this many bytes
  1283.     push    bx
  1284.     mov    bx,temp            ; get file handle
  1285.     int    dos
  1286.     pop    bx
  1287.     jc    getbyt2            ; c = failure
  1288.     cmp    ax,1            ; got the single byte?
  1289.     jb    getbyt2            ; b = no, failure
  1290.     mov    al,tempb        ; return read byte
  1291.     cmp    al,'z'            ; in lower case range?
  1292.     ja    getbyt1            ; a = no
  1293.     cmp    al,'a'            ; in lower case range?
  1294.     jb    getbyt1            ; b = no
  1295.     and    al,not 20h        ; lower to upper case
  1296. getbyt1:clc                ; carry clear for success
  1297.     ret                ; return char in AL
  1298. getbyt2:push    bx
  1299.     mov    bx,temp            ; file handle
  1300.     mov    ah,fclose        ; close the file
  1301.     int    dos
  1302.     pop    bx
  1303.     stc                ; say EOF or other failure
  1304.      ret
  1305. getbyte    endp
  1306.  
  1307. ; Worker for odibind.
  1308. ; Enter with BX holding Novell frame type from the MLID configuration table. 
  1309. ; Set _arp_hardware and _MAC_len and return BX holding _MAC_len value, else 
  1310. ; if frame is not supported return BX = 0. These two values are needed by the
  1311. ; ARP functions. This list searching method is to accomodate the ever 
  1312. ; expanding quantity of frame types appearing with ODI; we deal with those we
  1313. ; understand (sic).
  1314. get_hwd    proc    near
  1315.     push    es
  1316.     push    di
  1317.     mov    ax,DGROUP
  1318.     mov    es,ax
  1319.     mov    al,bl            ; get frame value (MLID config)
  1320.     xor    bx,bx            ; prepare no-match return value
  1321.     mov    di,offset frame_type    ; list to search
  1322.     mov    cx,num_frames        ; number of elements in the list
  1323.     cld
  1324.     repne    scasb            ; byte search
  1325.     jne    get_hwd1        ; ne = no match, fail
  1326.     sub    di,offset frame_type+1    ; make di be an index along the list
  1327.     mov    al,hardware_type[di]    ; ARP/RARP hardware type ident
  1328.     xor    ah,ah            ; return in local (host) order
  1329.     mov    _arp_hardware,ax    ; hardware type for ARP/RARP pkts
  1330.     mov    bl,frame_adlen[di]    ; array of MAC lengths for frame types
  1331.     xor    bh,bh
  1332.     mov    _MAC_len,bx        ; save MAC address length (1..6 bytes)
  1333.     pop    di
  1334.     pop    es
  1335.     ret
  1336. get_hwd1:mov    _arp_hardware,bx    ; hardware type 0 for ARP/RARP pkts
  1337.     mov    _MAC_len,bx        ; save MAC address length (0 bytes)
  1338.     pop    di
  1339.     pop    es
  1340.     ret                ; return _MAC_len in BX
  1341. get_hwd    endp
  1342.  
  1343. ; Unbind a protocol TYPE from an ODI virtual board
  1344. ; Enter with protocol TYPE (net order) in AX, return carry set if failure.
  1345. ; The TYPE is used as our handle to the application.
  1346. ; Prescan and Default methods call lslsupport with the board number in AX 
  1347. ; rather than StackID and use matching PROTSUP_DEREGISTER_* code.
  1348. odiunbind proc    near
  1349.     cmp    ax,ip_type        ; IP, 0x0008h?
  1350.     jne    odiunb1            ; ne = no
  1351.     mov    ax,ip_stackid.pstack    ; StackID
  1352.     jmp    short odiunb3
  1353.  
  1354. odiunb1:cmp    ax,arp_type        ; ARP, 0x0608?
  1355.     jne    odiunb2            ; ne = no
  1356.     mov    ax,arp_stackid.pstack
  1357.     jmp    short odiunb3
  1358.  
  1359. odiunb2:cmp    ax,rarp_type        ; RARP, 0x3580?
  1360.     jne    odiunb4            ; ne = no
  1361.     mov    ax,rarp_stackid.pstack
  1362.  
  1363. odiunb3:mov    bx,PROTSUP_DEREGISTER_STACK ; deregister stack (StackID in AX)
  1364.     call    lslsupport        ; stops reception now
  1365.     jnz    odiunb4            ; nz = failure
  1366.     clc                ; success
  1367.     ret
  1368. odiunb4:stc                ; failure
  1369.     ret
  1370. odiunbind endp
  1371.  
  1372. ; ODI receive interrupt handler, for use only by the LSL.
  1373. ; Called with DS:DI pointing to lookahead structure, interrupts are off.
  1374. ; Returns ES:SI pointing at ECB, AX = 0 if we want pkt, AX = 8001h if decline.
  1375. ; There are three of these, one each for IP, ARP, and RARP. All have the
  1376. ; same calling convention and all jump to odircv to do the real work. 
  1377. ; The length of the arriving packet is available if the MLID supports the
  1378. ; new (mid-May 1992) capability, our "tells_len"; otherwise we make an
  1379. ; intelligent guess based on the protocol header. These entry points can be 
  1380. ; called multiple times before receive-completion, and likely will be, so we
  1381. ; use several ecb's to accept requests.
  1382. ip_rcvr    proc    far
  1383.     push    bx
  1384.     push    cx
  1385.     push    di
  1386.     push    ds
  1387.     mov    cx,ds            ; DS:DI from LSL
  1388.     mov    es,cx            ; use ES for LSL items
  1389.     mov    ax,DGROUP        ; set DS to our data segment
  1390.     mov    ds,ax
  1391.     push    es
  1392.     push    si
  1393.     cmp    tells_len,0        ; have data length available?
  1394.     je    ip_rec1            ; e = no
  1395.     les    si,es:[di].DataLookAheadDataSize ; ptr to what it says
  1396.     mov    cx,word ptr es:[si]    ; get length of data field
  1397.     add    cx,4            ; for overzealous board transfers
  1398.     pop    si
  1399.     pop    es
  1400.     jmp    far ptr odircv
  1401.  
  1402. ip_rec1:les    si,es:[di].LookAheadPtr    ; point at data lookahead ptr
  1403.     mov    cx,word ptr es:[si+2]    ; IP pkt header, length word
  1404.     cmp    byte ptr es:[si],45h    ; validate IP pkt kind (ver/hlen)?
  1405.     pop    si
  1406.     pop    es
  1407.     jne    ip_rcvr1        ; ne = invalid, decline
  1408.     xchg    ch,cl            ; net to local order
  1409.     add    cx,14+8            ; our MAC level addressing + 8 safety
  1410. ip_rec2:mov    ax,ip_stackid.pstack    ; StackID for ecb structure
  1411.     mov    rcvtype,ip_type        ; store protocol TYPE int
  1412.     cmp    cx,ETH_MSS+40+12+20    ; LARGEST ACCEPTABLE PKT
  1413.     jbe    odircv            ; be = acceptable length
  1414.  
  1415. ip_rcvr1:add    pstats.PIgnoredRxPackets,1 ; update ODI statistics counter
  1416.     adc    pstats.PIgnoredRxPackets+2,0
  1417.     mov    ax,LSLERR_OUT_OF_RESOURCES ; decline the packet
  1418.     or    ax,ax            ; set Z flag to match AX
  1419.     pop    ds
  1420.     pop    di
  1421.     pop    cx
  1422.     pop    bx
  1423.     ret
  1424. ip_rcvr    endp
  1425.  
  1426. ; RARP protocol receive service routine, similar to ip_rcvr.
  1427. rarp_rcvr proc    far
  1428.     push    bx
  1429.     push    cx
  1430.     push    di
  1431.     push    ds
  1432.     mov    cx,ds            ; DS:SI from LSL
  1433.     mov    es,cx
  1434.     mov    ax,DGROUP        ; set DS to our data segment
  1435.     mov    ds,ax
  1436.     mov    ax,rarp_stackid.pstack    ; StackID for ecb structure
  1437.     mov    rcvtype,rarp_type    ; store protocol TYPE int
  1438.     jmp    short arp_common    ; do ARP/RARP common code
  1439. rarp_rcvr endp
  1440.  
  1441. ; ARP protocol receive service routine, similar to ip_rcvr.
  1442. arp_rcvr proc    far
  1443.     push    bx
  1444.     push    cx
  1445.     push    di
  1446.     push    ds
  1447.     mov    cx,ds            ; DS:SI from LSL
  1448.     mov    es,cx
  1449.     mov    ax,DGROUP        ; set DS to our data segment
  1450.     mov    ds,ax
  1451.     mov    ax,arp_stackid.pstack    ; StackID for ecb structure
  1452.     mov    rcvtype,arp_type    ; store protocol TYPE int
  1453.  
  1454. arp_common:                ; common code for ARP/RARP
  1455.     push    es
  1456.     push    si
  1457.     cmp    tells_len,0        ; have data length available?
  1458.     je    arp_com1        ; e = no
  1459.     les    si,es:[di].DataLookAheadDataSize ; ptr to what it says
  1460.     mov    cx,word ptr es:[si]    ; get length of data field
  1461.     add    cx,4            ; for overzealous board transfers
  1462.     pop    si
  1463.     pop    es
  1464.     jmp    short odircv
  1465.  
  1466. arp_com1:les    si,es:[di].LookAheadPtr    ; point at lookahead ptr for Data
  1467.     mov    cx,word ptr es:[si+4]    ; ARP/RARP pkt header, length bytes
  1468.     add    cl,ch            ; add HA and IP address lengths
  1469.     xor    ch,ch
  1470.     add    cl,cl            ; for host and target
  1471.     adc    ch,0
  1472.     add    cx,8            ; plus ARP/RARP main header
  1473.     cmp    word ptr es:[si+2],ip_type ; ARP/RARP Protocol type of IP?
  1474.     pop    si
  1475.     pop    es
  1476.     jne    ip_rcvr1        ; ne = invalid, decline
  1477.     ; fall through to odircv
  1478. arp_rcvr endp
  1479.  
  1480. ; General worker for ip_rcvr, arp_rcvr, rarp_rcvr. These are invoked by the
  1481. ; LSL when their kind of packet arrives. This module creates the ECB and
  1482. ; dispatches it to the LSL. Operating at LSL interrupt level.
  1483. ; ES:DI is ptr to ODI Lookahead structure, DS is our data seg (DGROUP).
  1484. ; AX is stackid for invoked protocol kind, CX is (guessed) pkt length overall.
  1485. ; Rcvtype is the current invoked protocol TYPE (0008h is IP etc).
  1486. ; When done store in the ecb's protocolws array:
  1487. ;    dw    protocol TYPE (0008h for IP etc)
  1488. ;    dw    subscript of this ecbr item (for use by odircmp)
  1489. ;    dw    <unused>,<unused>
  1490. ; Return ES:SI as pointer to a free ecb and AX = 0 to accept pkt, else
  1491. ; return AX = 8001h to decline pkt (and to ignore ES:SI). Set Z flag to
  1492. ; match AX value.
  1493. odircv    proc    far
  1494.     add    pstats.PtotalRxPackets,1 ; update ODI statistics counter
  1495.     adc    pstats.PtotalRxPackets+2,0
  1496.     push    ax
  1497.     push    cx
  1498.     mov    cx,ecbr_qty        ; number of receive ecb's
  1499.     xor    bx,bx            ; find a free ecb for this packet
  1500. odircv8:cmp    ecbr_busy[bx],0        ; is this ECB free?
  1501.     jne    odircv9            ; ne = no, try next
  1502.     mov    ecbr_num,bx        ; remember index for end of proc
  1503.     mov    ax,size ecbstruct    ; size of an ecb
  1504.     mul    bl            ; times this subscript
  1505.     add    ax,offset DGROUP:ecbr    ; start of receive ecbs
  1506.     mov    bx,ax            ; offset of free ecb
  1507.     pop    cx
  1508.     pop    ax
  1509.     jmp    short odircv2        ; use ds:[bx] for address of ecb
  1510. odircv9:inc    bx            ; next byte in busy array
  1511.     loop    odircv8
  1512.     pop    cx            ; failed to find a free ecbr
  1513.     pop    ax
  1514.  
  1515. odircv1:add    pstats.PIgnoredRxPackets,1 ; update ODI statistics counter
  1516.     adc    pstats.PIgnoredRxPackets+2,0
  1517.     mov    ax,LSLERR_OUT_OF_RESOURCES ; decline the packet
  1518.     or    ax,ax            ; set Z flag for ODI
  1519.     pop    ds
  1520.     pop    di
  1521.     pop    cx
  1522.     pop    bx
  1523.     ret
  1524.                     ; ds:[bx] is ptr to a free ecbr
  1525. odircv2:mov    [bx].stackid,ax        ; StackID from odircv entry points
  1526.     mov    ax,es:[di].LBoardNum    ; boardnum from ProtocolID lookahead
  1527.     mov    [bx].boardnum,ax    ; store in ecbr
  1528.     mov    ax,rcvtype        ; get TYPE from odircv entry points
  1529.     mov    word ptr [bx].protocolws,ax    ; save TYPE for odircmp
  1530.     mov    ax,ecbr_num        ; ecbr index
  1531.     mov    word ptr [bx].protocolws+2,ax    ; save index for odircmp
  1532.  
  1533.     cmp    cx,64            ; min packet for Ethernet + 4 spare
  1534.     jae    odircv3            ; ae = no padding needed here
  1535.     mov    cx,64            ; padded min pkt plus 4 spare bytes
  1536. odircv3:push    bx            ; get a buffer of length CX bytes
  1537.     xor    ax,ax            ; set AX = 0 for PD "get buf" call
  1538.     call    pdrcvr            ; use PD buffer allocator code
  1539.     pop    bx            ; ES:DI = buffer pointer, CX = length
  1540.     mov    ax,es
  1541.     or    ax,di            ; check for refused pkt (es:di = NULL)
  1542.     jz    odircv1            ; z = pkt refused (no buffer space)
  1543.     add    di,6+6+2        ; skip our MAC header for ecb use
  1544.     sub    cx,6+6+2        ; less same length for MLID
  1545.     mov    [bx].frag1addr,di    ; offset of buffer which MLID sees
  1546.     mov    ax,es
  1547.     mov    [bx].frag1addr+2,ax    ; seg of buffer
  1548.     mov    [bx].datalen,cx        ; length of buffer for MLID/LSL use
  1549.     mov    [bx].frag1len,cx    ; ditto
  1550.     mov    ax,DGROUP        ; segment of our ecb's
  1551.     mov    es,ax
  1552.     mov    si,bx            ; return ES:SI pointing to ECB
  1553.     mov    bx,ecbr_num        ; get ecbr index
  1554.     mov    ecbr_busy[bx],1        ; mark this ecbr as busy
  1555.     pop    ds
  1556.     pop    di
  1557.     pop    cx
  1558.     pop    bx
  1559.     xor    ax,ax            ; return AX = 0 to accept
  1560.     ret
  1561. odircv    endp
  1562.  
  1563. ; ODI receive-complete call-back routine for use only by the LSL.
  1564. ; Enter with ES:SI pointing at ECB, interrupts are off.
  1565. ; Returns nothing.
  1566. ; There is no guarantee that this routine will be called in the sequence
  1567. ; which packets arrived, so we carry the bookkeeping in the delivered ECB:
  1568. ; TYPE is for Ethernet_II struct results, ecbr_busy is don't-touch interlock.
  1569. ; Note that we have to construct our own "destination" MAC address.
  1570. ; es:[si].status is 0 (success), 8006h (buffer overrun), 8007h (canceled).
  1571. ; StackID field is from LSL, and it's 0ffffh if using Prescan, and undefined
  1572. ; if using Default. The manual says LSL, but not MLID, calls are ok in here.
  1573. odircmp    proc    far
  1574.     push    ds
  1575.     push    ax
  1576.     push    bx
  1577.     push    cx
  1578.     mov    ax,DGROUP
  1579.     mov    ds,ax            ; set ds to our data segment
  1580.     cmp    es:[si].frag1addr+2,0    ; segment of pkt being confirmed
  1581.     je    odircmp5        ; e = illegal, ignore this call
  1582.     cmp    es:[si].status,0     ; check ECB status for failure
  1583.     je    odircmp1        ; e = success
  1584.     mov    es:[si].protocolws,0    ; write TYPE of 0 to permit queueing
  1585. odircmp1:push    di            ; put dest,src,TYPE into pkt buffer
  1586.     push    es
  1587.     push    si            ; save ecbr's si
  1588.     mov    cl,byte ptr es:[si].driverws ; kind of destination, from LSL
  1589.     mov    di,es:[si].frag1addr    ; start of our pkt buffer + 6+6+2
  1590.     sub    di,6+6+2        ; back to start, for our MAC header
  1591.     push    ds            ; WATCH this, presumes ES == DS!
  1592.     pop    es            ; set ES to DS (where pkt buffer is)
  1593.     mov    si,offset DGROUP:_eth_addr ; our hardware address
  1594.     cmp    cl,ECB_BROADCAST     ; a broadcast?
  1595.     jne    odircmp2        ; ne = no, use our address
  1596.     mov    si,offset DGROUP:bcast    ; fill with all 1's
  1597. odircmp2:mov    cx,3            ; 6 byte addresses to our application
  1598.     cld
  1599.      rep    movsw            ; store source address in pkt buffer
  1600.     pop    si            ; recover ecb si
  1601.     push    si            ; save it again
  1602.     mov    ax,es:[si].protocolws     ; get TYPE, from odircv
  1603.     lea    si,es:[si].immaddr    ; offset to MAC address of sender
  1604.     mov    cx,3            ; three words worth, garbage and all
  1605.     rep    movsw            ; copy to packet buffer
  1606.     stosw                ; and write TYPE to packet buffer
  1607.     pop    si
  1608.     pop    es
  1609.     pop    di
  1610.     mov    cx,es:[si].datalen    ; length of data field from ecb
  1611.     add    cx,6+6+2        ; plus space for dest,src,TYPE
  1612.     push    es            ; save ecb's es:si
  1613.     push    si
  1614.     mov    si,es:[si].frag1addr    ; offset of pkt being confirmed
  1615.     sub    si,6+6+2        ; adj to beginning, for our MAC header
  1616.     mov    ax,1            ; set AX = 1 for buffer done call
  1617.     call    pdrcvr            ; do post processing of buffer
  1618.     pop    si
  1619.     pop    es
  1620.  
  1621. odircmp5:xor    ax,ax
  1622.     cmp    es:[si].frag1addr+2,ax    ; segment of pkt being confirmed
  1623.     je    odircmp6        ; e = illegal, ignore this call
  1624.     mov    es:[si].frag1addr+2,ax    ; clear pkt buffer pointer (seg)
  1625.     mov    es:[si].protocolws,ax     ; clear packet TYPE
  1626.     mov    bx,es:[si].protocolws+2    ; point to ecb index
  1627.     mov    ecbr_busy[bx],al    ; say this ecb is free now
  1628. odircmp6:pop    cx
  1629.     pop    bx
  1630.     pop    ax
  1631.     pop    ds
  1632.     ret
  1633. odircmp    endp
  1634.  
  1635. ; ODI transmission routine
  1636. ; Enter with ds:si pointing at full Ethernet_II packet, cx = length (bytes)
  1637. ; Once sent the ecb belongs to ODI until the xmt-complete routine is called.
  1638. odixmt    proc    near
  1639.     push    si
  1640.     push    di
  1641.     push    es
  1642.     mov    ax,ds
  1643.     mov    es,ax
  1644.     cmp    ecbx_busy,0        ; is this transmitter ecb free?
  1645.     je    odixmt8            ; e = yes
  1646. odixmt7:stc                ; say failure
  1647.     jmp    odixmt6            ; abandon
  1648.  
  1649. odixmt8:mov    ax,cx            ; overall Ethernet_II length
  1650.     sub    ax,6+6+2        ; omit our MAC header
  1651.     jc    odixmt6            ; c = failure, abandon
  1652.     mov    ecbx.datalen,ax        ; setup ECB overall data
  1653.     mov    ecbx.frag1len,ax    ; and fragment length
  1654.  
  1655.     mov    cx,3            ; three words of dest MAC address
  1656.     mov    di,offset DGROUP:ecbx.immaddr    ; destination address in ecb
  1657.     rep    movsw            ; copy destination MAC address
  1658.     add    si,6            ; skip source Ethernet address
  1659.     lodsw                ; get protocol TYPE, move it to AX
  1660.     mov    ecbx.frag1addr,si    ; offset of packet data
  1661.     mov    si,ds
  1662.     mov    ecbx.frag1addr+2,si    ; segment of packet data
  1663.  
  1664. ; Note: Prescan and Default methods use Raw Send: put 0ffffh in StackID
  1665. ; and include the full frame header in the data field. Check MLID 
  1666. ; configuration word ModeFlags, MRawSendBit, for Raw Send capability.
  1667.  
  1668.     cmp    ax,ip_type        ; IP, 0x0008h?
  1669.     jne    odixmt1            ; ne = no
  1670.     mov    si,offset DGROUP:ip_stackid
  1671.     jmp    short odixmt3
  1672.  
  1673. odixmt1:cmp    ax,arp_type        ; ARP, 0x0608?
  1674.     jne    odixmt2            ; ne = no
  1675.     mov    si,offset DGROUP:arp_stackid
  1676.     jmp    short odixmt3
  1677.  
  1678. odixmt2:cmp    ax,rarp_type        ; RARP, 0x3580?
  1679.     jne    odixmt7            ; ne = error, do not send
  1680.     mov    si,offset DGROUP:rarp_stackid
  1681.  
  1682. odixmt3:mov    cx,5            ; stackid, protid, boardnum
  1683.     mov    di,offset DGROUP:ecbx.stackid    ; get stack ident area
  1684.     rep    movsw            ; copy to ecbx
  1685.  
  1686.     mov    ecbx_busy,1        ; set ECBx busy flag to busy state
  1687.     add    pstats.PtotalTxPackets,1 ; update ODI statistics counter
  1688.     adc    pstats.PtotalTxPackets+2,0
  1689.  
  1690.     mov    si,offset DGROUP:ecbx    ; set es:si to ECB
  1691.     mov    bx,PROTSUP_SEND_PACKET    ; send it
  1692.     call    lslsupport        ; call LSL with ecbx ptr in es:si
  1693.     clc                ; success so far, ints are still off
  1694. odixmt6:pop    es
  1695.     pop    di
  1696.     pop    si
  1697.     ret
  1698. odixmt    endp
  1699.  
  1700. ; ODI transmission-complete processor, for use only by the LSL.
  1701. ; Returns nothing. Unlocks ECB busy flag.
  1702. odixcmp    proc    far
  1703.     push    ds
  1704.     push    ax
  1705.     mov    ax,DGROUP        ; set addressibility
  1706.     mov    ds,ax
  1707.     mov    ecbx_busy,0        ; set ECB busy flag to not-busy
  1708.     pop    ax
  1709.     pop    ds
  1710.     ret
  1711. odixcmp    endp
  1712.  
  1713. ; ODI Protocol (that's us) Control routine, required, called from outside.
  1714. ; In principle we should have one of these for each protocol (IP, ARP, RARP)
  1715. ; by putting a different StackControlHandler address in registerstk, but I 
  1716. ; doubt that anyone is that interested in such detailed counts.
  1717. ; Return AX clear, Z flag set, and ES:SI as table pointer if success, else
  1718. ; return AX with error code and Z flag clear.
  1719. pcontrol proc    far
  1720.     cmp    bx,GET_STACK_CONFIGURATION ; get stack configuration?
  1721.     jne    pcont1            ; ne = no
  1722.     mov    si,DGROUP
  1723.     mov    es,si            ; es:si points to configuration table
  1724.     mov    si,offset DGROUP:pconfig; the table
  1725.     xor    ax,ax            ; set Z flag
  1726.     ret
  1727. pcont1:    cmp    bx,GET_STACK_STATISTICS    ; get stack statistics?
  1728.     jne    pcont2            ; ne = no
  1729.     mov    si,DGROUP
  1730.     mov    es,si            ; es:si points to statistics table
  1731.     mov    si,offset DGROUP:pstats    ; the table
  1732.     xor    ax,ax            ; set Z flag
  1733.     ret
  1734. pcont2:    mov    ax,LSLERR_OUT_OF_RESOURCES ; other functions, report error
  1735.     or    ax,ax            ; clear Z flag
  1736.     ret
  1737. pcontrol endp
  1738.  
  1739. _TEXT    ends
  1740.         end
  1741.  
  1742.