TITLE DIS_PKT ; DIS_PKT.ASM - Adapter provides Packet Driver v1.09 interface over NDIS. ; Version 1.07 18 May 1991 by Joe R. Doupnik, Utah State Univ. ; Version 1.08 9 Aug 1991 by Dan Lanciani, ddl@harvard.harvard.edu ; Version 1.09 3 Nov 1991 by Joe R. Doupnik, Utah State Univ. ; Copyright (C) 1988 - 1991 FTP Software, Inc. ; ; This unmodified source file and it's executable form may be used and ; redistributed freely. The source may be modified, and the source or ; executable versions built from the modified source may be used and ; redistributed, provided that this notice and the copyright displayed by ; the exectuable remain intact, and provided that the executable displays ; an additional message indicating that it has been modified, and by whom. ; ; FTP Software Inc. releases this software "as is", with no express or ; implied warranty, including, but not limited to, the implied warranties ; of merchantability and fitness for a particular purpose. ; ; USE AT YOUR OWN RISK. ; ; ; To build, using Microsoft MASM 5 or later, LINK 3.64 or later, and EXE2BIN: ; ; masm dis_pkt; ; link dis_pkt; ; exe2bin dis_pkt.exe dis_pkt.dos ; del dis_pkt.exe ; del dis_pkt.obj ; ; ;What DIS_PKT.DOS does: It provides an Ethernet or a Token Ring Packet Driver ;interface to programs built to operate over Packet Drivers. It talks ;to NDIS (3Com/Microsoft) instead of to a lan board directly. It shares ;the board with NDIS users. We call this a "shim", sitting between the ;normal applications program (NetWare shells, TCP/IP, etc) and the more ;hardware specific portions (NDIS in this case). ; ; Packet Driver flavored applications NDIS flavored applications ; || || ; ------------- || ; | DIS_PKT | || ; ------------- || ; || || ; ------------------------------------------ ; | main module | ; | NDIS ........................ | ; | board specific driver(s) | ; ------------------------------------------- ; || ; -------------------------------- ; | Ethernet/Token Ring board(s) | ; -------------------------------- ; || ; =================================== Ethernet/Token Ring wire ; ; ;First sample PROTOCOL.INI file: ; ;[protocol manager] ; drivername = PROTMAN$ ; ;[pktdrv] <-- name of this driver entry ; drivername = pktdrv$ <-- formal driver name ; bindings = wd8003xmac <-- use your board's NDIS driver here ; intvec = 0x60 <-- Packet Driver Int, 60h..7fh ; chainvec = 0x66 <-- post-EOI processing interrupt, unused ; novell = y <-- Optional, if present and y(es) then ; convert between old Novell 802.3 pkts ; on the wire and Type 8137 for the app. ; Omitting this line or using any other ; response turns off the conversion; ; default is no conversion. ; ;[attiso] ; drivername = ATTISO$ <-- Another NDIS client ; bindings = wd8003xmac <-- bound to the same harware driver ; nsess = 5 ; ncmds = 14 ; use_emm = n ; ;Western Digital EtherCard PLUS Family Adapter <-- Ethernet board ;[wd8003xmac] <-- its ndis driver ; drivername = MACWD$ ; irq = 7 ; ramaddress = 0xCA00 ; iobase = 0x280 ; receivebufsize = 1536 <-- make this a full Ethernet pkt ; ; ; ; ;Sample section of CONFIG.SYS (StarGROUP material is not required): ; ;device=c:\lanman\protman.sys /i:c:\lanman <-- must be first ;device=c:\lanman\macwd.dos <-- WD8003E driver ;device=c:\lanman\dis_pkt.dos <-- Pkt Driver (this program) ;device=c:\lanman.dos\drivers\attload.dos /Y <-- StarGROUP NDIS ;device=c:\lanman.dos\drivers\attiso\attiso.dos <-- StarGROUP NDIS ;device=c:\qemm\loadhi.sys /r:1 e:\pctcp\ifcust.sys <-- PC/TCP stuff ;device=c:\qemm\loadhi.sys /r:4 e:\pctcp\ipcust.sys <-- etc ; ; ; A second, more elaborate example, with names easier to type. We start with ;file PROTOCOL.INI. Note that semicolons start comment lines. ; ;; This is a sample protocol.ini file listing three Ethernet boards: ;; attcsma.dos is an AT&T StarLAN 10 EN100 ;; elnkii.dos is a 3Com 3C503 ;; wd8003.dos is a Western Digital WD8003E ;; Only one board will be selected but the other two are present. ; ;[protocol manager] ; drivername = PROTMAN$ ; ;; Packet Driver protocol users tie in here ;[pktdrv] ; drivername = pktdrv$ ; bindings = attcsma ;; bindings= elnkii ;; bindings = wd8003 ; intvec = 0x60 ;; chainvec = 0x66 ; novell = no ; do not convert packet types this time ; ;; AT&T StarGROUP protocol stack ties in here via name ATTISO$ ;[attiso] ; drivername = ATTISO$ ; bindings = attcsma ;; bindings = elnkii ;; bindings = wd8003 ; nsess = 5 ; ncmds = 14 ; use_emm = n ; ;;Western Digital EtherCard PLUS Family Adapter, WD8003E in this case ;[wd8003] ; drivername = MACWD$ ; irq = 7 ; ramaddress = 0xCA00 ; iobase = 0x280 ; receivebufsize = 1536 ;; maxtransmits = 6 ;; receivebuffers = 6 ;; receivechains = 6 ; ;; 3Com Etherlink II, 3C503 ;[elnkii] ; drivername = ELNKII$ ; ioaddress = 0x350 ; interrupt = 5 ; transceiver = onboard ; maxtransmits = 12 ; xmitbufs = 1 ; ;; AT&T StarLAN 10 EN100 ;[attcsma] ; drivername = ATTCSMA$ ; board_type = 2 ; irq = 2 ; ioaddr = 0x360 ; daram = 0xD000 ; ;; End of file protocol.ini ; ;Fragment of config.sys for the second example. Note three .dos board drivers. ; ;device=c:\system\ramdrive.sys 1024 512 128 /E ;device=c:\lanman\protman.sys /i:c:\lanman.dos\drivers\star10en ;device=c:\lanman\attcsma.dos ;device=c:\lanman\elnkii.sys ;device=c:\lanman\macwd.dos ;device=c:\lanman\dis_pkt.dos ;device=c:\lanman.dos\drivers\attload.dos /Y ;device=c:\lanman.dos\drivers\attiso\attiso.dos ;device=c:\qemm\loadhi.sys /r:1 e:\pctcp\ifcust.sys ;device=c:\qemm\loadhi.sys /r:4 e:\pctcp\ipcust.sys ;device=c:\qemm\loadhi.sys /r:4 c:\netdev.sys ;shell=c:\command.com /p /e:800 ; ;It seems to be necessary to run NETBIND.EXE to get all this to be active. ; ; ; Edit History ; 06-Jul-89 WJR Changed interface flags in LDT to 2 per Norsk Data ; (may make vector binding work). Changed receive to ; allocate buffer for frame size instead of lookahead ; value. (This will fail miserably if the frame size ; is unknown at upcall time; such is life.) Changed ; SetPacketFilter to use module ID instead of dummy. ; 11-Sep-89 jbvb Clean up, add 1.09 functionality. ; 12-Sep-89 jbvb Don't do interrupt if vector contents are 0. ; 14-Sep-89 wjr Changed frame_rejected to frame_not_recognized to make ; vectored operation work. Changed send_pkt to use ; drv_cct.mod_id. Tried using 0 as protocol id in open ; adapter call. Changed device name to pktdrv$, ; flushed open adapter not supported message. ; 15-Sep-89 wjr Changed open adapter back to CS since 0 broke it. ; 24-Oct-89 wjr Changed FRAME_NOT_RECOGNIZED from 4 to 3 ; 07-Feb-90 wjr Added push and pop SI to rcv_chn & rcv_lah. ; 02-Apr-90 wjr Fixed xmt_chn to properly check for request queued ; 03-Apr-90 wjr Given changed TCP, treat REQUEST_QUEUED as success. ; 06-Apr-90 jbvb Update patch level to 2. ; 23-Apr-90 jbvb Don't trash BP, free init code, fix comments. ; 25-Apr-90 jbvb Support "extended" calls: get/set_rcv_mode, ; get_statistics will suffice for LW. ; 26-Apr-90 jbvb Support "match all" on typelen == 0. ; 05-Jun-90 jbvb Fix stack bug in "match all" handling in access_type, ; pass valid CX on 2nd receiver() upcall, version 5. ; 13-Jun-90 jbvb Write basic set_address() code, but comment it out ; because NDIS may require a CloseAdapter first in ; order for it to work. Not worth it to me. ; 27-Jul-90 jbvb Copyright, build instructions, release v1.05. ; 24-Mar-91 jrd Rewrite great chunks to straighen out stack and DS ; addressing. This now works with Novell IPX/NETn ; and Netwatch (together as a matter of fact) and ; with PC/TCP from FTP Inc. Version to 1.06. ; Joe R. Doupnik, jrd@cc.usu.edu, Utah State Univ. ; 30-Mar-91 jrd Allow 10 byte TYPE idents to pick out packets, ; more cleanups, more needed. Promiscuous mode put last. ; Allow 20 handles. Works fine with (NetWare+PC/TCP+ ; Netwatch) Pkt Drvr + Lan Man going simulanteously. ; Works with Clarkson issued Packet Driver utilities. ; 18-May-91 jrd Add filtering of packet addresses if running in ; promiscuous mode, add get current Ethernet address ; function to aid filtering, add receive mode indicator ; for each handle, correct error in snd_def initing. ; Correct problem with receive lookahead addressing. ; Compensate for 3Com drivers not preserving regs. ; Bump up NDIS tables to v2. Dis_pkt version to 1.07. ; 09-Aug-91 ddl 802.5, 802.3 support; default binding; overwrite fix ; 03-Nov-91 jrd Add keyword NOVELL to PROTOCOL.INI to convert between ; old Novell 802.3 packets on the wire to 8137 for the ; applications program. Convert if the line is present ; and the value is y(es). Small cleanups. PAGE ,80 EOL EQU <13, 10, '$'> LF = 10 CR = 13 EOS = '$' DOS equ 21h prstr equ 9 fopen equ 3dh fclose equ 3eh ioctl equ 44h MSG MACRO TEXT PUSH DX ;; save DX across call push ax push ds mov ax,cs mov ds,ax MOV DX,OFFSET TEXT ;; point to message mov ah,prstr ; display dollar terinated string int dos pop ds pop ax POP DX ENDM ; DOS request header offsets command = 2 status = 3 bpb = 18 end_off = 14 end_seg = 16 ; NDIS General Request codes INIT_DIAG equ 1 READ_ERR_LOG equ 2 SET_STA_ADDR equ 3 OPEN_ADAPTER equ 4 CLOSE_ADAPTER equ 5 RESET_MAC equ 6 SET_PKT_FLT equ 7 ADD_MULT_ADDR equ 8 DEL_MULT_ADDR equ 9 UPDATE_STATS equ 10 CLEAR_STATS equ 11 INTERRUPT_ME equ 12 SET_FUNC_ADDR equ 13 SET_LOOKAHEAD equ 14 ADDR_NONE EQU 0 ; NDIS Receiver modes: disabled ADDR_MULT EQU 1 ; Receive packets for my address & multicast ADDR_BRD EQU 2 ; Receive broadcast packets ADDR_PROM EQU 4 ; Receive all packets (promiscuous mode) ADDR_SRCRT EQU 8 ; Receive all source-routed packets ; Protocol to MAC return codes SUCCESS EQU 0 REQUEST_QUEUED EQU 2 FRAME_NOT_RECOGNIZED EQU 3 NOT_SUPPORTED EQU 9 GENERAL_FAILURE EQU 0FFH ; NDIS-related structure definitions cct_def struc dw 64 ; Size of common characteristics table (cct) dw 0 ; Level of cct (zero this version) dw 0 ; Level of service-specific subtables db 2 ; Major module version (2 BCD digits) db 0 ; Minor module version (2 BCD digits) dd 2 ; Module function flags db 'PKTDRV$', 9 dup (0) ; Module name, 16 byte ASCIIZ format db 4 ; Protocol level at upper boundary of module db 0 ; type of interface at upper module boundary db 1 ; protocol level at lower boundary of module db 1 ; type of interface at lower module boundary mod_id dw -1 ; module ID filled in by Protocol Manager mod_ds dw 0 ; module DS system dd 0 ; system request dispatch entry point sscp dd 0 ; pointer to service-specific characteristics sssp dd 0 ; pointer to service-specific status udtp dd 0 ; pointer to upper dispatch table ldtp dd 0 ; pointer to lower dispatch table dd 0 ; reserved (must be NULL) dd 0 ; reserved (must be NULL) cct_def ends ssc_def struc dw 94 ; length of MAC service-specific ; characteristics table (ssc) mtype db 16 dup (0) ; type name of MAC, ASCIIZ format dw 0 ; length of station addresses in bytes db 16 dup (0) ; permanent station address cur_add db 16 dup (0) ; current station address dd 0 ; current functional address of adapter dd 0 ; multicast address list dd 0 ; link speed svc_1 dw 0 ; service flags svc_2 dw 0 ; service flags maxfram dw 0 ; max frame size both sent and recv dd 0 ; total transmission buffer cap in driver dw 0 ; transmission buffer allocation block size dd 0 ; total reception buffer cap in driver dw 0 ; reception buffer allocation block size db 3 dup (0) ; IEEE vendor code (OUI) db 0 ; vendor adapter code dd 0 ; vendor adapter description pointer dw 0 ; IRQ of adapter (NDIS v2) dw 0 ; transmit queue depth (NDIS v2) ssc_def ends sss_def struc dw 0 ; length of status table dd 0 ; date/time of last diagnostics dd 0 ; MAC status dw 0 ; current packet filter dd 0 ; pointer to media specific statistics table dd 0 ; date/time of last ClearStatistics call r_tot dd 0 ; total frames received r_crc dd 0 ; frames with CRC error rb_tot dd 0 ; total bytes received r_drop dd 0 ; frames discarded - no buffer space r_mult dd 0 ; multicast frames received r_bro dd 0 ; broadcast frames received r_err dd 0 ; frames received with errors r_big dd 0 ; frames exceeding maximum size r_runt dd 0 ; frames smaller than minimum size rb_mul dd 0 ; multicast bytes received rb_bro dd 0 ; broadcast bytes received r_hwer dd 0 ; frames discarded - hardware error x_tot dd 0 ; total frames transmitted xb_tot dd 0 ; total bytes transmitted x_mul dd 0 ; multicast frames transmitted x_bro dd 0 ; broadcast frames transmitted xb_bro dd 0 ; broadcast bytes transmitted xb_mul dd 0 ; multicast bytes transmitted x_tmo dd 0 ; frames not transmitted - time-out x_hwer dd 0 ; frames not transmitted - hardware error sss_def ends udt_def struc ; upper dispatch table dd 0 ; back pointer to cct reqadd dd 0 ; request address xchain dd 0 ; TransmitChain address dd 0 ; TransferData address dd 0 ; ReceiveRelease address indon dd 0 ; IndicationOn address indoff dd 0 ; IndicationOff address udt_def ends ldt_def struc ; lower dispatch table dd 0 ; back pointer to cct dd 2 ; interface flags (2 means something) dd 0 ; RequestConfirm address dd 0 ; TransmitConfirm address dd 0 ; ReceiveLookahead indication address dd 0 ; IndicationComplete address dd 0 ; ReceiveChain indication address dd 0 ; status indication address ldt_def ends snd_def struc ; transmit buffer descriptor dw 0 ; byte count of immediate data (always 0) dd 0 ; address of immediate data dw 1 ; count of data blocks (always 1) db 0 ; pointer type (0 == physical) db 0 ; reserved snd_len dw 0 ; number of bytes to send snd_off dw 0 ; offset of data to send snd_seg dw 0 ; segment of data to send snd_def ends rcv_def struc ; receive buffer descriptor dw 1 ; count of data blocks (always 1) db 0 ; pointer type (0 == physical) db 0 ; reserved rcv_len dw 0 ; number of bytes to get rcv_off dw 0 ; offset of data to get rcv_seg dw 0 ; segment of data to get rcv_def ends req_def struc ; Request block - Protocol Manager primitives req_opc dw 0 ; opcode for PM request req_sta dw 0 ; status returned from request req_of1 dw 0 ; first parameter pointer req_sg1 dw 0 req_of2 dw 0 ; second parameter pointer req_sg2 dw 0 req_prm dw 0 ; parameter word req_def ends bnd_def struc ; binding list bnd_cnt dw 1 ; number of MACs to bind to -- 0 or 1 bnd_nam db 16 dup (0) ; name of module to bind to bnd_def ends SUBTTL Resident Data Area PAGE CSEG SEGMENT PARA PUBLIC 'CODE' assume cs:CSEG, ds:CSEG, es:nothing ; DEVICE HEADER - must be at offset zero within device driver DD -1 ; becomes pointer to next device header DW 8000H ; attribute (char device) DW OFFSET strat ; pointer to device strategy routine DW OFFSET intr ; pointer to device interrupt handler DB "PKTDRV$ " ; device driver name ; END OF DEVICE HEADER mac_cctp dd 0 ; address of MAC's cct table mac_ds dw 0 ; DS register for MAC rtn_cod dw 0 ; Save NDIS return code here drv_cct cct_def <> ; Common Characteristics Table drv_ldt ldt_def <> ; Lower Dispatch Table drv_snd snd_def <> ; Argument blocks for NDIS TransmitChain, drv_rcv rcv_def <> ; TransferData, drv_bnd bnd_def <> ; and Bind (via DOS IOCTL) drv_req req_def <> ; Argument block for general NDIS requests TransmitChain dd 0 ; MAC entry point to send packet TransferData dd 0 ; MAC entry point for data copy Request dd 0 ; MAC entry point for requests ReceiveRelease dd 0 ; MAC entry point (???not used???) IndicationOn dd 0 ; MAC entries to control Indications IndicationOff dd 0 ; (upcalls) from NDIS req_con_flg dw REQUEST_QUEUED ; Completion status from NDIS upcall init_flg db 0 ; Non-zero if we've been initialized address db 16 dup (0) ; Current address from MAC bytcnt dw 0 ; Bytes copied by TransferData xmt_cmp dw SUCCESS ; TransmitChain result open_adap dw 0 ; OpenAdapter & SetPacketFilter result ; Request Header (RH) address, saved here by "strategy" routine req_hdr LABEL DWORD req_off dw 0 req_seg dw 0 ; Save the request header for use by the interrupt routine strat PROC FAR mov word ptr cs:req_off,bx ; offset mov word ptr cs:req_seg,es ; segment ret strat ENDP EVEN ; Get into word alignment ;; ;; Data for Packet Driver ;; BAD_HANDLE EQU 1 ; invalid handle number NO_CLASS EQU 2 ; no interfaces of this class found NO_TYPE EQU 3 ; no interfaces of specified type found NO_NUMBER EQU 4 ; no interfaces of specified number found BAD_TYPE EQU 5 ; bad packet type specified NO_MULTICAST EQU 6 ; this interface does not support multicast CANT_TERMINATE EQU 7 ; this packet driver cannot terminate BAD_MODE EQU 8 ; an invalid receiver mode was specified NO_SPACE EQU 9 ; operation failed because of insufficient space TYPE_INUSE EQU 10 ; type had previously been accessed and not released BAD_COMMAND EQU 11 ; the command was out of range or not implemented CANT_SEND EQU 12 ; the packet couldn't be sent (usually hardware error) CANT_SET EQU 13 ; The hardware address couldn't be changed BAD_ADDRESS EQU 14 ; Hardware address has bad length or format CANT_RESET EQU 15 ; Couldn't reset interface (more than 1 handle open) PD_LEVEL EQU 6 ; Implementation level (basic, high perf, ext) ANY_TYPE EQU 0FFFFh ; Matches any if_type ETHERADDR_LEN EQU 6 ; Length of an Ethernet address ETHERTYPE_LEN EQU 2 ; Length of Ethertypes ETHERTYPE_NONE EQU 0 ; Ethertypes of 0 mean not defined ; The connection arrays: types, and corresponding upcalls PD_MAX_CONNS EQU 20 ; The maximum number of handles/Types that can ; be registered at one time MAX_P_LEN equ 10 ; max length of TYPE matching field, bytes per_handle struc ; Packet Driver HANDLE structure pd_conn_used db 0 ; non-zero if this handle is in use pd_conn_type db MAX_P_LEN dup(0) ; associated packet type pd_conn_type_len dw 0 ; associated packet type length pd_conn_rmode dw 3 ; receive mode for this handle pd_conn_rcvr dd 0 ; receiver handler address pd_conn_class db 0 ; interface class per_handle ends handles per_handle PD_MAX_CONNS dup(<>) end_handles label byte novell db 0 ; if non-zero convert between old ; Novell 802.3 interior to Type 8137 ; Caller used 8137, wire gets 802.3 ; Because some NDIS drivers can't support multiple calls to TransferData ; for a single reception, we only allow one handle (by implication, the last), ; to be in "match all" mode at a given time, but we do allow other handles ; to be open at the same time. if_class DB 1 ; Class 1 is Ethernet if_type DW 57 ; NDIS to Packet Driver adapter pd_version DW 9 ; Version conn_in_use DW 0 ; Number of handles open pd_vector DW -1 ; Packet Driver vector to serve on pd_rcv_mode DW 3 ; Default to rcv mode 3 (normal/bcast) pd_name DB "MAC/DIS converter", 0 pd_recvall db 0 ; non-zero if Promiscuous mode is active off dw 12 ; offset to match bytes aoff dw 0 ; offset to addresses ; Table re-maps (badly) NDIS modes to Packet Driver modes (in parentheses) ndis_mode db 0 ; No packets (0 == illegal) db 0 ; No packets (1 == receiver off) db 1 ; Directed | Multicast (2 should be directed only) db 3 ; Directed | Multicast | Broadcast ; (3 should be directed | broadcast) db 3 ; Directed | limited Multicast | Broadcast ; (4 == directed | broadcast | limited multicast) db 3 ; Directed | limited Multicast | Broadcast ; (5 should be directed | broadcast | all multicast) db 4 ; Promiscuous (6 == match all) EVEN ; Get into word alignment ; struct param; Pointer to this returned by get_parameters() pd_param db 1 ; Major revision = 1 db 9 ; Minor revision = 9 db 14 ; Length of this structure = 14 db ETHERADDR_LEN ; MAC addr length mtu dw 1514 ; MAC packet length dw 0 ; No multicast support dw 0 ; No promises re: back-to-back receives dw 0 ; No promises re: back-to-back transmits param_int dw 0 ; Default to no interrupt on EOI ; Pointer to this returned by get_statistics pd_statistics struc pkt_in dd 0 ; Total packets in pkt_out dd 0 ; Total packets out bytes_in dd 0 ; Total bytes received bytes_out dd 0 ; Total bytes sent errs_in dd 0 ; Total transmit errors errs_out dd 0 ; Total receive errors pkts_lost dd 0 ; Packets dropped - no buffer, out of resc pd_statistics ends pd_stat pd_statistics <> ; An instance of the above PUBLIC driver_info, access_type, release_type, send_pkt, terminate PUBLIC get_address, reset_interface, get_parameters, set_rcv_mode PUBLIC get_rcv_mode, get_statistics, set_address ; Normal (basic Packet Driver functions) Jump Table pd_table DW pd_none ; No handler DW driver_info ; 1 DW access_type ; 2 DW release_type ; 3 DW send_pkt ; 4 DW terminate ; 5 DW get_address ; 6 DW reset_interface ; 7 pd_table_size EQU ($-pd_table)/2 ; High Performance functions Jump Table hp_table DW get_parameters ; 10 DW pd_none ; 11 (as_send_pkt not implemented) hp_table_size EQU ($-hp_table)/2 ; Extended functions Jump Table ext_table DW set_rcv_mode ; 20 DW get_rcv_mode ; 21 DW pd_none ; 22 (set_multicast_list not implemented) DW pd_none ; 23 (get_multicast_list not implemented) DW get_statistics ; 24 DW set_address ; 25 ext_table_size EQU ($-ext_table)/2 ; ; rcv_lah is the proc that handles ReceiveLookAhead upcalls from the MAC ; ; First, it determines if the packet is one that is wanted. If so, it asks ; the appropriate application for a buffer. If it gets one, it copies the ; data and makes the 2nd call to the application to post it complete. If ; not, it returns SUCCESS to the DIS driver anyway. It returns SUCCESS if ; if the packet was copied or FRAME_NOT_RECOGNIZED if it is not in the list ; of desired types. ; ;The stack coming into this call is: ; dw bp[20] MACID ; dw bp[18] framesize ; dw bp[16] bytes available in buffer ; dw bp[14] lookahead data address seg ; dw bp[12] lookahead data address off ; dd bp[10] indicate flag ; dw bp[6] ds of called protocol mode (ME) ; rcv_lah PROC FAR push bp mov bp,sp push bx ; -2[bp] ; save things push cx ; -4[bp] push dx ; -6[bp] push di ; -8[bp] push ds ; -10[bp] push es ; -12[bp] sub sp,6 ; -14[bp] handle ; -16[bp] seg of PD buffer ; -18[bp] offset of PD buffer push si mov ax,cs ; setup data segment mov ds,ax mov ax,14[bp] ; segment of lookahead buffer mov es,ax mov di,12[bp] ; and its offset call pktfilter ; apply packet filter jnc lah_get_buf ; nc = we want this packet mov ax,FRAME_NOT_RECOGNIZED ; packet not accepted jmp lah_don lah_get_buf: ; Call Packet Driver receive routine to get its buffer address mov cx,18[bp] ; CX = packet length xor ax,ax ; AX = 0, 1st call to receiver mov -14[bp],bx ; BX = handle, for next call push bp ; we depend on BP call dword ptr cs:[bx].pd_conn_rcvr ; Call the receive routine pop bp ; Get BP back mov ax,es ; Buffer address is in ES:DI or ax,ax ; Check for segment of buffer, jnz rcvlha4 ; nz = ok or di,di ; Check for offset of buffer, jnz rcvlha4 ; nz = ok mov ax,SUCCESS ; No copy, accept pkt anyway jmp lah_don rcvlha4: ; Get data into buffer mov -16[bp],es mov -18[bp],di ; save PD buffer pointer mov ax,offset bytcnt ; Create far pointer to Addr push ds ; to put bytes copied into push ax ; and push it xor ax,ax ; Starting offset in frame push ax ; is always zero ; ; Set up recv table description ; mov ax,18[bp] ; Len of recv data mov drv_rcv.rcv_len,ax ; goes in argument descriptor mov drv_rcv.rcv_seg,es ; as does far address of mov drv_rcv.rcv_off,di ; receive buffer push ds ; Push far pointer to mov ax,offset drv_rcv ; descriptor push ax mov ax,mac_ds ; Push MAC's DS value push ax call dword ptr cs:TransferData ; Copy pkt to buf (pops args) ; ; Call Packet Driver receive routine again (AX = 1) to finish up ; mov ax,-16[bp] ; recover PD buffer pointer mov ds,ax mov si,-18[bp] ; to DS:SI for second PD call mov cx,18[bp] ; CX = packet length mov bx,-14[bp] ; BX = handle mov ax,1 ; AX = 1 (second call) call dword ptr cs:[bx].pd_conn_rcvr ; Call receive routine again mov ax,SUCCESS ; we accepted the packet lah_don:pop si add sp,6 ; local material pop es pop ds pop di pop dx pop cx pop bx pop bp ret 16 ; Pop MAC's params off stack rcv_lah ENDP ; ; rcv_chn is the proc that handles ReceiveChain upcalls from the MAC ; ; First, it determines if the packet is one that is wanted. Then it tranfers ; the data into an internal buffer. it blocks any new indications until the ; indicate complete upcall allows it the time to do a packet driver upcall. ; It returns success if the packet is ok or FRAME_NOT_RECOGNIZED if it is not ; in the list of currently open types. ; ; The stack coming into this call is: ; dw bp[20] MACID ; dw bp[18] framesize ; dw bp[16] request handle ; dw bp[14] receive-chain buf descriptor address seg ; dw bp[12] receive-chain buf descriptor address off ; dd bp[8] indicate flag addr ; dw bp[6] DS of called protocol mode (ME) ; ; where receive-chain buffer descriptor format is ; dw rxdatacount count of received data blocks, max of 8 ; dw rxdatalen length of a data block ; dd rxdataptr seg:offset of a data block rcv_chn PROC FAR push bp mov bp,sp push bx ; -2[bp] ; save things push cx ; -4[bp] push dx ; -6[bp] push di ; -8[bp] push ds ; -10[bp] push es ; -12[bp] sub sp,2 ; -14[bp] handle push si mov ax,cs ; setup data segment (== CS) mov ds,ax mov ax,14[bp] ; seg of rcv-chain buffer descriptor mov es,ax mov di,12[bp] ; and its offset les di,es:[di+4] ; es:di is now the buffer pointer call pktfilter ; apply packet filter, return handle jnc chn_get_buf ; nc = we want this packet mov ax,FRAME_NOT_RECOGNIZED ; packet not accepted jmp chn_don ;; Call the Packet Driver receive routine to get its buffer address chn_get_buf: mov cx,18[bp] ; CX = packet length xor ax,ax ; AX = 1st call to receiver mov -14[bp],bx ; remember handle for next call push bp ; We depend on BP call dword ptr cs:[bx].pd_conn_rcvr ; Call the receive routine pop bp ; Restore BP ; Now protocol stack's buffer address is in ES:DI mov ax,es or ax,ax ; Check for non-zero segment jne rcvchn4 ; ne = ok or di,di ; Check for non-zero offset jne rcvchn4 ; ne = ok mov ax,SUCCESS ; No copy, accept pkt anyway jmp chn_don rcvchn4: ;; Get data from NDIS buffer(s) into protocol stack's buffer push ds ; Save to restore after call push es ; Save ES:DI (pointer) to pass push di ; back to receiver later lds si,12[bp] ; Addr of rcv descriptor mov cx,[si] ; Get number of data blocks add si,2 ; & move to top of list chn_dat: ; Move data from next block into stack's buffer push cx push ds push si mov cx,[si] ; Get byte count of block add si,2 lds si,[si] ; Get far pointer to data cld shr cx, 1 jnc rcvchn5 ; nc = even already movsb ; Move 1 byte if count is odd rcvchn5:rep movsw ; Use word mov for efficiency pop si ; Go through rest of chain add si,6 pop ds pop cx loop chn_dat ; For all blocks ; ; Call Packet Driver receive routine again to finish up ; pop si ; DS:SI = buffer pointer pop ds ; that we're completing mov cx,18[bp] ; CX = packet length mov bx,-14[bp] ; BX = handle mov ax,1 ; Indicate 2nd (AX == 1) call call dword ptr cs:[bx].pd_conn_rcvr ; Call receive routine again mov ax,SUCCESS ; We accepted the packet pop ds ; Now we're done with DS chn_don:pop si add sp,2 pop es pop ds pop di pop dx pop cx pop bx pop bp ret 16 ; pop params off stack rcv_chn ENDP ; Worker for lookahead and receive_chain procedures above. Checks PD handles ; for wanting this kind of packet. Returns carry clear and BX = handle ; if packet is wanted, else carry set to reject the packet. Expects MAC layer ; to provide at least our needed number of bytes (14+). ; Destroys AX, CX, DX, SI, preserves DI, ES, sets BX. Expects DS = CS. pktfilter proc near cmp conn_in_use,0 ; any requests active? jnz pktfil1 ; e = no, exit no-match jmp pktfil11 pktfil1:mov dx,di ; es:di is data pointer, save here mov bx,offset handles ; BX = offset of handle table mov cx,PD_MAX_CONNS ; CX = entries in table pktfil2:push cx ; save loop counter cmp [bx].pd_conn_used,0 ; is handle in use? jne pktfil4 jmp pktfil9 ; e = no, do next handle pktfil4:lea si,[bx].pd_conn_type ; TYPE wanted by this handle mov cx,[bx].pd_conn_type_len; number of bytes to match or cx,cx jnz pktfil6 ; nz = do not match all packets pktfil5:jmp pktfil12 ; match all packets pktfil6:mov ax,[bx].pd_conn_rmode ; receive mode cmp ax,6 ; Promiscuous? je pktfil5 ; e = yes, accept packet mov di,dx ; es:di is lookahead data ptr cmp if_class,3 ; Token Ring 802.5 Class 3 interface? jne pktfil7 ; ne = no test byte ptr es:8[di],80h ; routing info present? jz pktfil7 ; z = no push cx mov cl,es:14[di] ; get length of routing info and cx,1fh ; just 5 bits worth add di,cx ; skip over routing info pop cx pktfil7:add di,off ; skip to TYPE field et seq ; do old Novell 802.3 to Type 8137 cmp if_class,1 ; regular Ethernet? jne pktfil8 ; ne = no cmp novell,0 ; doing old Novell conversion? je pktfil8 ; e = no cmp word ptr es:[di+2],0ffffh ; have the bad DSAP/SSAP signature? jne pktfil8 ; ne = no mov ax,es:[di] ; get length/Type field value xchg ah,al ; low endian form cmp ax,1500 ; size is larger than length? jae pktfil8 ; ae = yes, a protocol type mov word ptr es:[di],3781h ; force in Novell Type 8137 ; end of Novell section pktfil8:cld repe cmpsb ; check for matching TYPE je pktfil12 ; e = match ; If Promiscuous mode do manual filter cmp pd_recvall,0 ; doing Promiscuous mode? je pktfil9 ; e = no, next handle mov si,offset address ; our board's Ethernet addr mov cx,ETHERADDR_LEN ; length of an Ethernet address mov di,dx ; lookahead buffer add di,aoff cld ; look at destination address repe cmpsb ; look for our Ethernet address je pktfil12 ; e = matched, accept lookahead cmp ax,2 ; ignore multicast and broadcast? jbe pktfil9 ; be = yes mov di,dx ; recover offset of start of buffer add di,aoff test byte ptr es:[di],80h ; multicast bit set? jnz pktfil12 ; nz = yes, accept lookahead cmp ax,3 ; accepting broadcasts? jb pktfil9 ; b = no mov al,0ffh ; look for broadcast mov cx,ETHERADDR_LEN repe scasb ; scan for all 0xFF's je pktfil12 ; e = matched, a broadcast pktfil9:add bx,size per_handle ; next entry pop cx ; recover loop counter dec cx ; mechanical loop or cx,cx ; end of loop? jz pktfil10 ; z = yes jmp pktfil2 ; try next one pktfil10:mov di,dx ; restore di pktfil11:stc ; carry set = no match found ret pktfil12:pop cx ; clean loop counter from stack mov di,dx ; restore di clc ; carry clear = have match ret pktfilter endp ; ; Services indication complete upcall ; ; Executes interrupt (returned by get_parameters()) to pass control to ; an application which wants to run after the EOI. ; ; NOTE: Interrupt number at label ind_int is over-written if a different ; interrupt is configured in protocols.ini. ; ind_com PROC FAR ; Indication_complete upcall push es push bx xor ax,ax mov es,ax ; Point ES at interrupt segment mov bx,cs:param_int ; Get offset of vector or bx,bx ; Is there one? jz ind_no_int ; z = no, don't do the interrupt shl bx,1 ; Multiply by 4 for memory offset shl bx,1 cmp word ptr es:[bx]+2,0 ; Is there a segment there? jne ind_int ; ne = yes cmp word ptr es:[bx],0 ; Is there an offset there? je ind_no_int ; no, no interrupt ind_int: ; INT 65 overwritten if selected INT 65h ; Pass control to the application ind_no_int: pop bx ; Restore registers pop es mov ax,SUCCESS ret 4 ind_com ENDP ;;;;;;;;;;;;;;;;;;;;;;;;; Packet Driver section regs struc ; stack offsets of incoming regs _ES dw ? _DS dw ? _BP dw ? _DI dw ? _SI dw ? _DX dw ? _CX dw ? _BX dw ? _AX dw ? _IP dw ? _CS dw ? _F dw ? ; flags, Carry flag is bit 0 regs ends bytes struc ; stack offsets of incoming regs dw ? ; es, ds, bp, di, si are 16 bits dw ? dw ? dw ? dw ? _DL db ? _DH db ? _CL db ? _CH db ? _BL db ? _BH db ? _AL db ? _AH db ? bytes ends CY equ 0001h ; to set caller's carry bit ; ; Interrupt handler for the Packet Driver interface (protocol stack downcalls) ; ; NOTE: Leaves interrupts disabled on entry - code in access_type and ; release_type depends on this. send_pkt enables interrupts for MAC. ; PUBLIC pd_isr pd_isr PROC FAR jmp short over ; skip the string (this MUST be a 3 byte jmp) nop ; make three bytes DB "PKT DRVR",0 ; string to identify a packet driver over: push ax push bx push cx push dx push si push di push bp push ds push es cld push cs ;set up ds to this code segment pop ds mov bp,sp ;we use bp to access the original regs and _F[bp],not CY ;start by clearing the carry flag mov _DH[bp],0 ; put no-error code in caller's DH cmp ah,pd_table_size ; AH too large? jae highperf_table ; ae = yes, try next set ; Dispatch on AH using normal table mov bl,ah ; Get function code xor bh,bh ; into a word register shl bx,1 ; index by words jmp pd_table[bx] ; and go highperf_table: sub ah, 10 ; Offset of 1st high-performance function jl pd_none ; l = ah is out of range cmp ah,hp_table_size ; is AH still in range? jae xtend_table ; ae = no, try next set ; Dispatch on AH using high-performance table mov bl,ah ; Get function code xor bh,bh ; into a word register shl bx,1 ; index by words jmp hp_table[bx] ; and go xtend_table: sub ah,10 ; Offset of 1st extended function jl pd_none ; l = AH is not in range cmp ah,ext_table_size ; still in range? jae pd_none ; ae = no ; Dispatch on AH using extended table mov bl,ah ; Get function code xor bh,bh ; into a word register shl bx,1 ; index by words jmp ext_table[bx] ; and go pd_none: mov dh,BAD_COMMAND ; set error code err_ret: mov _DH[bp],dh ; put error code in caller's DH or _F[bp],CY ; set caller's carry flag good_ret: ; good return (carry clear) pop es pop ds pop bp pop di pop si pop dx pop cx pop bx pop ax iret ; ; Checks the handle in BX. If out of range or not valid cleans up the ; stack and jumps directly to err_ret with a BAD_HANDLE error. Assumes ; called with DS pushed and a near call. If handle is good, just returns. ; BX is shifted one bit to the left. ; ; Bounds check on handle chk_hdl PROC NEAR mov bx,_BX[BP] ; Handle cmp bx,offset handles ; start of handles area jb chkhdl1 ; b = out of range cmp bx,offset end_handles ; end of handles area jae chkhdl1 ; ae = above max table size cmp [bx].pd_conn_used,0 ; is handle used? je chkhdl1 ; e = no, go bomb out ret ; return BX as handle chkhdl1: pop ds ;clear stack (was the return address) mov dh,BAD_HANDLE ;return BAD_HANDLE error jmp err_ret chk_hdl ENDP ; The following implement the individual Packet Driver commands, basic ; functions first. ; ; Send a packet. ; send_pkt: mov xmt_cmp,REQUEST_QUEUED ; set up for queued data mov bx,_BX[bp] ; handle mov dx,_DS[bp] ; get ds of data block to dx mov cx,_CX[bp] mov si,_SI[bp] mov ax,drv_cct.mod_id ; put our module id push ax push ds ; request handle - good as any ; do conversion of Type 8137 to old Novell 802.3 cmp if_class,1 ; regular Ethernet? jne send_pkt3 ; ne = no, no conversion cmp novell,0 ; doing Novell packet conversion? je send_pkt3 ; e = no push es mov es,dx ; segment of packet cmp word ptr es:[si+12],3781h ; outgoing Novell Type 8137? jne send_pkt2 ; ne = no mov ax,es:[si+12+4] ; get internal length indicator xchg ah,al inc ax ; round up to an even length and al,not 1 xchg ah,al mov es:[si+12],ax ; change packet Type field to length send_pkt2:pop es ; end of Novell conversion send_pkt3: mov drv_snd.snd_len,cx ; save byte count in descriptor mov drv_snd.snd_off,si ; store offset of pkt buffer mov drv_snd.snd_seg,dx ; store segment of pkt buffer mov bx,offset drv_snd ; get addr of xmit buff desc push ds ; store on stack push bx mov ax,mac_ds ; MACID push ax sti ; enable ints just to be sure call TransmitChain ; do downcall to NDIS xor dx,dx ; clear return code cmp ax,SUCCESS ; done? je send_pkt4 ; e = yes, success cmp ax,REQUEST_QUEUED ; queued? jne send_pkt5 ; ne = no send_pkt4:jmp good_ret ; queued is ok send_pkt5: mov dh,CANT_SEND ; trouble, fail jmp err_ret ; ; Handle driver_info() downcall - return driver information. ; driver_info: mov bx,pd_version ; BX is version mov ch,if_class ; CH is class mov dx,if_type ; DX is type xor cl,cl ; CL is interface number (always 0) mov _BX[bp],bx mov _CX[bp],cx mov _DX[bp],dx mov _SI[bp],offset pd_name ; ds:si is ptr to name mov ax,ds mov _DS[bp],ax mov al,PD_LEVEL ; Level of implementation xor ah,ah mov _AX[bp],ax jmp good_ret ; ; Handle access_type() - sets up to handle an Ethernet packet type. ; ; NOTE: Depends on entry with interrupts disabled for shared data locking. ; access_type_class: mov dh,NO_CLASS jmp err_ret access_type_type: mov dh,NO_TYPE jmp err_ret access_type_number: mov dh,NO_NUMBER jmp err_ret access_type_bad: mov dh,BAD_TYPE jmp err_ret access_type: mov al,if_class cmp _AL[bp],al ; our class? jne access_type_class ; ne = no, fail access_type_1: ; cmp _BX[bp],ANY_TYPE ; generic type? ; je access_type_2 ; e = yes ; mov al,driver_type ; cbw ; cmp _BX[bp],ax ; our type? ; jne access_type_type ; ne = no access_type_2: cmp _DL[bp],0 ; generic number? je access_type_3 ; e = yes cmp _DL[bp],1 ; our number? jne access_type_number ; ne = no access_type_3: cmp _CX[bp],MAX_P_LEN ; is the type length too long? ja access_type_bad ; a = yes, this can't be ours ; now we do two things--look for an open handle, and check the existing ; handles to see if they're replicating a packet type. xor dx,dx ; remember no free handle yet mov bx,offset handles ; first handle cld access_type_4: cmp [bx].pd_conn_used,0 ; is this handle in use? je access_type_5 ; e = no, do not check the type mov al,_AL[bp] ; is this handle the same class as cmp al,[bx].pd_conn_class ; they want? jne short access_type_6 ; ne = no mov es,_DS[bp] ; get a pointer to their type mov di,_SI[bp] ; from their ds:si to our es:di mov cx,_CX[bp] ; get the minimum of their length ; and our length. As currently ; implemented, only one receiver ; gets the packets, so we have to ; ensure that the shortest prefix ; is unique. mov si,[bx].pd_conn_type_len ; length of their Type cmp cx,si ; are we less specific than they are? jb access_type_8 ; b = no mov cx,si ; yes, use their (shorter) length access_type_8: lea si,[bx].pd_conn_type ; their desired Type or cx,cx ; pass-all TYPE? (zero TYPE length) jnz access_type_7 ; nz = no mov bx,offset handles+(PD_MAX_CONNS-1)*(size per_handle) jmp short access_type_5 ; put pass-all last access_type_7: repe cmpsb ; same type? (conflict if so) jne short access_type_6 ; ne = no, go look at the next one access_type_inuse: mov dh,TYPE_INUSE ; a handle has been assigned for TYPE jmp err_ret ; cannot assign a type access_type_5: ; handle is not in use or dx,dx ; found a free handle yet? jne access_type_6 ; ne = yes mov dx,bx ; remember first free handle in dx access_type_6: add bx,(size per_handle) ; go to the next handle cmp bx,offset end_handles ; examined all handles? jb access_type_4 ; b = no, continue mov bx,dx ; did we find a free handle? or bx,bx jz access_type_space ; z = no, return error mov [bx].pd_conn_used,1 ; remember that we're using it mov ax,_DI[bp] ; get receiver address from ES:DI mov word ptr [bx].pd_conn_rcvr,ax ; offset part mov ax,_ES[bp] mov word ptr [bx].pd_conn_rcvr+2,ax ; segment part push ds mov ax,ds mov es,ax mov ds,_DS[bp] ; remember their type mov si,_SI[bp] mov cx,_CX[bp] mov es:[bx].pd_conn_type_len,cx ; remember the TYPE length lea di,[bx].pd_conn_type rep movsb ; copy TYPE field to match pop ds inc conn_in_use ; count handles in use mov al,_AL[bp] ; remember Class mov [bx].pd_conn_class,al mov _AX[bp],bx ; return handle in caller's AX call chk_rmode ; update Promiscous mode status jmp good_ret access_type_space: mov dh,NO_SPACE jmp err_ret ; ; Perform release_type() - forget the packet type/upcall/handle ; ; NOTE: Depends on entry with interrupts disabled for shared data locking. ; release_type: call chk_hdl ; get handle, return here if ok ; This is a critical region!! mov [bx].pd_conn_type,ETHERTYPE_NONE ; Clear connection mov [bx].pd_conn_used,0 ; free handle-used indicator dec conn_in_use ; Count one less handle open call chk_rmode ; update Promiscous mode status jmp good_ret ; ; Perform terminate() - never actually do it. ; terminate: call chk_hdl ; check handle mov dh,CANT_TERMINATE ; Return error jmp err_ret ; ; Perform get_address() - get the current Ethernet address of the interface ; get_address: mov ax,_AX[bp] mov bx,_BX[bp] mov cx,_CX[bp] mov si,_SI[bp] mov di,_DI[bp] mov es,_ES[bp] cld cmp cx,ETHERADDR_LEN ; Make sure it's an ethernet address jne get_address_err ; ne = bad length, fail call get_eaddr ; address to caller's area mov ax,ds mov es,ax mov di,offset address ; where to store Ethernet address call get_eaddr ; get board's Ethernet address jmp good_ret get_address_err: mov dh,NO_SPACE ; hmmm, I suppose it's close enough jmp err_ret ; Return board's current Ethernet address in es:di (ETHERADDR_LEN bytes) ; via NDIS information. get_eaddr proc near push ds push si push cx push es ; preserve destination push di les si,mac_cctp ; get address of mac cct lds si,es:sscp[si] ; get address of mac ssc add si,cur_add ; mov to offset in structure pop di pop es mov cx,ETHERADDR_LEN ; get length cld rep movsb ; copy address pop cx pop si pop ds ret get_eaddr endp ; ; Perform reset_interface() - this is ignored. ; reset_interface: call chk_hdl ; check handle jmp good_ret ; if the handle was good, call is good ; ; The following implement the High Performance functions ; ; get_parameters() - Return pointer to parameters structure in ES:DI ; get_parameters: mov ax,cs mov _ES[bp],ax ; return struct adr in caller's ES:DI mov _DI[bp],offset pd_param jmp good_ret ; & pass it to caller ; ; as_send_pkt() - Not implemented. ; ;as_send_pkt: ; mov dh,BAD_COMMAND ; jmp err_ret ; ; The following implement the Extended functions ; ; set_rcv_mode translates the PDS mode to an NDIS Packet Filter. ; set_rcv_mode: call chk_hdl ; get handle, return here if ok mov ax,_AX[bp] mov cx,_CX[bp] jcxz set_rcv_mode_err ; z = illegal receive mode, quit cmp cx,6 ; is mode legal? ja set_rcv_mode_err ; a = no, quit mov bx,cx ; Put it in an index register mov bl,ndis_mode[bx] ; and translate it for NDIS xor bh,bh cmp bl,4 ; NDIS Promiscuous mode? jb set_rec_mode2 ; b = no push es push di les di,mac_cctp ; check if Promiscuous mode supported les di,es:[di].sscp test es:[di].svc_1,8 ; first 15 service flags, Promis bit jnz set_rec_mode1 ; nz = mode is supported dec bl ; use regular NDIS mode 3 instead set_rec_mode1: pop di pop es set_rec_mode2: call set_ndis_mode ; Try to set it cmp ax,SUCCESS ; did it succeed? je set_rcv_mode_ok ; e = yes, return success set_rcv_mode_err: mov dh,BAD_MODE ; no, return error jmp err_ret set_rcv_mode_ok: mov bx,_BX[bp] ; get handle again mov cs:[bx].pd_conn_rmode,cx ; set receive mode in handle's struct mov cs:pd_rcv_mode,cx ; save the mode we just set call chk_rmode ; check on Promiscous mode jmp good_ret ; and return ok ; Examine all PD handles and set global variable pd_recvall to 0 if no handle ; is doing Promiscuous mode receives, else non-zero. chk_rmode proc near push bx push cx push ds mov cx,cs mov ds,cx mov bx,offset handles ; BX = offset of handle table mov cx,PD_MAX_CONNS ; CX = entries in table mov pd_recvall,0 ; assume no Promiscous mode active chk_rmode1: cmp [bx].pd_conn_used,0 ; is handle in use? je chk_rmode2 ; e = no, do next handle cmp [bx].pd_conn_rmode,6 ; Promiscuous mode active here? jne chk_rmode2 ; ne = no mov pd_recvall,1 ; say Promiscous mode is active jmp short chk_rmode3 chk_rmode2: loop chk_rmode1 chk_rmode3: pop ds pop cx pop bx ret chk_rmode endp ; ; Return the current Packet Driver receive mode. ; get_rcv_mode: call chk_hdl ; get handle, return here if ok mov ax,[bx].pd_conn_rmode ; get mode for this handle mov _AX[bp],ax jmp good_ret ; return it get_statistics: les si,mac_cctp ; ES:SI == address of NDIS cct les si,es:sssp[si] ; ES:SI == address of NDIS sss mov ax,es or ax,ax ; Is the segment non-zero? jnz getsta1 ; nz = yes, accept it or si,si ; how about offset? jnz getsta1 ; nz = ok mov DH,BAD_COMMAND ; If they don't implement it, jmp err_ret ; neither do we getsta1:mov ax,cs mov ds,ax mov di,offset pd_stat ; Get start of PD stats table cli ; Don't allow updates just now mov ax,WORD PTR es:r_tot[si] ; Copy total received frames mov dx,WORD PTR es:r_tot+2[si] call valchk mov ax, WORD PTR es:x_tot[si] ; Copy total xmitted frames mov dx, WORD PTR es:x_tot+2[si] call valchk mov ax, WORD PTR es:rb_tot[si] ; Copy total received bytes mov dx, WORD PTR es:rb_tot+2[si] call valchk mov ax, WORD PTR es:xb_tot[si] ; Copy total transmitted bytes mov dx, WORD PTR es:xb_tot+2[si] call valchk mov ax, WORD PTR es:r_err[si] ; Copy total receive errors mov dx, WORD PTR es:r_err+2[si] call valchk mov ax, WORD PTR es:x_hwer[si] ; Copy total transmit errors mov dx, WORD PTR es:x_hwer+2[si] call valchk mov ax, WORD PTR es:r_drop[si] ; Copy total receives dropped mov dx, WORD PTR es:r_drop+2[si] call valchk sti ; All done with shared data mov _SI[bp],OFFSET pd_stat ; set caller's DS:SI to the mov ax,cs ; address of Packet Driver stats mov _DS[bp],ax jmp good_ret ; Convert double word dx:ax from NDIS unknown value of (long) -1 to (long) 0, ; store results in ds:[di, di+2], move di forward two words. valchk proc near cmp ax,-1 ; starting at -1 (NDIS, for unknown)? jne valchkx ; ne = no cmp dx,-1 ; this part too jne valchkx ; ne = no xor ax,ax ; zero counters for zero based counts xor dx,dx valchkx:mov [di],ax ; store results locally mov [di+2],dx add di,4 ; step to next storage double word ret valchk endp ; ; Perform set_address() - change physical address of the interface. ; ; The problem with this is that some NDIS drivers may just accept the ; SetStationAddress call, but others may require a CloseAdapter/OpenAdapter ; to bracket it. This latter doesn't seem worth the effort at the moment. ; set_address: IFDEF DO_SET_ADDRESS mov bx,_BX[bp] ; Get handle (not checked) mov cx,_CX[bp] cmp cx,ETHERADDR_LEN ; Make sure it's an ethernet address jne set_address_err ; Jump if bad length cmp conn_in_use,1 ; How many handles are open? jbe set_allowed ; be = 1 or none, ok set_err: mov dh,CANT_SET ; Too many - don't allow it jmp err_ret set_allowed: mov ax, cs:drv_cct.mod_id ; Make set station address call push ax ; Module ID of protocol inc ax push ax ; Push request ID (0 to not conf) xor bx,bx push bx ; Must be 0 push es ; Push pointer to address to set push di push SET_STA_ADDR ; SetStationAddress function code les bx,mac_cctp mov ax,es:[bx].mod_ds push ax mov cs:req_con_flg,REQUEST_QUEUED call cs:Request ; Make call to NDIS mov cs:req_con_flg,ax sti ; Wait for request to complete setall1: cmp ax,SUCCESS ; success? je setall2 ; e = yes cmp ax,REQUEST_QUEUED ; Is it queued? jne set_err ; ne = no, quit with CANT_SET mov ax,cs:req_con_flg ; get current status jmp short setall1 ; keep polling setall2:jmp good_ret set_address_err: mov dh, BAD_ADDRESS ; We didn't like the address jmp err_ret ELSE mov dh, CANT_SET ; Built this way, we can't set address jmp err_ret ENDIF pd_isr ENDP ;;;;;; end of Packet Driver direct support procedures ; ; The following are upcalls from DIS: ; RequestConfirm enters with stack of (after our push bp) ; dw [BP+16] ProtID ; dw [BP+14] MACID ; dw [BP+12] ReqHandle ; dw [BP+10] Status ; dw [BP+8] Request ; dw [BP+6] ProtDS (our DS) req_con PROC FAR ; Request Confirm push bp mov bp,sp mov ax,[bp+10] ; get NDIS status response mov cs:req_con_flg,ax ; store in local area mov ax,SUCCESS ; return our feelings on the matter pop bp ret 12 req_con ENDP ; TransmitConfirm enters with stack of (after our push bp) ; dw [BP+14] ProtID ; dw [BP+12] MACID ; dw [BP+10] ReqHandle ; dw [BP+8] Status ; dw [BP+6] ProtDS (our DS) xmt_con PROC FAR ; Transmit Confirm push bp mov bp,sp mov ax,8[bp] mov cs:xmt_cmp,ax ; moves the return code into static mov ax,SUCCESS pop bp ret 10 xmt_con ENDP sta_ind PROC FAR ; Status handled, not used mov ax,SUCCESS ret 12 sta_ind ENDP dis_pat PROC FAR ; System entry point for pkt driver push bp ; Used only by initiate bind request mov bp,sp mov ax,8[bp] ; Check opcode cmp ax,1 ; Is it initiate_bind? je dispat1 ; e = yes mov ax,GENERAL_FAILURE ; NO: fail pop bp ret 14 dispat1:push ds ; save stuff push es push bx push cx push si push di mov ax,cs ; set up DS == CS mov ds,ax mov bx,offset mac_cctp ; Save addr of MAC's cct mov ax,12[bp] mov [bx],ax mov ax,14[bp] mov 2[bx], ax mov ax,offset drv_cct ; push pkt drv cct (our cct) push ds push ax mov ax,offset mac_cctp ; push addr for MAC's cct push ds push ax xor ax,ax ; pad parameter push ax mov ax,2 ; Load Bind command code push ax les bx,mac_cctp ; load address of MAC's cct mov ax,es:[bx].mod_ds push ax ; push MAC's ds call dword ptr es:[bx].system ; call MAC's system entry point mov rtn_cod,ax ; remember return status or ax,ax jz dispat2 ; z = Bind succeeded MSG bad_bind ; tell the user the bad news jmp rtn_dis ; Bind failed, fatal error dispat2: call sav_mac ; Save MAC entry point addresses les bx,mac_cctp ; Check if OpenAdapter needed les bx,es:[bx].sscp lea di,[bx].mtype ; MAC type, asciiz mov si,offset t8023 ; try 802.3 mov cx,t8023len cld repe cmpsb je is8023 ; e = matched lea di,[bx].mtype mov si,offset t8025 ; try 802.5 (Token Ring) mov cx,t8025len repe cmpsb je is8025 ; e = matched jmp short gottype is8023: mov if_class,11 ; 802.3 with 802.2 (SNAP) headers mov off,14 ; 6 MAC + 6 MAC + 2 LEN jmp short gottype is8025: mov if_class,3 ; Token Ring 802.5 mov off,14 mov aoff,2 mov ax,es:[bx].maxfram mov mtu,ax ; jmp short gottype gottype:mov ax,es:[bx].svc_1 test ax,0800h ; OpenAdapter supported? jnz dispat3 ; nz = yes, go do it jmp open_ok1 ; skip to setting packet filter dispat3: ; Make OpenAdapter call to NDIS mov ax,cs push ax ; module ID of protocol push ax ; unique handle (0 to not conf) ifdef ALLFRAMES mov ax, 6 push ax endif xor ax,ax ifndef ALLFRAMES push ax ; dw pad endif push ax ; dd pad push ax mov ax,OPEN_ADAPTER ; OpenAdapter command code push ax les bx,mac_cctp mov ax,es:[bx].mod_ds push ax mov cs:req_con_flg,REQUEST_QUEUED call cs:Request ; Make call to NDIS via indirect ptr mov cs:req_con_flg,ax ; Save immediate return code dispat4:sti ; Needed because of bugs in some MACs cmp ax,SUCCESS jz open_ok1 cmp ax,NOT_SUPPORTED jz open_ok1 cmp ax,REQUEST_QUEUED ; Was it queued? jne dispat5 ; NO: bomb mov ax,cs:req_con_flg jmp short dispat4 ; keep polling dispat5:MSG bad_open_adpt ; Fatal error: open adapter failed jmp rtn_dis open_ok1: mov ax,cs ; Temp fix for Apricot (may not mov ds,ax ; be needed anymore) mov ax,mac_ds push ax call IndicationOff mov ax,mac_ds push ax call IndicationOn sti ; Who disabled? MAC bug probably mov bx,3 ; Set default filter: Directed, call set_ndis_mode ; Multicast & Broadcast (3) cmp ax,SUCCESS ; Did it work? je set_vec ; e = yes, go on to vector MSG bad_set_pkt ; show an error and fail jmp rtn_dis ; Give warning if the Packet Driver vector is already in use but use anyway set_vec: xor ax,ax ; Set ES to 0 to look in int tab mov es,ax mov bx,cs:pd_vector ; Get vector and multiply by 4 shl bx,1 shl bx,1 mov ax,es:[bx] or ax,ax ; Is segment zero? jnz vin_use2 ; nz = yes, print warning mov ax,es:2[bx] or ax,ax ; Is offset zero? jz dispat6 ; z = no, don't print warning vin_use2: MSG vec_in_use ; Print a warning dispat6: mov ax,offset pd_isr ; move packet driver isr addr into mov es:[bx],ax ; interrupt vector table mov ax,cs mov es:2[bx],ax xor ax,ax rtn_dis: pop di ; all done pop si pop cx pop bx pop es pop ds pop bp ret 14 dis_pat ENDP ; Make the NDIS SetPktFilter call (both at bind and from set_rcv_mode) ; ; Arguments: ; BX NDIS Packet filter to set (see DIS p 45 for bits) ; * 0 - directed and multicast ; * 1 - broadcast ; 2 - promiscuous ; 3 - any source routing packet ; set_ndis_mode PROC NEAR push es ; Save ES & BX registers push bx mov ax,cs:drv_cct.mod_id ; make set packet filter call push ax ; module ID of protocol inc ax push ax ; unique handle (0 to not conf) push bx ; Push packet filter value xor ax,ax push ax ; dd pad push ax mov ax,SET_PKT_FLT ; SetPacketFilter command push ax les bx,mac_cctp mov ax,es:[bx].mod_ds push ax mov cs:req_con_flg,REQUEST_QUEUED call cs:Request ; Make call to NDIS mov cs:open_adap,ax sti ; Wait for request to complete setndmode1: cmp ax,SUCCESS ; done? jz setndmode2 ; z = yes, success cmp ax,REQUEST_QUEUED ; Is it queued? jne setndmode2 ; ne = no, fail mov ax,cs:req_con_flg ; get current status jmp setndmode1 ; keep polling setndmode2: pop bx pop es ret ; NDIS return code is in AX set_ndis_mode ENDP ; ; Put MAC entry points into static locations - called at bind time. ; sav_mac PROC NEAR push ax les si,mac_cctp mov ax,es:[si].mod_ds ; save MAC ds mov mac_ds, ax les si,es:[si].udtp mov bx,offset Request ; save request entry point mov ax, es:4[si] mov [bx],ax mov ax,es:6[si] mov 2[bx], ax mov bx,offset TransmitChain ; save xmt block entry point mov ax,es:8[si] mov [bx],ax mov ax,es:10[si] mov 2[bx],ax mov bx,offset TransferData ; save xfer data entry point mov ax,es:12[si] mov [bx],ax mov ax,es:14[si] mov 2[bx],ax mov bx,offset ReceiveRelease ; save recv rel entry point mov ax,es:16[si] mov [bx],ax mov ax,es:18[si] mov 2[bx],ax mov bx,offset IndicationOn ; save ind on entry point mov ax,es:20[si] mov [bx],ax mov ax,es:22[si] mov 2[bx],ax mov bx,offset IndicationOff ; save ind off entry point mov ax,es:24[si] mov [bx],ax mov ax,es:26[si] mov 2[bx],ax pop ax ret sav_mac ENDP ; Message strings needed at bind time. bad_open_adpt db "Adapter did not open", EOL bad_set_pkt db "Set packet filter failed", EOL vec_in_use db "Vector already in use", EOL bad_bind db 7,"BIND failed",EOL t8023 db '802.3',0 t8023len equ $-t8023 t8025 db '802.5',0 t8025len equ $-t8025 end_res: ;;;; Currently not keeping init code in memory ; ; DOS device driver interrupt entry point. ; ; This is used to initialize module and read parameters from PROTOCOLS.INI ; only, and frees itself after startup. The NDIS bind takes place later, ; via dis_pat and its friends above. ; intr PROC FAR push es ; save all registers push ds push si push di push dx push cx push bx push ax mov ax,cs ; check to see if already initialized mov ds,ax mov al,init_flg ; our init flag or al,al ; not inited yet (0)? jz intr1 ; z = yes, init now mov bx,req_off ; already initialized - return mov ds,req_seg ; with error mov [bx].status, 810Ch jmp rtn intr1: cli ; not initialized - switch to new mov si,SS ; stack and init mov dx,SP mov ax,CS mov SS,ax mov SP,OFFSET new_stk ; Need a big stack for this call STI ; Critical region PUSH SI ; Save old SS PUSH DX ; and SP MSG msg_copyright ; Display copyright notice call init ; Init this driver mov ax,cs ; Set DS == CS mov ds,ax mov bx,req_off ; Get request header ptr mov es,req_seg mov word ptr es:[bx].status,0100h ; Set return status ok mov init_flg,1 ; Note that we've initialized mov ax,offset end_res ; Set end of resident code mov word ptr es:[bx].end_off,ax mov ax,cs mov es:[bx].end_seg,ax POP DI ; Old SP POP SI ; and old SS CLI ; Critical region mov SS, SI ; Change back to old stack mov SP, DI STI ; End critical region rtn: pop ax ; All done pop bx pop cx pop dx pop di pop si pop ds pop es ret intr ENDP db 512 dup (0) new_stk label word ; A stack for init to use db 4 dup (0) fil_han dw 0 ; File handle for init ; ; Initialize the converter module - read parameters from PROTOCOLS.INI. ; init PROC NEAR mov ax,cs ; open the Protocol Manager driver mov ds,ax mov ah,fopen ; open file mov al,0C2h mov dx,offset pm__nam ; device name int dos jnc init1 ; nc = success MSG pro_no_open ; error jmp init_err init1: mov fil_han,ax ; file handle mov bx, ax mov ax, cs mov ds, ax mov drv_req.req_opc,1 ; make GetProtocolManagerInfo call mov drv_req.req_sta,-1 ; zero out return status mov drv_req.req_of1,-1 ; NULL out pointers mov drv_req.req_sg1,-1 mov drv_req.req_of2,-1 ; NULL out pointer 2 mov drv_req.req_sg2,-1 mov drv_req.req_prm,-1 ; zero out parameter word mov ah,ioctl ; IOCTL req mov al,02h ; device input mov dx,offset drv_req ; pointer to buffer mov cx,14 ; size of buffer int dos ; call DOS jnc init2 ; nc = success MSG pro_bad_gpm ; Error: print msg & bomb jmp init_err init2: mov ax, cs ; restore ds mov ds, ax mov ax,offset pro_nam ; Get name of module to bind to, push ax ; returned by get_pro in ES:DI mov ax,pro_nam_len push ax mov ax,offset pro_bnd_to push ax mov ax,pro_bnd_to_len push ax xor ax,ax push ax call get_pro ; Try to find the token we want or di,di ; Was it there? jnz init4 ; nz = yes, parse it mov drv_bnd.bnd_cnt,0 ; else say nothing bound jmp short init45 init4: push ds ; Save name in bindings structure push ds ; currently allowed to bind to only push es ; one MAC pop ds pop es mov si,di mov di,offset drv_bnd.bnd_nam mov cx,-2[si] cld rep movsb pop ds init45: mov ax,offset pro_nam ; Get Packet Driver vector to use push ax mov ax,pro_nam_len push ax mov ax,offset pro_prm_vec ; "INTVEC" keyword push ax mov ax,pro_prm_vec_len push ax xor ax,ax push ax call get_pro ; Go look for the token or di,di ; Was the token found? jnz init5 ; nz = yes MSG vec_not_spc ; abort if not found jmp init_err init5: mov dx,es:[di] ; check that vector is in range cmp dx,80h ; 0x80 is high limit jge bad_vec2 cmp dx,60h ; 0x60 is low limit jl bad_vec2 mov pd_vector,dx ; Save value for bind time jmp short init6 ; Go on to EOI interrupt bad_vec2: MSG msg_bad_vec ; Abort if out of range jmp init_err init6: mov ax,offset pro_nam ; Get EOI interrupt (if any) push ax mov ax,pro_nam_len push ax mov ax,offset pro_daisy_vec ; "CHAINVEC" key word push ax mov ax,pro_daisy_len push ax xor ax,ax push ax call get_pro ; Try to find the token or di,di jz init7 ; z = no interrupt mov dx,es:[di] ; Check that interrupt is ok cmp dx,80h ; High limit is 0x80 jae bad_vec3 ; ae = above high limit cmp dx,60h ; Low limit is 0x60 jb bad_vec3 ; b = below lower limit mov byte ptr ind_int+1,dl ; Modify the code mov param_int, dx ; Save interrupt number jmp short init7 ; Go do the RegisterModule bad_vec3: MSG msg_bad_vec jmp init_err ; Abort installation init7: mov ax,offset pro_nam ; Get old Novell 802.3 keyword push ax mov ax,pro_nam_len push ax mov ax,offset pro_novell ; "NOVELL" key word push ax mov ax,pro_nov_len push ax xor ax,ax push ax mov novell,0 ; assume no token call get_pro ; Try to find the token or di,di jz init8 ; z = no token mov dx,es:[di] ; get the token's value and dl,not 20h ; to upper case cmp dl,'Y' ; "yes"? jne init8 ; ne = no conversion mov novell,1 ; set flag MSG novmsg ; tell the user about conversion init8: call pkt_ptr ; Initialize the LDT and CCT pointers mov ax,cs mov ds,ax mov drv_req.req_opc,2 ; RegisterModule call mov drv_req.req_sta,0 ; zero out return status mov drv_req.req_of1,offset drv_cct ; cct pointer mov drv_req.req_sg1,ax mov drv_req.req_of2,offset drv_bnd mov drv_req.req_sg2,ax mov drv_req.req_prm,0 ; zero out parameter word mov ah,ioctl ; IOCTL call mov al,2 mov dx,offset drv_req mov cx,14 mov bx,fil_han int dos mov ax,drv_req.req_sta ; check return status cmp ax,SUCCESS je init9 ; e = success mov cs:rtn_cod,ax ; abort if reg mod failed MSG reg_mod_nok jmp init_err init9: mov bx,fil_han ; Close protman device mov ah,fclose int dos jc init10 ; c = failure xor ax,ax ; Indicate success ret ; & do normal return init10: MSG msg_err_clo ; close failed, quite unlikely jmp init_err init_err:mov ax,1 ; error return ret init ENDP ; get_pro returns a pointer to the keyword entry from GPMI call ; 12[bp] is a pointer to module name ; 10[bp] is length of module name ; 8[bp] is a pointer to keyword name ; 6[bp] is length of keyword name ; 4[bp] is number of parameter wanted from specified keyword ; ; returns ; es:bx is pointer to param ; ax zero for ok and !0 for not found ; get_pro PROC NEAR push bp mov bp,sp push ds push bx push si lds bx,dword ptr drv_req.req_of1 ; ConMemIma pointer mov ax,cs ; find module name mov es,ax getpro1:mov ax,ds ; quit if pointer NULL (eol) or ax,ax jz err_get_pro ; z = error mov di,12[bp] ; module name mov si,bx ; set up to point name add si,8 mov cx,10[bp] ; module name length cld repe cmpsb ; right module name? je pro_fnd ; e = module name found lds bx,dword ptr [bx] ; not found-load next in chain jmp short getpro1 pro_fnd: add bx,24 ; offset of parameter pointers getpro2: mov ax,ds or ax,ax jz err_get_pro mov di,8[bp] ; parameter name mov cx,6[bp] ; parameter name length mov si,bx add si,8 cld repe cmpsb je key_fnd ; e = parameter found lds bx,dword ptr [bx] ; not found-load next in chain jmp short getpro2 key_fnd: add bx,24 ; offset of values mov cx,4[bp] ; check if enough values are cmp cx,[bx] ; here jge err_get_pro add bx,2 ; position to the value jcxz prm_fnd ; may be either char string getpro3: ; or number depending on type add bx,2 add bx,[bx] add bx,2 loop getpro3 prm_fnd: mov si,bx ; set es:di to point to value add si,4 mov cx,2[bx] mov ax,ds mov es,ax mov di,si jmp short getpro4 err_get_pro: ; MSG pro_not_fnd ; error return xor ax,ax mov es,ax mov di,ax getpro4: pop si ; common return pop bx pop ds pop bp ret 10 get_pro ENDP pkt_ptr PROC NEAR ; Set up pointers in Packet mov ax,cs ; Driver ldt and cct mov ds,ax ; Note:most of the could mov bx,offset drv_ldt ; (should) be done statically mov word ptr [bx],offset drv_cct ; driver's cct back pointer mov 2[bx], ax add bx,8 ; skip int flgs mov [bx],offset req_con ; RequestConfirm address mov 2[bx],ax mov 4[bx],offset xmt_con ; TransmitConfirm address mov 6[bx],ax mov 8[bx],offset rcv_lah ; ReceiveLookahead indication mov 10[bx],ax mov 12[bx],offset ind_com ; IndicationComplete address mov 14[bx],ax mov 16[bx],offset rcv_chn ; ReceiveChain indication add mov 18[bx],ax mov 20[bx],offset sta_ind ; status indication address mov 22[bx],ax mov bx,offset drv_cct.ldtp ; set up point to drv ldt mov word ptr [bx],offset drv_ldt mov 2[bx],ax ; ;set up pointers in pkt driver cct ; only doing lower dispatch table, all other left NULL ; hopefully this will work ; mov drv_cct.mod_id,-1 mov drv_cct.mod_ds,ax mov bx,offset drv_cct.system mov [bx],offset dis_pat ; drv system func entry point mov 2[bx],ax ; drv ds mov word ptr 16[bx],offset drv_ldt ; ptr to ldt mov 18[bx],ax ret pkt_ptr ENDP ; Text messages that can be flushed after startup but before bind. msg_no_vect db "Vector not specified", EOL msg_bad_vec db "Invalid vector (must be 60h-7Fh)",EOL msg_err_clo db "Error closing MAC driver", EOL msg_copyright db "MAC/DIS to Packet Driver converter loaded." db " Version 1.09",CR,LF db "Copyright 1991 FTP Software, Inc. All rights " db "reserved.", cr,lf db " v1.07 by Joe R. Doupnik, jrd@cc.usu.edu, " db "Utah State Univ, 18 May 1991", cr,lf db " v1.08 by Dan Lanciani, ddl@harvard.harvard.edu",cr,lf db " v1.09 by Joe R. Doupnik, jrd@cc.usu.edu, " db "Utah State Univ, 3 Nov 1991",EOL pm__nam db "protman$", 0 pro_no_open db "Protocol Manager not present", EOL pro_bad_gpm db "GetProtocolManagerInfo call failed", EOL pro_nam db "PKTDRV",0 pro_nam_len equ $ - pro_nam pro_prm_vec db "INTVEC",0 pro_prm_vec_len equ $ - pro_prm_vec pro_daisy_vec db "CHAINVEC",0 pro_daisy_len equ $ - pro_daisy_vec pro_prm_nok db "SINTVECXX",0 pro_prm_nok_len equ $ - pro_prm_nok pro_bnd_to db "BINDINGS",0 pro_bnd_to_len equ $ - pro_bnd_to pro_novell db "NOVELL",0 pro_nov_len equ $ - pro_novell novmsg db "Using OLD NOVELL 802.3 packets on the wire",EOL vec_not_spc db "Interrupt vector for Packet Driver not specifed" db " in PROTOCOL.INI", EOL reg_mod_nok db "Register module call failed", EOL CSEG ends end