home *** CD-ROM | disk | FTP | other *** search
- ;*****************************************************************************;
- ;* *;
- ;* File: IBMTOKEN.ASM *;
- ;* Auth: Brian Fisher *;
- ;* Queens University *;
- ;* Computing and Communications Services *;
- ;* Rm 2-50 Dupuis Hall *;
- ;* Kingston Ontario *;
- ;* *;
- ;* Date: September 3 1989 *;
- ;* *;
- ;* Purp: Ethernet (3C501) packet driver for IBM Token Ring. This *;
- ;* driver uses the IBM LAN support program DIR interface. *;
- ;* The current implementation supports IP and ARP. *;
- ;* *;
- ;* (C) 1989 Queens University *;
- ;* Computing and Communications Services. This portion of *;
- ;* the program remains the property of Queens University. *;
- ;* *;
- ;*===========================================================================*;
- ;* Program Logic: *;
- ;* *;
- ;* IBMTOKEN extracts IP and ARP data from ethernet datagrams passed to *;
- ;* it by the ULP, makes any adjustments required, then builds a token *;
- ;* ring datagram and sends it out over the network. The process is *;
- ;* reversed when packets are received. IBMTOKEN supports token ring *;
- ;* source routing and functions in a bridged environment. *;
- ;* *;
- ;* The ULP uses Ethernet 'Blue Book' encapsulation. IBMTOKEN uses *;
- ;* 802.2 LLC format for transmission on token ring. The IBM (tm) *;
- ;* LAN Support Program is required. IBMTOKEN uses the DIR interface *;
- ;* to send/receive packets on token ring. *;
- ;* *;
- ;* IP packets do not require any modifications, and are sent 'as is.' *;
- ;* ARP packets have an 'hwr' field that must be changed fro 1h to 6h *;
- ;* during send_pkt, and changed back to 1h from 6h during _receive. *;
- ;* *;
- ;* The minimum size of an ethernet packet is 60 bytes (minus the 4 byte *;
- ;* ethernet checksum). Token ring has no lower limit. The ULP will *;
- ;* reject 'short' packets, so IBMTOKEN lies and tells it there are 60 *;
- ;* bytes. *;
- ;* *;
- ;* ARP packets are 28 bytes in length. The ULP rounds the size of a *;
- ;* packet up to 60 bytes, so there is extra data on the end of the ARP *;
- ;* packet. IBMTOKEN trims this off, because token ring hosts reject *;
- ;* 'too long' ARP packets. *;
- ;* *;
- ;* The minimum size of an ethernet packet is 60 bytes. The maximum *;
- ;* is 1514 bytes. The buffer sizes for token ring send/receive are *;
- ;* set to accomodate this. *;
- ;* *;
- ;* Source Routing: *;
- ;* *;
- ;* The ethernet entrenched logic of the ULP does not accomodate source *;
- ;* routing. IBMTOKEN provides a mechanism for source routing that is *;
- ;* transparent to the ULP. The RIF information associated with token *;
- ;* ring source addresses are placed in a cache. When the ULP sends to *;
- ;* that address, the RIF information is extracted from the cache and *;
- ;* used to route the packet to the target host. *;
- ;* *;
- ;* RIF Cache Logic: *;
- ;* *;
- ;* The cache logic uses an LRU algorithm. Each entry is time *;
- ;* stamped. If all the slots in the cache are being used, the oldest *;
- ;* entry (assumed to be the LRU) is replaced (bumped from the cache). *;
- ;* *;
- ;* If the ULP uses an address whose RIF has been bumped from the *;
- ;* cache, a mechanism exists to rediscover the source route. *;
- ;* IBMTOKEN attaches a phony RIF, with the broadcast bit set and *;
- ;* and empty route table. This packet travels to all rings. When *;
- ;* the foreign host responds, the RIF info is placed back in the *;
- ;* cache. Subsequent transmissions will use the rediscovered RIF. *;
- ;* *;
- ;* The size of the RIF cache should be set to handle the maximum *;
- ;* number of concurrent hosts. This will minimize the bumping *;
- ;* effect and minimize all rings broadcasts. *;
- ;* *;
- ;* I chose this algorithm so the ULP would not require any special *;
- ;* coding to work. It eliminates the need for special syncronization *;
- ;* of the ARP and RIF cache's. *;
- ;* *;
- ;*===========================================================================*;
- ;* *;
- ;* Revs: Sep 29 1989 Successful tests with TN3270, FTP, and FTPBIN.*;
- ;* B. Fisher Some fine tuning required. *;
- ;* *;
- ;* Oct 1 1989 Cleaning up code. Found bug that prevented *;
- ;* buffer1/buffer2..n copies from working. *;
- ;* *;
- ;* Oct 15 1989 Rearranged buffer sizes to accomodate Adapt I *;
- ;* *;
- ;* Nov 15 1989 Added missing popf at end of recv_complt *;
- ;* Fixed missing popf at end of recv_complt *;
- ;* *;
- ;* Nov 19 1989 Added marker to show interrupt activity *;
- ;* for debugging. *;
- ;* *;
- ;* Nov 20 1989 Add changes for Release 5 compatibility *;
- ;* *;
- ;* Nov 21 1989 Fix es/bx reversal at get_size *;
- ;* *;
- ;* Nov 22 1989 RIF not working because of confusion with *;
- ;* SA bit acquired via ARP and SA bit acquired *;
- ;* through Token Receive. Send_Pkt now looks *;
- ;* up all dest addresses in RIF table. *;
- ;* *;
- ;* Nov 23 1989 Have DEBUG mode report RIF table address when *;
- ;* get_multicast_ call made. *;
- ;* *;
- ;* Nov 28 1989 Add phony RIF to 'local' addresses so the *;
- ;* bridge will pass them on. ARP acquired HW *;
- ;* addresses need RIF to cross bridge. This is *;
- ;* done in send_pkt. *;
- ;* *;
- ;* Nov 29 1989 Fixed REPT macro in SA_blk so size of SA info *;
- ;* is correct. Didn't hurt function, however. *;
- ;* *;
- ;* Nov 29 1989 Clear broadcast bit in RIF before entry in *;
- ;* table. This prevents bridges from altering *;
- ;* existing route. FF,FF,FF,FF,FF,FF address *;
- ;* uses broadcast bit so ARP will work. *;
- ;* *;
- ;* Nov 29 1989 Predefined broadcast RIF entry direction bit *;
- ;* polarity reversal prevented broadcast from *;
- ;* going over the bridge. *;
- ;* *;
- ;* Version 1.A - Production Version released at Queens *;
- ;* *;
- ;* Jan 02 1990 Fix missing CLD in _receiver, shows up when *;
- ;* TOKREUI is used instead of Lan Support Pgm... *;
- ;* *;
- ;* Version 1.B *;
- ;* Jan 15 1990 Begin modifications for LRU algorithm in the *;
- ;* (alpha 0) RIF cache. 3rd parm on cmd line sets number *;
- ;* of entries in the cache, which is allocated *;
- ;* using INT 21, Function 48h. The cache *;
- ;* routines are modified to handle the new addr *;
- ;* mode for accessing the table. *;
- ;* *;
- ;* Jan 16 1990 Adding time mark info to SA_table structure. *;
- ;* (alpha 1) add_entry initializes t_mark *;
- ;* loc_entry refreshes t_mark when match found *;
- ;* add_entry uses LRU slot in table when slots *;
- ;* are all in use. *;
- ;* *;
- ;* Jan 18 1990 Updated the program documentation to reflect *;
- ;* the operation of the RIF cache. *;
- ;* *;
- ;* Version 1.C Add code for compatibility with Release 6 of *;
- ;* Mar 18 1990 Clarkson drivers, including TERMINATE call. *;
- ;* *;
- ;* Version 1.D Fix bug that prevents get_address from *;
- ;* returning adapter 1's hardware address. *;
- ;* *;
- ;* *;
- ;* Version 1.E Modified to coexist with other LAN software *;
- ;* 25.06.1991 (MS LAN Manager, IBM LAN Support ....) by *;
- ;* Antero Koskinen, Nokia Data Systems Oy, *;
- ;* Finland (anterok@xerver.icl.fi) *;
- ;*****************************************************************************;
-
- version equ 16h ; Version E = 15h
-
- include defs.asm
-
- debug = 0 ; set 1 for IRM marks on RX
-
- alpha = 0 ; ALPHA Test Version = 0
- alpha_ver = 1 ; Which ALPHA Version...
-
- hrs24 = 1573040 ; ticks in 24 hour day
-
- toke_vect = 5Ch ; LAN Support Pgm Vector
- toke_wait = 0FFh ; completion code wait status
- pool_size = 512 ; 8K space for buffer pool area
-
- num_rcv_buff = 2 ; <2 defaults to 8
- recv_size = 1536 ; max size of card recieve buffer
- tran_size = 1536 ; max size of transmit buffer
-
- STATION_ID = 0 ; ; talk using direct station
-
- RECV_OPTIONS = 0C0h ; contiguous mac/data in bufs
-
- open_cmd = 3h ; LAN Support OpCodes
- interrupt_cmd = 0h
- initialize_cmd = 20h
- close_cmd = 4h
- modify_cmd = 1h
- restore_cmd = 2h
- trans_dir_cmd = 0Ah
- free_ccb_cmd = 27h
- recv_can_cmd = 29h
- open_recv_cmd = 28h
- get_status_cmd = 21h
-
- SA_table_size = 32 ; default size of the RIF cache
- SA_min_size = 2 ; minimum size
- SA_max_size = 1024 ; maximum size
-
- LLC_AC = 10h ; access control LLC
- LLC_FC = 40h ; frame control LLC
- LLC_SSAP_DSAP = 0AAAAh ; reversed for network <grin>
- LLC_CON = 03h
-
- MAC_hdr_size = 22 ; MAC+LLC+SNAP header length
-
- not_SA_mask = 7Fh
- SA_mask = 80h
- RIF_size_mask = 1Fh
- RIF_dir_bit = 80h
-
- broadcast_byte = 0FFh ; broadcast is FF,FF,FF,FF,FF,FF
-
- ARP_type = 0608h ; reversed for network order
- ARP_Eth_hwr = 0100h ; reversed for network order
- ARP_Tok_hwr = 0600h ; reversed for network order
- ARP_packet_size= 28 ; fixes Ethernet assumption...
- phony_RIF = 2082h ; used for bridges...
-
-
-
- LLC_info_size = 8 ; LLC (3) + SNAP(5) = 8
-
- ;-> the assigned Ethernet address of the card.
- extrn rom_address: byte
-
- ;-> current address
- extrn my_address: byte
-
- mark = 0F90h ; marker debug pos on screen 25
-
- marker macro st,nd
-
- IF debug NE 0 ; do marker if debug <> 0
-
- pushf ; show 2 char marker on
- push es ; 25th line, 1st column
- push ax
- mov ax,0B800h
- mov es,ax
- mov al,'&st&'
- mov byte ptr es:[mark],al
- mov al,byte ptr es:[mark+1] ; get color value
- inc al
- and al,0Fh
- or al,1
- mov byte ptr es:[mark+1],al ; advance it to show activity
- mov al,'&nd'
- mov byte ptr es:[mark+2],al
- mov al,byte ptr es:[mark+3]
- inc al
- and al,0Fh
- or al,1
- mov byte ptr es:[mark+3],al
- pop ax
- pop es
- popf
-
- ENDIF
-
- endm
-
- call_token macro ccb
- ;--------------------------------------;
- ; loads address of CCB in ES:BX, then ;
- ; calls the Token Ring Interface. ;
- ;--------------------------------------;
- mov ax,cs
- mov es,ax
- mov bx,offset &ccb&
- int toke_vect
- endm
-
-
- call_wait macro
- local wait_loop
- ;---------------------------------------;
- ; assumes ES:BX points to a CCB. Waits ;
- ; for a pending command to terminate. ;
- ;---------------------------------------;
- wait_loop:
- mov al,es:[bx+2]
- cmp al,toke_wait
- je wait_loop
- endm
-
-
- ticks macro
- ;---------------------------------------;
- ; get system timer ticks in CX:DX ;
- ;---------------------------------------;
- mov ah,0
- int 1Ah
- endm
-
-
- set_ptr macro dest,addr
- ;---------------------------------------;
- ; loads a far pointer with a near ;
- ; address offset and CS: ;
- ;---------------------------------------;
- mov ax,offset &addr&
- mov word ptr [&dest&],ax
- mov ax,cs
- mov word ptr [&dest&+2],ax
- endm
-
-
- print$ macro string
- ;---------------------------------------;
- ; sends $ terminated string to screen ;
- ;---------------------------------------;
- mov ah,9
- mov dx,offset &string& ; print $ terminated string
- int 21h
- endm
-
-
- clr_struc macro name
- ;---------------------------------------;
- ; clear all bytes of the named struc ;
- ; to zero. Useful for Token calls. ;
- ;---------------------------------------;
- mov cx,SIZE &name& ; uses ax, es:di, cx
- mov ax,ds
- mov es,ax
- mov di,offset &name&
- xor al,al
- cld
- rep stosb ; set all elements to 0
- endm
-
-
- rdupb macro l,n
- &l& db ?
- rept &n&-1
- db ?
- endm
- endm
-
- ccb_blk struc ; CCB used for local token ring calls.
- adapter db ? ; adapter 0 or 1
- command db ? ; command code
- returncode db ? ; command completion code
- work db ? ; scratch
- pointer dd ? ; queue pointer
- complt dd ? ; command complete appendage
- parms dd ? ; pointer to CCB parameter table
- ccb_blk ends
-
-
- init_parms struc ; parameters for DIR_INITIALIZE
- bring_ups dw ? ; result of bring up tests
- sram_addr dw ? ; shared ram address
- reserved dd ? ; not used...
- chk_exit dd ? ; adapter check exit
- status dd ? ; ring status exit
- error dd ? ; PC error exit
- init_parms ends
-
-
- o_parms struc ; ccb parms for DIR_OPEN
- adapt dd ? ; ptr to adapter parms
- direct dd ? ; ptr to direct parms
- dlc dd ? ; ptr to dlc parms
- msg dd ? ; ptr to msg parms
- o_parms ends
-
-
- ada_blk struc ; adapter open parms table format
- err_code dw ? ; open errors detected
- options dw ? ; various options
- node_addr dd ? ; node address ( 4 bytes here + )
- dw ? ; rest of node address ( 2 here )
- group_add dd ? ; group address
- func_add dd ? ; functional address
- rcv_buff dw ? ; number of receive buffers
- rcv_len dw ? ; receive buffer length
- dhb_len dw ? ; length of transmit buffers
- hold_buf db ? ; number of tx buffers
- db ? ; reserved
- lock_code dw ? ; lock code
- id_addr dd ? ; address of id code
- ada_blk ends
-
-
- dir_blk struc ; dir interfce open parms table format
- buf_size dw ? ; size of direct station buffer
- pool_blks dw ? ; number of 16 byte blocks in buff pool
- pool_addr dd ? ; address of direct station buffer pool
- chk_exit dd ? ; the rest can be 0 (defaults) for now
- stat_exit dd ? ; ring status appendage pointer
- err_exit dd ? ; PC error exit
- work_addr dd ? ; work area segment value
- len_req dw ? ; work area length requested
- len_act dw ? ; actual length obtained
- dir_blk ends
-
-
- dlc_blk struc ; dlc interface open parms table format
- max_sap db ? ; max number of saps
- max_sta db ? ; max number of stations
- max_gsap db ? ; max group saps
- max_gmem db ? ; max members per group
- t1_tick1 db ? ; DLC timer t1 interval
- t2_tick1 db ? ; DLC timer t2 interval
- TI_tick1 db ? ; DLC timer TI interval
- t1_tick2 db ? ; DLC timer t1 group 2
- t2_tick2 db ? ; DLC timer t2 group 2
- TI_tick2 db ? ; DLC timer TI group 2
- dlc_blk ends
-
-
- mod_blk struc ; modify open parms parameter block
- buf_size dw ? ; size of SAP buffers
- pool_blks dw ? ; length in 16-byte, of buffer pool
- pool_adrs dd ? ; address of direct interface buf pool
- chkt_exit dd ? ; appendage, adapter check
- stat_exit dd ? ; appendage, ring status
- err_exit dd ? ; appendage, PC error exit
- new_opts dw ? ; new options (wrap is ignored)
- mod_blk ends
-
-
- tx_blk struc ; transmit.dir.frame parameter block
- station dw ? ; defines station sending data
- trans_fs db ? ; * stripped FS field (returned)
- rsap db ? ; RSAP (remote sap value)
- queue_1 dd ? ; address of TX queue 1
- queue_2 dd ? ; address of TX queue 2
- buf_len_1 dw ? ; length of buffer 1
- buf_len_2 dw ? ; length of buffer 2
- buffer_1 dd ? ; address of the first transmit buffer
- buffer_2 dd ? ; address of the second transmit buffer
- tx_blk ends
-
-
- free_blk struc ; buffer.free parameters
- st_id dw ? ; station id
- buf_left dw ? ; returns number of buffers left
- resrvd dd ? ;
- first_buf dd ? ; address of 1st buffer to free
- free_blk ends
-
-
- get_blk struc ; buffer.get parameters
- stn_id dw ? ; station id
- buffr_lef dw ? ; buffers left
- buff_get db ? ; number of buffers to get
- resrv1 db ? ; 3 bytes not used
- resrv2 db ?
- resrv3 db ?
- frst_buff dd ? ; address of buffer obtained
- get_blk ends
-
-
- rx_blk struc ; receive parms
- id dw ? ; station id
- user_len dw ? ; size of user space in buffer
- receiver dd ? ; appendage for received data
- first_bf dd ? ; pointer to 1st buffer
- opts db ? ; receive options
- rx_blk ends
-
-
- status_blk struc ; parameter table for dir.status
- encoded_addr dw ? ; adapters permanent ring address
- dd ?
- node_adrs dw ? ; ring address set by open
- dd ?
- group_adrs dd ?
- func_adrs dd ?
- REPT 16
- db ?
- ENDM
- REPT 3
- dd ?
- ENDM
- dw ?
- status_blk ends
-
-
-
-
-
- mac_header struc ; token ring mac header format
- AC db ? ; access control byte
- FC db ? ; frame control byte
- dest db EADDR_LEN dup(?)
- source db EADDR_LEN dup(?)
- dsap db ? ; LLC dsap
- ssap db ? ; LLC ssap
- control db ? ; control byte
- ptype db ?
- db ? ; SNAP header
- db ?
- ethtype dw ? ; EtherType
- rif dw ? ; optional RIF information
- REPT 8 ; segment information
- dw ? ; this is not its real position.
- ENDM ; this is a variable length field...
- mac_header ends
-
-
- SA_blk struc
- rdupb s_addr,EADDR_LEN
- RCF db ?
- db ?
- route dw ?
- REPT 7
- dw ?
- ENDM ?
- t_mark dd ? ; LRU time marker...
- SA_blk ends
-
-
- ether_hdr struc ; ethernet header format
- rdupb ether_dest,EADDR_LEN
- rdupb ether_src,EADDR_LEN
- ether_type dw ?
- ether_hdr ends
-
-
- first_buffer struc ; Token receive 1st buffer
- next_buffer dd ? ; ptr to next buffer
- xx1 dw ?
- data_size dw ? ; size of user data
- REPT 12
- db ?
- ENDM
- user_data db ?
- first_buffer ends
-
- user_data2 = 12 ; 2nd buffer slightly different
-
-
-
- ;=============================================================================;
- ;======================= START OF PROGRAM CODE ===============================;
- ;=============================================================================;
-
- code segment word public
- assume cs:code, ds:code
-
- ccb ccb_blk <> ; scratch CCB
- free_ccb ccb_blk <>
- tx_parms tx_blk <> ; transmit.dir.frame parms
- iparms init_parms <> ; init parms
- pool_buff db (pool_size+1)*16 dup (?); buffer pool
- free_parms free_blk <> ; buffer.free parameters
- get_parms get_blk <> ; buffer.get parameters
-
- rx_ccb ccb_blk <> ; receive CCB
- rx_parms rx_blk <> ; receive parms
-
-
- id_code db 18 dup (0) ; phony product id code
- ; (a real space saver...)
-
- my_open db 0 ; set to 1 if we opened the adapter
-
- ada_parm ada_blk <0,0,0,0,0,0,num_rcv_buff,recv_size,tran_size,1,0,0,0>
-
- dir_parm dir_blk <0,pool_size,0,0,0,0,0,0,0>
- dlc_parm dlc_blk <0,0,0,0,0,0,0,0,0,0>
- init_parm o_parms <0,0,0,0>
- initccb ccb_blk <0,0,0,0,0,0,0>
- toke_status status_blk <>
-
- modparms mod_blk <0,pool_size,0,0,0,0,0>
- modccb ccb_blk < 0,modify_cmd,0,0,0,0,0>
-
- lan_header mac_header <LLC_AC,LLC_FC>
-
-
- ; SA RIF table has 1 entry in it by default, for the broadcast address.
- ;
- SA_index dw 1
- SA_size dw SA_table_size ; size of table
- dw 0 ; parsed from cmd line
-
- SA_delta dw 0 ; delta t for LRU find
- dw 0
- SA_ord dw 0 ; ordinal for LRU entry
-
- RIF_cache_ptr dw ?
-
- dir_interrupt proc
- ;---------------------------------------;
- ; Entry: token_card (0 or 1) ;
- ; Exit: AX = CCB return code ;
- ;---------------------------------------;
- clr_struc ccb ; initialize CCB
- mov ax,token_card
- mov [ccb.adapter],al
- mov al,interrupt_cmd
- mov [ccb.command],al
- call_token ccb ; call the interface
- call_wait ccb ; wait for completion
- xor ah,ah
- mov al,[ccb.returncode] ; return the result in AX
- ret
- dir_interrupt endp
-
-
- dir_initialize proc
- ;---------------------------------------;
- ; Entry: token_card (0 or 1) ;
- ; Exit: ;
- ; Ah = bring up return code ;
- ; Al = ccb return code ;
- ;---------------------------------------;
- clr_struc ccb ; clear ccb
- clr_struc iparms ; clear init parms (defaults)
-
- mov ax,token_card ; assign parameters
- mov [ccb.adapter],al
- mov al,initialize_cmd ; command....
- mov [ccb.command],al
-
- set_ptr ccb.parms,iparms ; link to init parms
-
- call_token ccb ; call the interface
- call_wait ccb ; wait for completion
-
- mov ah,byte ptr iparms.bring_ups
- mov al,[ccb.returncode]
-
- ret
- dir_initialize endp
-
-
- dir_open_adapter proc
- ;---------------------------------------;
- ; Entry: token_card (0 or 1) ;
- ; Exit: AX = CCB return code ;
- ;---------------------------------------;
- mov ax,token_card ; get adapter number
- mov [initccb.adapter],al
-
- mov al,open_cmd
- mov [initccb.command],al ; 03h open_adapter command
-
- set_ptr ada_parm.id_addr,id_code
- set_ptr dir_parm.pool_addr,pool_buff
- set_ptr init_parm.adapt,ada_parm
- set_ptr init_parm.direct,dir_parm
- set_ptr init_parm.dlc,dlc_parm
- set_ptr initccb.parms,init_parm
-
- xor al,al
- mov [initccb.returncode],al
-
- call_token initccb ; call the interface
- ; call_wait initccb ; wait for completion
- doa_1:
- print$ msg_opening ; wait for completion
- mov al,es:[bx]+2
- cmp al,toke_wait
- je doa_1
-
- print$ msg_lf
-
- xor ah,ah
- mov al,[initccb.returncode]
-
- ret
- dir_open_adapter endp
-
-
- dir_close_adapter proc
- ;---------------------------------------;
- ; Entry: token_card (0 or 1) ;
- ; Exit: AX = CCB return code ;
- ;---------------------------------------;
- clr_struc ccb ; clear CCB
-
- mov ax,token_card ; initialize local CCB
- mov [ccb.adapter],al
- mov al,close_cmd ; close command
- mov [ccb.command],al
-
- call_token ccb ; call the interface
- call_wait ccb ; wait for completion
-
- xor ah,ah
- mov al,[ccb.returncode] ; return the result
- ret
- dir_close_adapter endp
-
-
- dir_modify_open proc
- ;---------------------------------------;
- ; Entry: token_card (0 or 1) ;
- ; Exit: AX = CCB return code ;
- ;---------------------------------------;
- mov ax,token_card ; get adapter number
- mov [modccb.adapter],al ; command is a constant in ccb
-
- set_ptr modparms.pool_adrs,pool_buff
- set_ptr modccb.parms,modparms
-
- xor al,al
- mov [modccb.returncode],al
-
- call_token modccb ; call the interface
- call_wait modccb ; wait for completion
-
- xor ah,ah
- mov al,[modccb.returncode]
- ret
- dir_modify_open endp
-
-
- dir_restore_open proc
- ;---------------------------------------;
- ; Entry: token_card (0 or 1) ;
- ; Exit: AX = CCB return code ;
- ;---------------------------------------;
- clr_struc ccb ; initialize CCB
-
- mov ax,token_card
- mov [ccb.adapter],al
- mov al,restore_cmd ; dir.restore.open.parms
- mov [ccb.command],al
-
- call_token ccb ; call the interface
- call_wait ccb ; wait for completion
-
- xor ah,ah
- mov al,[ccb.returncode] ; return the result in AX
- ret
- dir_restore_open endp
-
-
- transmit_dir_frame proc
- ;---------------------------------------;
- ; Entry: token_card (0 or 1) ;
- ; ;
- ; Stack: ;
- ; sp+14 dw [usr seg] ;
- ; sp+12 dw [usr ofs] ;
- ; sp+10 dw [usrsize] ;
- ; sp+8 dw [hdr seg] ;
- ; sp+6 dw [hdr ofs] ;
- ; sp+4 dw [hdrsize] ;
- ; sp+2 dw [ret ofs] ;
- ; sp+0 dw [ bp ] ;
- ; ;
- ; Exit: ;
- ; Ah = stripped FS field ;
- ; al = CCB return code ;
- ;---------------------------------------;
-
- trans_frame struc ; transmit_dir_frame parms
- _x_bp dw ? ; old bp register
- _x_ret_ofs dw ? ; near return address
- header_size dw ? ; MAC header size
- llc_header dd ? ; address of header
- user_dsize dw ? ; user data size
- user_daddress dd ? ; user data address
- trans_frame ends
-
- push bp
- mov bp,sp
-
- mov ax,cs
- mov ds,ax
-
- clr_struc ccb ; zero the CCB
- clr_struc tx_parms ; zero parameters
-
- mov ax,token_card ; initialize local CCB
- mov [ccb.adapter],al
- mov al,trans_dir_cmd ; transmit.dir.frame
- mov [ccb.command],al
- ;
- ; Set up transmit parameters, and link them to
- ; the CCB...
- ;
- mov ax,offset tx_parms
- mov word ptr [ccb.parms],ax
-
- mov ax,cs
- mov word ptr [ccb.parms+2],ax
- ;
- mov ax,STATION_ID
-
- mov word ptr [tx_parms.station],ax
-
- mov ax,[bp][user_dsize]
- mov word ptr [tx_parms.buf_len_2],ax
-
- mov ax,word ptr [bp][user_daddress]
- mov word ptr [tx_parms.buffer_2],ax
- mov ax,word ptr [bp][user_daddress+2]
- mov word ptr [tx_parms.buffer_2+2],ax
-
- mov ax,[bp][header_size]
- mov word ptr [tx_parms.buf_len_1],ax
-
- mov ax,word ptr [bp][llc_header]
- mov word ptr [tx_parms.buffer_1],ax
- mov ax,word ptr [bp][llc_header+2]
- mov word ptr [tx_parms.buffer_1+2],ax
-
- call_token ccb ; call the interface
- call_wait ccb ; wait for completion
-
- mov ah,[tx_parms.trans_fs]
- mov al,[ccb.returncode]
-
- pop bp
-
- ret (SIZE trans_frame)-4 ; (forget bp and ret address)
- transmit_dir_frame endp
-
-
- buffer_free proc
- ;---------------------------------------;
- ; Entry: ;
- ; sp+4 [ seg 1st buffer ] ;
- ; sp+2 [ ofs 1st buffer ] ;
- ; sp+0 [ bp ] ;
- ; ;
- ; Exit: AX = CCB return code ;
- ;---------------------------------------;
- mov ax,cs
- mov ds,ax
-
- push bp
- mov bp,sp
-
- clr_struc free_ccb
- clr_struc free_parms
-
- mov ax,token_card ; initialize local CCB
- mov [free_ccb.adapter],al
-
- mov al,free_ccb_cmd ; buffer.free
- mov [free_ccb.command],al
-
- mov ax,offset free_parms
- mov word ptr [free_ccb.parms],ax
-
- mov ax,cs
- mov word ptr [free_ccb.parms+2],ax
- ;
- ; Load free_parms to release buffer
- ;
- mov ax,STATION_ID
- mov word ptr [free_parms.st_id],ax
-
- mov ax,[bp][4]
- mov free_parms.first_buf.offs,ax
- mov ax,[bp][6]
- mov free_parms.first_buf.segm,ax
-
- call_token free_ccb ; call the interface
-
- xor ah,ah
- mov al,[free_ccb.returncode]; return the result in AX
-
- pop bp
-
- ret 4
- buffer_free endp
-
-
- recv_cancel proc
- ;---------------------------------------;
- ; Entry: token_card (0 or 1) ;
- ; ;
- ; Exit: ;
- ; AX = CCB return code ;
- ; ;
- ;---------------------------------------;
- mov ax,token_card ; initialize local CCB
- mov [ccb.adapter],al
-
- mov al,recv_can_cmd ; receive.cancel
- mov [ccb.command],al
-
- xor ax,ax ; word/bytes set to 0
- mov [ccb.returncode],al
- mov [ccb.work],al
- mov word ptr [ccb.pointer],ax
- mov word ptr [ccb.pointer+2],ax
- mov word ptr [ccb.complt],ax
- mov word ptr [ccb.complt+2],ax
- mov word ptr [ccb.parms+2],ax
-
- mov ax,STATION_ID
- mov word ptr [ccb.parms],ax
-
- call_token ccb ; call the interface
- call_wait ccb ; wait for completion
-
- xor ah,ah
- mov al,[ccb.returncode] ; return the result in AX
- ret
-
- recv_cancel endp
-
-
- open_receive proc
- ;---------------------------------------;
- ; Entry: token_card (0 or 1) ;
- ; ;
- ; Stack: ;
- ; sp+6 dw [ret ofs] ;
- ; sp+4 dw [ bp ] ;
- ; sp+2 dw [ ds ] ;
- ; sp+0 dw [ es ] ;
- ; ;
- ; Exit: ;
- ; AX = CCB return code ;
- ;---------------------------------------;
- mov ax,cs
- mov ds,ax
-
- clr_struc rx_ccb
- clr_struc rx_parms ;
-
- mov ax,token_card ; initialize local CCB
- mov [rx_ccb.adapter],al
-
- mov al,open_recv_cmd ; receive
- mov [rx_ccb.command],al
-
- mov ax,offset recv_complt
- mov word ptr [rx_ccb.complt],ax
- mov ax,cs
- mov word ptr [rx_ccb.complt+2],ax
- ;
- ; Link receive parameters table
- ;
- mov ax,offset rx_parms
- mov word ptr [rx_ccb.parms],ax
- mov ax,cs
- mov word ptr [rx_ccb.parms+2],ax
-
- mov ax,STATION_ID
- mov word ptr [rx_parms.id],ax
-
- mov al,RECV_OPTIONS
- mov rx_parms.opts,al
-
- mov ax,offset _receiver
- mov word ptr [rx_parms.receiver],ax
- mov ax,cs
- mov word ptr [rx_parms.receiver+2],ax
- ;
- ; Note: The receive request is submitted, but it doesn't 'complete'
- ; here. So DON'T wait for a completion code!
- ;
- call_token rx_ccb ; call the interface
-
- xor ah,ah
- mov al,[rx_ccb.returncode] ; return the result
- ret
- open_receive endp
-
-
- recv_complt proc
- ;
- ; This procedure is an interrupt routine called by the Token Card
- ; when receive completion occurs after an error. All it should have
- ; to do is resubmit the receive request, then exit.
- ;
- pushf
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- push bp
- sti
-
- marker E,R
- call open_receive ; restart communications
-
- pop bp
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- popf
- iret
- recv_complt endp
-
-
- recv_frame struc ; stack frame for receiver
- RIF_size dw ? ; size of RIF in packet.
- user_buff dd ? ; pointer to users buffer
- user_size dw ? ; size of buffer needed/used
- _BP dw ? ; register set on stack
- _ES dw ?
- _DS dw ?
- _DI dw ?
- _SI dw ?
- _DX dw ?
- _CX dw ?
- _BX dw ?
- _AX dw ?
- recv_frame ends
-
-
- _receiver proc
- ;
- ; This interrupt procedure is called when the Token Ring
- ; card has data.
- ;
- ; On entry, ds:si points to the CCB
- ; es:bx points to the receive first_buffer in the chain.
- ;
- ;
- pushf ; save CPU environment
- push ax
- push bx
- push cx
- push dx
- push si
- push di
- push ds
- push es
- push bp
-
- push ax ; local variables: size of receive data
- push ax ; segment of user supplied buffer
- push ax ; offset of user supplied buffer
- push ax
-
- mov bp,sp ; set stack frame reference
-
- cld
- sti ; enable further int activity
-
- marker R,X
- ;
- ; If the source address is mine, ignore the transmission!
- ;
- mov ax,cs
- mov ds,ax
- mov si,offset my_address
- lea di,[bx].user_data+source; ds:si -> token address
- ; es:di -> pkt
- mov cx,EADDR_LEN
- push word ptr es:[di] ; save msb of address
-
- mov al,es:[di]
- and al,not_SA_mask ; drop SA indicator
- mov es:[di],al ; fix the bit during compare
- repe cmpsb ; do string compare now
- jne not_mine
-
- lea di,[bx].user_data+source
- pop word ptr es:[di] ; restore token address
-
- jmp drop_buffer ; from me, ignore it!
-
- ; es:bx -> 1st receive buffer
- not_mine:
- lea di,[bx].user_data+source
- pop word ptr es:[di] ; save MSB of source address
-
- xor ax,ax
- mov cx,ax
- mov word ptr [bp][RIF_size],ax; zero RIF size value
-
- get_size:
- mov ax,es
- or ax,bx
- je got_size
- add cx,es:[bx].data_size
- les bx,es:[bx].next_buffer
- jmp get_size
-
- got_size:
- sub cx,LLC_info_size ; adjust size for Token
-
- mov es,[bp][_ES]
- mov bx,[bp][_BX] ; get buffer address
- mov al,es:[bx][user_data+source]
- and al,SA_mask ; if SA, adjust total
- je got_no_fix
-
- ;
- ; How big is the RIF?
- ;
- mov ax,word ptr es:[bx][user_data+source+EADDR_LEN]
- and ax,RIF_size_mask
- mov [bp][RIF_size],ax
- ;
- ; Take away size of RIF. Upper level doesn't get it.
- ;
- sub cx,ax ; subtract RIF size
-
- got_no_fix:
- ;
- ; Min Ethersize is RUNT, so check it first, round up if necessary
- ;
- cmp cx,RUNT
- jge no_adjust_cx
- mov cx,RUNT
-
- no_adjust_cx:
- mov [bp].user_size,cx ; save size of receive data
- ;
- ; Call recv_find to determine if the receiver wants the data,
- ; and where it should be stored.
- ;
- mov es,_ES[bp] ; reload segment/offset
- mov di,_BX[bp] ; points to E-type in Token
- add di,40 ; assumes Buffer 1 format,
- add di,[bp][RIF_size] ; RIF size added now...
- ;
- ; if ARP type, convert hardware address space value back to Ethernet...
- ;
- mov ax,word ptr es:[di] ; -> EtherType in SNAP
- cmp ax,ARP_type ; ARP packet?
- jne not_rx_arp
- mov ax,ARP_Eth_hwr
- mov word ptr es:[di][2],ax ; fix 1st field of data
-
- not_rx_arp:
- mov dl,BLUEBOOK
- call recv_find ; es:di -> Snap E-Type, CX = data size
-
- mov [bp].user_buff.offs,di
- mov [bp].user_buff.segm,es
-
- mov ax,es
- or ax,di
- jne do_copy
- jmp drop_buffer ; if ptr is 0, doesn't want it!
- ;
- ; Copy Token Ring data to users Ethernet format receive buffer.
- ;
- do_copy:
- ;
- ; Since the upper level wants it, better keep the RIF info in case we
- ; want to send a return message.
- ;
- mov ds,_ES[bp]
- mov si,_BX[bp]
- add si,user_data+source ; 1st byte of source address
- call add_entry ; do table maintenance
- ;
- ; Copy data to the users buffer
- ;
- les di,[bp].user_buff ; Ethernet destination buffer
-
- mov bx,_BX[bp] ; Token Ring Source buffer
- mov ds,_ES[bp]
- lea si,[bx].user_data ; offset to user data
- ;
- ; ds:si points to 1st token buffer
- ; es:di points to ethernet format buffer
-
- ; 1. Copy Token/Ether dest/source field to users buffer
- ; after stripping off the SA bit in the source address.
-
- and ds:[si].source,7fh
-
- mov cx,EADDR_LEN*2 ; 2 address fields
- add si,2 ; offset to dest field
- rep movsb
-
- add si,LLC_info_size-2 ; assume no RIF,
- add si,word ptr [bp][RIF_size]; compensate for RIF
-
- movsw ; get ethertype
-
- mov cx,[bx].data_size ; get length of data
- sub cx,MAC_hdr_size ; drop MAC header stuff
- sub cx,[bp][RIF_size] ; compensate for RIF
-
- copy_buffer:
- rep movsb ; copy rest of data to Ether..
- lds bx,[bx].next_buffer ; bx is base of buffer
- lea si,[bx].user_data2 ; si offsets to user data
- mov cx,[bx].data_size ; length of user data
- mov ax,ds
- or ax,bx ; NULL pointer?
- jne copy_buffer ; no, keep copying...
- ;
- ; Tell Upper layer I copied the data into his buffer...
- ;
- lds si,[bp].user_buff
- mov cx,[bp].user_size
-
- call recv_copy
- ;
- ; _ES:_BX points to 1st receive buffer, drop it, then exit
- ;
- drop_buffer:
- push _ES[bp] ; tell Token, drop buffer
- push _BX[bp]
- call buffer_free ; seg:offs of 1st buff on stack
-
- add sp,4*2 ; vacuum local variables off the stack
-
- pop bp
- pop es
- pop ds
- pop di
- pop si
- pop dx
- pop cx
- pop bx
- pop ax
- popf
-
- marker r,x
-
- iret
-
- _receiver endp
-
-
- comp_adr proc
- ;
- ; Compare two token address values, set flags without affecting any
- ; other registers. JE or JNE to test result.
- ;
- push si
- push di
- push cx
- mov cx,EADDR_LEN
- repe cmpsb
- pop cx
- pop di
- pop si
- ret
- comp_adr endp
-
-
- make_adr proc
- ;
- ; Given CX as an ordinal (1..n) into the RIF_cache, build the address
- ; in ES:DI
- ;
- push ax
- push cx
- dec cx
- xor di,di
- cmp cx,0
- je make_adr1
- make_adr0:
- add di,SIZE SA_blk ; build index into SA_table
- loop make_adr0
-
- make_adr1:
- mov ax,cs ; segment of table
- mov es,ax
- add di,RIF_cache_ptr ; + offset to base of table
- pop cx
- pop ax
- ret
- make_adr endp
-
-
-
- add_entry proc
- ;
- ; DS:SI -> Token Address, make an entry in the SA routing table
- ;
- mov cx,EADDR_LEN ; don't add broadcasts to table
- push si ; leave the default intact
-
- add_entry0:
- lodsb ; Broadcast?
- cmp al,broadcast_byte
- loope add_entry0
- pop si
- je add_done ; yes...
-
- mov al,ds:[si] ; is it a source route address?
- and al,SA_mask
- je add_done
- ;
- ; Is it in the table?
-
- call loc_entry
- jc add_done ; c = 1, its in the table.
- ;
- ; if its not in the table, try to put it in a 'new' slot...
- ;
- mov cx,word ptr cs:[SA_index]
- cmp cx,word ptr cs:[SA_size]
- jne lotsa_room ; room in table, make flat entry
- ;
- ; If no new slots available, determine LRU entry and overwrite it...
- ;
- push ds ; save initial pointer
- push si
- call find_lru ; returns cx ordinal into table
- pop si ; restore initial pointer
- pop ds
- jmp do_entry
- ;
- ; Update entry pointer, overwrite a new slot in the table...
- ;
- lotsa_room:
- inc cx
- mov word ptr cs:[SA_index],cx; advance the table index
-
- ; before entry is made, the broadcast bit must be cleared so bridges
- ; will leave the segment values alone.
-
- do_entry:
- mov al,byte ptr ds:[si+EADDR_LEN]
- and al,07Fh ; clear broadcast bit
- mov byte ptr ds:[si+EADDR_LEN],al
-
- call make_adr ; build destination address
- push si
- push di
- push es
- mov cx,SIZE SA_blk
- rep movsb ; copy RIF into table
- pop es
- pop di
- pop si
- ;
- ; Put time stamp on the new entry for LRU algorithm
- ;
- ticks ; cx:dx = ticks count
- mov word ptr es:[di+t_mark],dx
- mov word ptr es:[di+t_mark+2],cx
-
- add_done:
- ret
- add_entry endp
-
-
- find_lru proc
- ;
- ; locates oldest entry in the RIF_cache, returns the ordinal number in
- ; CX. The first entry is NEVER chosen because it contains the broadcast
- ; route predefined in the table!
- ;
- ; CX = 2 .. cs:[SA_size] ( range to be searched )
- ;
- ; SA_delta dword contains time difference for last one checked
- ; SA_ord word contains the ordinal of the least recently used
- ;
- xor ax,ax ; zero search variables
- mov word ptr cs:[SA_delta],ax
- mov word ptr cs:[SA_delta+2],ax
- mov word ptr cs:[SA_ord],ax
-
- mov cx,2 ; 1st entry is NEVER touched!
-
- find_loop:
- call make_adr ; es:di -> current entry
- push cx ; save index
- ticks ; cx:dx = current ticks
- sub cx,word ptr es:[di+t_mark+2]; ticks = mark
- sbb dx,word ptr es:[di+t_mark]
- ;
- ; if the result < 0, then ticks went past midnight. Add 24 hrs in
- ; ticks to get the real delta t.
- ;
- jge _no_fix
- add cx,((hrs24 shr 16) and 0ffffh); longint to fix delta t
- adc dx,(hrs24 and 0ffffh) ; add 24 hours in ticks to
-
- _no_fix:
- ;
- ; If the result is greater than the stored SA_delta, replace it with
- ; this entry, then continue the loop...
- ;
- push cx ; save hi/low delta t result
- push dx
- sub cx,word ptr cs:[SA_delta+2]
- sbb dx,word ptr cs:[SA_delta]
- jl _no_replace
-
- ;
- ; replace SA_ord and SA_delta with entry that has been around longer
- ;
- pop cs:[SA_delta] ; pull lo/hi delta t result
- pop cs:[SA_delta+2]
- pop cx ; get ordinal...
- mov word ptr cs:[SA_ord],cx ; replace SA_ord...
- jmp _next_find
-
- _no_replace:
- pop cx
- pop cx
- pop cx
-
- _next_find:
- inc cx
- cmp cx,word ptr cs:[SA_size]
- jle find_loop
- jmp _find_exit
-
- _find_exit:
- mov cx,SA_ord ; return ordinal of LRU
- ret
-
- find_lru endp
-
-
-
- loc_entry proc
- ;
- ; DS:SI -> Token Address, locate entry in the SA routing table
- ; ES:DI -> SA information in table, if carry is set.
- ;
- mov cx,word ptr cs:[SA_index]; any entries in table?
- cmp cx,0
- je loc_done
-
-
- loc_entry0:
- call make_adr ; build address into table
- call comp_adr ; compare Token Addresses
- je loc_found ; if matches, in table
- loop loc_entry0
-
- loc_done:
- clc
- ret
-
- loc_found:
- ; ES:DI points to matching entry
- ticks ; cx:dx = ticks value for
- mov word ptr es:[di+t_mark],dx; refresh of existing
- mov word ptr es:[di+t_mark+2],cx; entry...
-
- stc
- ret
-
- loc_entry endp
-
-
- ;==============================================================================
- ;
- ;=================== DRIVER CODE =============================================
- ;
- ;==============================================================================
- ;
- ;
- ; Token Ring Card number, parsed from command line
- ;
- token_card dw 0 ; default adapter number 0
- dw 0 ; this prevents type error.
-
- toke_ad_name db "Adapter (0 or 1) ",'$'
- toke_sa_name db " RIF Cache Size: ",'$'
-
- dir_open_mode db 0 ; set <> 0 if modify_open used
- msg_initialize db " INIT: Initializing the adapter...",CR,LF,'$'
- msg_opening db " Opening the adapter...",CR,'$'
- msg_lf db LF,'$'
- msg_complete db " IBMTOKEN - Initialization complete.",CR,LF,'$'
- msg_modifying db " Creating direct buffer pool...",CR,LF,'$'
- msg_bad_adapter db "ERROR: adapter must be 0 or 1.",CR,LF,'$'
- no_mem_cache db "ERROR: RIF_cache value out of range!",CR,LF
- msg_bad_init db "ERROR: Initialization Failed.",CR,LF
- db " Installation aborted!",CR,LF,'$'
- msg_receiving db " Starting receiver process...",CR,LF,'$'
-
- public int_no
- int_no db 0,0,0,0 ;must be four bytes long for get_number.
-
- public driver_class, driver_type, driver_name, driver_function, parameter_list
- driver_class db BLUEBOOK,0 ;from the packet spec
- driver_type db 92 ;from the packet spec
- driver_name db 'IBMTokenR',0 ;name of the driver.
- driver_function db 2
-
- parameter_list label byte
- db 1 ;major rev of packet driver
- db 9 ;minor rev of packet driver
- db 14 ;length of parameter list
- db EADDR_LEN ;length of MAC-layer address
- dw GIANT ;MTU, including MAC headers
- dw MAX_MULTICAST * EADDR_LEN;buffer size of multicast addrs
- dw 0 ;(# of back-to-back MTU rcvs) - 1
- dw 0 ;(# of successive xmits) - 1
- dw 0 ;Interrupt # to hook for post-EOI
- ;processing, 0 == none,
-
- public rcv_modes
- rcv_modes dw 4 ;number of receive modes in our table.
- dw 0,0,0,rcv_mode_3
-
-
- sp_frame struc
- __bp dw ?
- u_size dw ?
- u_data dd ?
- u_snap dw ?
- sp_frame ends
-
-
- public bad_command_intercept
- bad_command_intercept:
- ;called with ah=command, unknown to the skeleton.
- ;exit with nc if okay, cy, dh=error if not.
- mov dh,BAD_COMMAND
- stc
- ret
-
- public as_send_pkt
- ; The Asynchronous Transmit Packet routine.
- ; Enter with es:di -> i/o control block, ds:si -> packet, cx = packet length,
- ; interrupts possibly enabled.
- ; Exit with nc if ok, or else cy if error, dh set to error number.
- ; es:di and interrupt enable flag preserved on exit.
- as_send_pkt:
- ret
-
- public drop_pkt
- ; Drop a packet from the queue.
- ; Enter with es:di -> iocb.
- drop_pkt:
- assume ds:nothing
- ret
-
- public xmit
- ; Process a transmit interrupt with the least possible latency to achieve
- ; back-to-back packet transmissions.
- ; May only use ax and dx.
- xmit:
- assume ds:nothing
- ret
-
-
- public send_pkt
- send_pkt:
- ;enter with ds:si -> packet, cx = packet length.
- ;exit with nc if ok, or else cy if error, dh set to error number.
- assume ds:nothing
-
- cmp cx,GIANT ; Is this packet too large?
- ja send_pkt_toobig
-
- sti
- marker T,X
-
- ;
- ; construct local stack frame
- ;
- push ds:[si].ether_type
- push ds ; pointer to user data packet
- lea ax,[si]+SIZE ether_hdr
- push ax ; adjusted userdata pointer
- sub cx,SIZE ether_hdr ; adjust size for send
- push cx
- push bp
- mov bp,sp ; use sp_frame for reference
-
-
- mov ax,cs ; set dest pointer to LLC header
- mov es,ax
-
- mov di,offset lan_header.dest
- mov cx,EADDR_LEN*2 ; copy dest|source fields
- rep movsb
- ;
- ; ds:si -> dest address, locate it in the SA RIF table
- ;
- mov ax,cs
- mov ds,ax
- mov si,offset lan_header.dest; building LAN header info here
-
- ; Set bit 7 of address, force lookup in table. If it is found, add RIF,
- ; otherwise, assume the local net.
-
- or byte ptr ds:[si],80h
-
- call loc_entry
- jc send_pkt1 ; yes, copy out RIF information
- ;
- ; add the rest of the fields to the LLC header, and set the size
- ; for the transmit call.
- ;
- and byte ptr ds:[si],not_SA_mask ; dest address 1st byte,
- ;lop off SA bit
-
- or byte ptr ds:[si][EADDR_LEN],80h ; force U bit high
-
- add si,EADDR_LEN*2 ; point after dest/source addrs.
- mov ax,es
- mov bx,ds
- mov ds,ax
- mov es,bx
- xchg si,di
-
- ; addresses acquired from ARP default to broadcast mode, using phony
- ; RIF info so the bridge will pass the packet along.
- ;
- mov ax,phony_RIF ; copy phony RIF to LLC buffer,
- stosw ; so 'local' can cross bridge..
- jmp send_pkt2
-
- send_pkt_toobig:
- mov dh,NO_SPACE
- stc
- ret
-
- send_pkt1:
- ;
- ; source/dest address need to be adjusted for routing.
- ;
- mov cx,EADDR_LEN
- push si
-
- send_pkt3:
- mov al,byte ptr ds:[si]
- inc si
- cmp al,broadcast_byte
- loope send_pkt3
- pop si
- je send_pkt4 ; broadcast address?
-
-
- and byte ptr ds:[si],not_SA_mask ; dest, lop off SA bit
-
- send_pkt4:
- or byte ptr ds:[si][EADDR_LEN],SA_mask ; set SA bit for RIF
-
- add si,EADDR_LEN*2 ; ds:si -> dest for RIF info.
- add di,EADDR_LEN ; es:di -> RIF info, addr fld
-
- mov bx,si ; keep RIF pos in LLC header
-
- mov ax,word ptr es:[di] ; get rif info
- and ax,RIF_size_mask ; get length of RIF
- mov cx,ax
- mov ax,es
- mov dx,ds
- mov ds,ax
- mov es,dx
- xchg si,di
- rep movsb
-
- ;
- ; Got RIF, fix direction bit.
- ;
- mov al,es:[bx][1] ; RIF+1 = dir bit location
- xor al,RIF_dir_bit ; change direction
- mov es:[bx][1],al
-
- send_pkt2:
- ;
- ; es:di -> target in LLC for the rest of the header,
- ; add LLC and SNAP information.
- ;
- mov ax,LLC_SSAP_DSAP ; build LLC portion
- stosw
- mov al,LLC_CON
- stosb
- xor ax,ax ; 3 bytes for Ptype in SNAP
- stosw
- stosb
- mov ax,word ptr [bp][u_snap]
- stosw
- ;
- ; header is complete.
- ;
- sub di,offset lan_header ; calculate size of LLC header
- ;
- ; stack parameters for Transmit
- ;
- pop bp
-
- mov ax,cs
- mov ds,ax ; set ds for transmit entry
- push ax
- mov ax,offset lan_header
- push ax
- push di
-
- ;--------------------------------------------------------------------
- ; If Users data is an ARP packet, 0806 type, then the 1st field
- ; must be changed from 0001 to 0006 for Token Ring broadcast, or
- ; no one will respond. Funny, eh? Another thing. Since an ARP
- ; packet is smaller than the min size for Ethernet, the caller rounds
- ; up the size. I have to change it back, or some Token hosts won't
- ; ARP for me. The nerve!
- ;
- push bp
- mov bp,sp
- mov ax,word ptr [bp][14] ; offset to ARP type on stack...
- pop bp
-
- cmp ax,ARP_type ; network byte order is backwards
- jne not_tx_arp
- ;
- ; The first field of the ARP data has to be changed from 0001 to 0006
- ;
- push bp ; use trans_frame
- push bp ; dummy entry on stack...
- mov bp,sp
- les di,[bp].user_daddress ; addr of user data
-
- mov ax,ARP_Tok_hwr
- mov word ptr es:[di],ax ; change ARP type to 0006
-
- mov ax,ARP_packet_size ; 28 bytes in an ARP packet
- mov word ptr [bp][user_dsize],ax; reset users data size
-
- pop bp ; pop fake return address
- pop bp ; pop real bp
-
- not_tx_arp:
- call transmit_dir_frame ; send the packet
-
- pop ax ; vacuum
- clc
- ret
-
-
- public set_address
- set_address:
- ;enter with ds:si -> Ethernet address, CX = length of address.
- ;exit with nc if okay, or cy, dh=error if any errors.
- assume ds:nothing
- mov dh,CANT_SET
- stc
- ret
-
-
- rcv_mode_3:
- ;receive mode 3 is the only one we support, so we don't have to do anything.
- ret
-
-
- public set_multicast_list
- set_multicast_list:
- ;enter with ds:si ->list of multicast addresses, ax = number of addresses,
- ; cx = number of bytes.
- ;return nc if we set all of them, or cy,dh=error if we didn't.
- mov dh,NO_MULTICAST
- stc
- ret
-
-
- public reset_interface
- reset_interface:
- ;reset the interface.
- assume ds:code
- ret
-
-
- ;called when we want to determine what to do with a received packet.
- ;enter with cx = packet length, es:di -> packet type, dl = packet class.
- extrn recv_find: near
-
- ;called after we have copied the packet into the buffer.
- ;enter with ds:si ->the packet, cx = length of the packet.
- extrn recv_copy: near
-
- ;call this routine to schedule a subroutine that gets run after the
- ;recv_isr. This is done by stuffing routine's address in place
- ;of the recv_isr iret's address. This routine should push the flags when it
- ;is entered, and should jump to recv_exiting_exit to leave.
- ;enter with ax = address of routine to run.
- extrn schedule_exiting: near
-
- ;recv_exiting jumps here to exit, after pushing the flags.
- extrn recv_exiting_exit: near
-
- ;enter with dx = amount of memory desired.
- ;exit with nc, dx -> that memory, or cy if there isn't enough memory.
- extrn malloc: near
-
- extrn count_in_err: near
- extrn count_out_err: near
-
- public recv
- recv:
- ;called from the recv isr. All registers have been saved, and ds=cs.
- ;Upon exit, the interrupt will be acknowledged.
- assume ds:code
- ret
-
- public terminate
- terminate:
- sti
- call recv_cancel ; shut down call-backs
- cmp my_open, word ptr 1
- jne restore_parms
- call dir_close_adapter ; close out the adapter
- final_exit:
- ret
-
- restore_parms:
- call dir_restore_open
- jmp short final_exit
-
- include popf.asm
-
- public timer_isr
- timer_isr:
- ;if the first instruction is an iret, then the timer is not hooked
- iret
-
- ;any code after this will not be kept. Buffers used by the program, if any,
- ;are allocated from the memory between end_resident and end_free_mem.
- public end_resident,end_free_mem
- end_resident label byte
- db SA_table_size * (size SA_blk) dup(0)
- end_free_mem label byte
-
- ;=======================================================================;
- ;============================== RIF Cache ==============================;
- ;=======================================================================;
- ; The first entry in the cache is for the broadcast address. This ;
- ; entry is NEVER bumped from the cache! ;
- ;=======================================================================;
-
- RIF_cache_initial SA_blk <0ffh,0ffh,0ffh,0ffh,0ffh,0ffh,82h,0A0h,0>
-
- public usage_msg
- usage_msg db CR,LF
- db "usage: IBMTOKEN <packet_int_no> <adapter> <RIF_cache>",CR,LF,LF
- db "where: entry_point is the interrupt vector",CR,LF
- db " adapter is adapter 0 or 1",CR,LF
- db " RIF_cache is number of hosts in RIF cache",CR,LF,CR,LF
- db " note: IBM (tm) LAN Support Program or similar DLC",CR,LF
- db " interface for other TR adapters required.",CR,LF,'$'
-
- public copyright_msg
- copyright_msg db CR,LF,"Token Ring Driver (3C501 emulation) Version "
- db '0'+(majver / 10),'0'+(majver mod 10),"."
- db '0'+(version / 10),'0'+(version mod 10),CR,LF
- IF alpha NE 0
- db "ALPHA TEST VERSION ",'0'+alpha_ver,CR,LF
- ENDIF
- db "portions -",CR,LF
- db "Copyright 1989, Queens University",CR,LF
- db "Computing and Communications Services",CR,LF
- db "Written by Brian Fisher",CR,LF
- db "Modified to run with MS LAN Manager/IBM LAN",CR,LF
- db "Support Program by Antero Koskinen",CR,LF
- db "Portions copyright 1992, Crynwr Software",CR,LF
- IF debug NE 0
- db "*** DEBUG VERSION ***",CR,LF
- ENDIF
- db LF,LF
- db '$'
-
- extrn set_recv_isr: near
-
- ;enter with si -> argument string, di -> wword to store.
- ;if there is no number, don't change the number.
- extrn get_number: near
-
- public parse_args
- parse_args:
- ;
- ; si points to next argument of command line...
- ;
- mov di,offset token_card ; next argument is card number
- call get_number
- jc _parse_exit
- mov di,offset SA_size ; see if cache size ok...
- call get_number
- _parse_exit:
- clc
- ret
-
- et_error:
- ; token adapter number out of range
- ;if we got an error,
- mov dx,offset msg_bad_adapter
- stc
- ret
-
- sa_error:
- ; RIF cache allocation problem
- ; if no memory for SA table,
- mov dx,offset no_mem_cache
- stc
- ret
-
- et_init_error:
- call dir_close_adapter ; make sure adapter is closed
- mov dx,offset msg_bad_init
- stc
- ret
-
- public etopen
- ;
- ; Initialize the IBM Token Ring Adapter, determine memory requirements
- ; for the RIF_cache.
- ;
- etopen:
- mov ax,cs
- mov ds,ax
- assume cs:code, ds:code
-
- mov ax,token_card ; check card parm for range
- cmp ax,1
- jg et_error
- cmp ax,0
- jl et_error ; less than zero?
-
- mov ax,SA_size ; is the requested RIF cache
- cmp ax,SA_min_size ; size in range?
- jl SA_error
- cmp ax,SA_max_size
- jg SA_error
-
- mov bx,SIZE SA_blk ; multiply to get bytes needed
- imul bx
- or dx,dx
- jne SA_error ; dx <> 0, way out of range!
- mov dx,ax ;malloc needs it in dx.
- call malloc ; bytes needed for code+RIF
- jc SA_error
- mov RIF_cache_ptr,dx ;save pointer to our RIF_cache.
-
- movseg es,cs
- mov di,dx
- mov si,offset RIF_cache_initial
- mov cx,(size SA_blk)
- rep movsb
-
- call dir_interrupt ; check if adapter open
- cmp ax, 0 ; adapter open if retcode 0
- je modify
-
- print$ msg_initialize ; initialize the adapter
- call dir_initialize
- cmp ax,0
- jne et_init_error
-
- call dir_open_adapter
- cmp ax,0
- jne et_init_error
- mov my_open, word ptr 1
- jmp short no_init
-
- modify:
- print$ msg_modifying ; modify adapter open params
- call dir_modify_open
- cmp ax, 0
- je no_init
- jmp et_init_error
-
- no_init:
- print$ msg_receiving ; set up receive routines
- call open_receive
- cmp ax,0ffh
- je init_ok
- jmp et_init_error ; no receive open...
- init_ok:
-
- print$ msg_complete ; card ready to go
-
- mov ax,cs
- mov ds,ax
-
- clr_struc ccb
- clr_struc toke_status
-
- mov ax,token_card ; set adapter number
- mov [ccb.adapter],al
- mov al,get_status_cmd ; get status returns address
- mov ccb.command,al
- mov ax,offset toke_status
- mov word ptr [ccb.parms],ax
- mov ax,ds
- mov word ptr [ccb.parms+2],ax
-
- call_token ccb
- call_wait ccb
-
- mov si,offset toke_status.node_adrs
-
- mov ax,cs
- mov es,ax ; get Token Address for _receiver
- mov di,offset rom_address
- mov ds,ax
-
- mov cx,EADDR_LEN
- rep movsb
-
- clc
- ret
-
- public print_parameters
- print_parameters:
- ret
-
- code ends
- end
-
- ;******************************************************************************
- ;
- ;* End of file: IBMTOKEN.ASM *
- ;
- ;******************************************************************************
-