; oditrpkt.ASM - Adapter provides Packet Driver interface over ODI ; ; (c) Copyright Daniel D. Lanciani 1991-1992. All rights reserved. ; ; This unmodified source file and its 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. ; ; Daniel D. Lanciani 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. ; ; This source has been modifyed by Ben James to provide Token-Ring_SNAP to ; Ethernet class 1 packet conversion. This source was modified using ; computers belonging to Oklahoma State University - Computer Center - ; Communications Department. I release it under the same conditions as ; the origional. ; version equ 1 ; for driver_info iftype equ 71 ; for driver_info/access_type nhand equ 8 ; max active handles mmatch equ 8 ; max length of header match mmulti equ 8 ; max multicast addresses pkvec equ 61h ; default control vector xbsize equ 4096 ; max receive frame size stksw equ 1 ; switch stacks in upcall nopid equ 1 ; use prescan/default instead of pid defstk equ 1 ; use default instead of prescan ;debug equ 1 headersize equ 24 send_buf_swap equ 1 GET_STACK_CONFIGURATION equ 0 GET_STACK_STATISTICS equ 1 ;BIND_TO_MLID equ 2 ;UNBIND_FROM_MLID equ 3 ;INFORM_MLID_DEREGISTERED equ 4 LSLERR_OUT_OF_RESOURCES equ 8001h ifndef nopid StackInfoStruc Struc StackNamePtr dd 0 StackReceiveHandler dd 0 StackControlHandler dd 0 StackInfoStruc ends endif ProtocolConfigStructure struc PConfigTableMajorVer db 1 PConfigTableMinorVer db 0 PProtocolLongName db 8, 'ODITRPKT', 0 PProtocolShortName db 5, 'TCPIP',0 PProtocolMajorVer db 1 PProtocolMinorVer db 0 PConfigTableReserved db 16 dup (0) ProtocolConfigStructure ends ProtocolStatStructure struc PStatTableMajorVer db 1 PStatTableMinorVer db 0 PNumGenericCounters dw 3 PValidCounterMask dd 111b PTotalTxPackets dw 2 dup (0) PTotalRxPackets dw 2 dup (0) PIgnoredRxPackets dw 2 dup (0) PNumCustomCounters dw 0 ProtocolStatStructure ends hinfo struc ; per-handle data nmatch dw -1 ; header match length match db mmatch dup (?) ; header match bytes recvo dw ? ; receiver offset recvs dw ? ; receiver segment hinfo ends CODE segment word public 'CODE' assume cs:CODE, ds:CODE, es:nothing, ss:CODE org 100h prog_stack label byte at100h: jmp start copyright db 13, 10, 'ODITRPKT 1.0 BETA 9', 13, 10 db '(c) Copyright Daniel Lanciani 1991-1992. All rights reserved.' db 13, 10, 'This software is provided with NO WARRANTY.', 13, 10 db 'This version of ODIPKT 1.3 has been modified by Ben James, OSU-UCC-DataComm.', 13, 10 db 'This driver does ODI Token-Ring_SNAP to Ethernet Class 1 Packet conversion.', 13, 10 db '$' myname db 'ODITRPKT B-9', 0 ; for driver_info class db 1 ; for driver_info xbusy db 0 ; receive buffer busy cmap db 0 ; class mapping flag ifdef stksw inhere db 0 ; on switched stack endif align 2 savpko dw 0 ; saved vector offset savpks dw 0 ; saved vector segment psup dd 0 ; LSL protocol support entry gsup dd 0 ; LSL general support entry control dd 0 ; MLID control entry config dd 0 ; MLID configuration table asup dw 0, 0 ; for as_send_pkt board dw 0 ; logical board number myvec dw 4 * pkvec ; 4 * my vector ifndef nopid stackid dw 0 ; stackid from LSL endif pconfig ProtocolConfigStructure <> pstats ProtocolStatStructure <> alen dw 6 ; address length off dw 12 ; header offset for match fmin dw 60 ; minimum frame size eth_min dw 60 ; ethernet min pkt size tok_min dw 28 ; * rmode dw 3 ; current receiver mode rmmap dw 0, 1, 5, 7, 7, 15 nmulti dw 0 ; number of multicast addresses mtab db mmulti * 6 dup (?) htab hinfo nhand dup (<>) ; the handle table htabe label byte stab dw 14 dup (0) ; for get_statistics ptab db 1, 9, 14, 6 ; for get_parameters dw 1514, mmulti * 6, 0, 0, 0 sECB db 52 dup (0) ; transmit ECB ifdef send_buf_swap sb db xbsize dup (?) ; Internal buffer for send buffer endif rECB db 52 dup (0) ; receive ECB xb db xbsize dup (?) ; receive buffer upcall proc far transcom: push ds push bp mov ax, cs mov ds, ax mov ax, asup or ax, asup + 2 jz trans1 mov ax, es:8[si] and ax, ax jz trans2 mov ax, 12 add stab + 20, 1 adc stab + 22, 0 mov word ptr sECB + 20, 0800 ; ProtocolID trans2: les di, es:46[si] call dword ptr asup mov cs:asup, 0 mov cs:asup + 2, 0 trans1: pop bp pop ds ret recvcom: cli cmp cs:xbusy, 0 jz havebuf jmp nobuf havebuf: mov dx, ds cld push di mov cx, 4[di] ;DataLookAheadPtr sub cx, [di] ;MediaHeaderPtr mov si, cs ; \ mov es, si ; > cs mov ds, si ; / rcvna1: mov si, offset rECB mov word ptr 46[si], offset xb ; Fragment0Address add word ptr 46[si], cx mov word ptr 50[si], xbsize ; Fragment0Length sub word ptr 50[si], cx mov ds, dx lds si, [di] ; media header ptr ?? mov di, offset xb rcvna2: rep movsb rcvna5: mov si, offset rECB pop di mov ds, dx xor ax, ax mov cs:xbusy, 1 ret nobuf2: pop di mov ds, dx nobuf: mov ax, 8001h add cs:stab + 16, 1 adc cs:stab + 18, 0 and ax, ax ret recvcom2: push bp push ds push es push si mov ax, cs mov ds, ax cld cli ifdef stksw cmp inhere, 0 jz notbusy add stab + 16, 1 adc stab + 18, 0 jmp busy notbusy: inc inhere mov bx, ss mov cx, sp mov ss, ax mov sp, offset prog_stack push bx push cx endif push ax mov cx, es:42[si] add cx, es:46[si] mov si, offset xb add si, 2 ; Offset for FC (Frame Control) ; add si, 54 ;low 54 mov ax, 0 mov ah, byte ptr es:12[si] ;get type field or rif indicator push cx test byte ptr es:6[si], 80h jnz Calc_rif mov ax, 0 jmp norif_with_SNAP rarp_arp: mov byte ptr es:15[di], 01h jmp not_rarp_arp Calc_rif: sub byte ptr es:6[si], 80h ;try to get rid of 9 ; This group gives you the ammount to offset mov cl, 3 ; shl ah, cl ; mov cl, 3 ; shr ah, cl ; mov al, ah ; mov ah, 0 ; Now rif size = ax - 2 norif_with_SNAP: add ax, 6 ; LLC + SNAP - type push di mov di, si add di, ax ; adjust for RIF etc mov cx, word ptr es:8[di] ; move type from SNAP mov word ptr es:12[si], cx ; to end of header ; move addresses mov cx, word ptr es:10[si] ; 1st word [dest] mov word ptr es:10[di],cx ; mov cx, word ptr es:8[si] ; 2nd word mov word ptr es:8[di], cx ; mov cx, word ptr es:6[si] ; 3rd word mov word ptr es:6[di], cx ; mov cx, word ptr es:4[si] ; 4th word [source] mov word ptr es:4[di], cx ; mov cx, word ptr es:2[si] ; 5th word mov word ptr es:2[di], cx ; mov cx, word ptr es:[si] ; 6th word mov word ptr es:[di], cx ; cmp word ptr es:12[di], 0608h ; If arp change Hardware Type to ethernet jz rarp_arp cmp word ptr es:12[di], 3580h ; If arp change Hardware Type to ethernet jz rarp_arp not_rarp_arp: pop di pop cx add si, ax ; adjust pointer for RIF etc pop ax sub cx, si cmp cx, eth_min jnc enuf mov cx, eth_min enuf: push es push si ;pointer to lower level push cx add stab, 1 adc stab + 2, 0 add stab + 8, cx adc stab + 10, 0 mov bx, offset htab recv1: mov cx, [bx].nmatch cmp cx, -1 jz recv5 ; if cx= -1 no more types jcxz recv2 ; if cx=0 match types mov di, si add di, off lea si, [bx].match ; load si with ptr to type in hinfo repe cmpsb ; compare the types jnz recv5 recv2: pop cx ; else if type found push cx push bx xor ax, ax call dword ptr [bx].recvo ; call recever pop bx cld mov ax, es or ax, di jz recv7 pop cx pop si pop ds push ds push si push cx push di shr cx, 1 rep movsw jnc recv3 movsb recv3: pop si pop cx push cx mov ax, es mov ds, ax push bx noararp: mov ax, 1 call dword ptr cs:[bx].recvo pop bx cld cli mov ax, cs mov ds, ax recv5: pop cx pop si pop es add bx, size hinfo cmp bx, offset htabe jnc recv6 ; no carry push es push si push cx jmp recv1 recv7: cli mov ax, cs mov ds, ax add stab + 24, 1 adc stab + 26, 0 jmp short recv5 recv6: ifdef stksw pop cx pop bx mov sp, cx mov ss, bx dec inhere endif busy: mov xbusy, 0 pop si pop es pop ds pop bp ret pcont: cmp bx, GET_STACK_CONFIGURATION jne pcont1 ; if not mov si, offset cs:pconfig xor ax, ax ret pcont1: cmp bx, GET_STACK_STATISTICS jne pcont2 ; if not mov si, offset cs:pstats xor ax, ax ret pcont2: mov ax, LSLERR_OUT_OF_RESOURCES or ax, ax ret nofunc: mov dh, 11 jmp bad upcall endp driver_info: pop bx mov bx, cs mov ds, bx mov bx, version mov ch, class mov dx, iftype xor cl, cl mov si, offset myname mov al, 6 jmp good1 access_type: pop bx push ds push cs pop ds cmp al, class jz access_type1 mov dh, 2 ; Error No Class jmp short access_type5 access_type1: cmp bx, iftype ; bx = if_type / iftype = 71 jz access_type7 cmp bx, -1 ; bx = if_type jz access_type7 ; mov dh, 3 ; Error No Type ; jmp short access_type5 access_type7: and dl, dl jz access_type2 mov dh, 4 ; Error No Number jmp short access_type5 access_type2: cmp cx, mmatch + 1 jc access_type3 mov dh, 14 ; Error Bad Address jmp short access_type5 access_type3: mov bx, offset htab access_type4: cmp [bx].nmatch, -1 jz access_type6 add bx, size hinfo cmp bx, offset htabe jc access_type4 mov dh, 9 ; Error No Space access_type5: pop ds jmp bad1 access_type6: mov [bx].nmatch, cx ; cx = type_length mov [bx].recvo, di ; \ Receiver offset mov [bx].recvs, es ; / segment or vice/versa mov di, ds mov es, di lea di, [bx].match pop ds rep movsb mov ax, bx jmp good1 release_type: pop bx mov cs:[bx].nmatch, -1 jmp good1 send_pkt: sti push ds mov bx, ds mov dx, cs mov ds, dx send_pkt1: cmp word ptr 8 + sECB, 0 ; status jg send_pkt1 mov word ptr 8 + sECB, 1 ; status add stab + 4, 1 adc stab + 6, 0 add stab + 12, cx adc stab + 14, 0 mov es, bx ifdef send_buf_swap mov di, offset sb push cx push bx push si loop_1: cmp cx, 0 jl done mov bx, word ptr es:[si] mov word ptr cs:[di], bx add si, 2 add di, 2 sub cx, 2 jmp loop_1 done: mov cx, cs mov es, cx pop si pop bx pop cx mov di, offset sb mov word ptr sECB + 48, cs ; Fragment0address LW mov es, bx else mov word ptr sECB + 48, bx ; Fragment0address LW endif push cx mov cx, word ptr es:12[si] mov word ptr sECB + 20, cx ; ProtocolID ifndef nopid mov cx, stackid endif mov word ptr sECB + 14, cx ; StackID mov cx, word ptr es:0[si] mov word ptr sECB + 24, cx ; Immediate address mov cx, word ptr es:2[si] mov word ptr sECB + 26, cx mov cx, word ptr es:4[si] mov word ptr sECB + 28, cx ; ***************** pop cx cmp word ptr es:12[si], 0608h ; if arp jz s_rarp_arp cmp word ptr es:12[si], 3580h ; if arp jz s_rarp_arp not_arp_send: ifdef send_buf_swap add di, 14 else add si, 14 endif sub cx, 14 send_pkt4: mov word ptr sECB + 42, cx ; Data Length ifdef send_buf_swap mov word ptr sECB + 46, di ; Fragment0Address else mov word ptr sECB + 46, si ; Fragment0Address endif mov word ptr sECB + 50, cx ; Fragment0Legnth mov si, offset sECB ifdef send_buf_swap push cx mov cx, cs mov es, cx pop cx else mov es, dx endif mov bx, 12 ; Send Packet call psup sti send_pkt2: cmp word ptr 8 + sECB, 0 ; Status jg send_pkt2 jnz send_pkt3 pop ds jmp good send_pkt3: add stab + 20, 1 ; Stats adc stab + 22, 0 pop ds mov dh, 12 jmp bad s_rarp_arp: mov byte ptr es:15[si], 06h ; is arp sub cx, 18 ; Reduce size for arp jmp not_arp_send terminate: push ds mov ax, cs mov ds, ax mov cx, nmulti jcxz terminate2 mov si, offset mtab terminate1: push si push cx mov ax, cs mov es, ax mov ax, board mov bx, 3 call control pop cx pop si add si, alen loop terminate1 terminate2: xor ax, ax mov es, ax mov bx, myvec mov ax, savpko mov es:[bx], ax mov ax, savpks mov es:2[bx], ax mov ax, board ifdef defstk mov bx, 9 else mov bx, 11 endif call psup ifndef nopid mov ax, stackid mov bx, 22 mov cx, board call psup mov ax, stackid mov bx, 7 call psup endif mov ax, cs mov es, ax mov ah, 49h int 21h pop ds jmp good get_address: cmp cx, cs:alen jnc get_address1 mov dh, 9 jmp bad get_address1: push ds lds si, cs:config add si, 28+6 mov cx, cs:alen sub si, cx rep movsb pop ds mov cx, cs:alen jmp good reset_interface: mov dh, 15 jmp bad get_parameters: mov di, cs mov es, di mov di, offset ptab jmp good set_rcv_mode: mov bx, cx dec bx cmp bx, 6 jnc set_rcv_mode1 shl bx, 1 push cx mov ax, cs:rmmap[bx] mov bx, 4 mov cx, -1 call cs:control pop cx ; jnz set_rcv_mode1 ; XXX no longer supported by ODI mov cs:rmode, cx jmp good set_rcv_mode1: mov dh, 8 jmp bad get_rcv_mode: mov ax, cs:rmode jmp good set_multicast_list: mov ax, cx xor dx, dx mov bx, cs:alen div bx and dx, dx jz set_multicast_list1 mov dh, 14 jmp bad set_multicast_list1: cmp ax, mmulti + 1 jc set_multicast_list6 mov dh, 9 jmp bad set_multicast_list6: push ds push cx push ax push es push di mov ax, cs mov ds, ax mov cx, nmulti jcxz set_multicast_list3 mov si, offset mtab set_multicast_list2: push si push cx mov ax, cs mov es, ax mov ax, board mov bx, 3 call control pop cx pop si add si, alen loop set_multicast_list2 set_multicast_list3: pop si pop ds pop ax pop cx mov bx, cs mov es, bx mov di, offset mtab cld rep movsb mov bx, cs mov ds, bx mov nmulti, ax mov cx, ax jcxz set_multicast_list5 mov si, offset mtab set_multicast_list4: push si push cx mov ax, cs mov es, ax mov ax, board mov bx, 2 call control pop cx pop si add si, alen loop set_multicast_list4 set_multicast_list5: pop ds jmp good get_multicast_list: mov di, cs mov es, di mov di, offset mtab mov ax, cs:nmulti mov cx, cs:alen mul cx mov cx, ax jmp good get_statistics: mov si, cs mov ds, si mov si, offset stab jmp good set_address: mov dh, 13 jmp bad funcs dw nofunc dw driver_info dw access_type dw release_type dw send_pkt dw terminate dw get_address dw reset_interface dw nofunc dw nofunc dw get_parameters dw nofunc dw nofunc dw nofunc dw nofunc dw nofunc dw nofunc dw nofunc dw nofunc dw nofunc dw set_rcv_mode dw get_rcv_mode dw set_multicast_list dw get_multicast_list dw get_statistics dw set_address nfuncs equ ($ - offset funcs) / 2 intpk proc far jmp short dopk nop sig db 'PKT DRVR', 0 dopk: cli cld push bx cmp ah, nfuncs jc dopk1 jmp nofunc dopk1: mov bl, ah xor bh, bh shl bx, 1 jmp cs:funcs[bx] bad: pop bx bad1: stc sti ret 2 good: pop bx good1: clc sti ret 2 intpk endp number0: call number jmp nothex number: xor ax, ax mov cx, -1 number1: cmp byte ptr [bx], '0' jc number2 cmp byte ptr [bx], '9' + 1 jnc number2 xor cx, cx mov dx, 10 mul dx mov dl, byte ptr [bx] sub dl, '0' xor dh, dh add ax, dx inc bx jmp short number1 number2: add cx, 1 ret calcvec: xor ax, ax call calcloop jz pexit mov cl, 4 shl al, cl mov ah, al call calcloop1 add al, ah mov cl, 4 mul cl mov myvec, ax xor cx, cx ret calcloop: cmp byte ptr [bx], '0' jne number0 inc bx cmp byte ptr [bx], 'x' jne start0 ;error calcloop1: inc bx cmp byte ptr [bx], '0' jb start0 ;error cmp byte ptr [bx], '9' ja letterhex mov al, byte ptr [bx] sub al, '0' ret letterhex: cmp byte ptr [bx], 'f' ja tryupp cmp byte ptr [bx], 'a' jb tryupp mov al, byte ptr [bx] sub al, 'a'-10 ret tryupp: cmp byte ptr [bx], 'F' ja start0 ; error cmp byte ptr [bx], 'A' jb start0 ; error mov al, byte ptr [bx] sub al, 'A'-10 ret pexit: mov ah, 9 int 21h int 20h start: mov ax, cs mov ds, ax cld mov dx, offset copyright mov ah, 9 int 21h mov bx, 81h call space call number jc start0 sub ax, 1 mov board, ax call space ; call number call calcvec jz start0 nothex: jc start0 add ax, ax add ax, ax mov myvec, ax start0: xor ax, ax mov es, ax mov bx, myvec les di, es:[bx] add di, 3 mov si, offset sig mov cx, 9 repe cmpsb jnz start1 mov dx, offset already mov ah, 9 int 21h int 20h start1: xor ax, ax mov es, ax xor bx, bx xor dx, dx mov ah, 0c0h start11: push ax int 2fh cmp al, 0ffh pop ax jz start13 start12: inc ah jnz start11 mov dx, offset nolsl jmp pexit start13: mov ax, dx or ax, bx jz start12 mov di, si mov si, offset lslname cld mov cx, 8 repe cmpsb jz start14 xor bx, bx xor dx, dx jmp start12 start14: mov word ptr psup, bx mov word ptr psup + 2, dx mov si, cs mov es, si mov si, offset psup mov bx, 2 call psup mov ax, word ptr gsup or ax, word ptr gsup + 2 jnz start2 mov dx, offset lslfail jmp pexit start2: mov bx, 18 mov ax, board call psup jz start3 mov dx, offset nocont jmp pexit start3: mov word ptr control, si mov word ptr control + 2, es mov ax, board xor bx, bx call control jz start4 mov dx, offset noconf jmp pexit start4: mov word ptr config, si mov word ptr config + 2, es mov al, es:114[si] xor ah, ah cmp al, 8 jnc noloirq add ax, 8 jmp short haveirq noloirq: cmp al, 16 jnc noirq add ax, 70h - 8 haveirq: mov word ptr ptab + 12, ax noirq: mov ax, es:60[si] cmp ax, 4 jz use_TR_SNAP cmp ax, 11 jz istok cmp ax, 3 jz will_not_support cmp ax, 5 jz will_not_support cmp ax, 10 jz will_not_support cmp ax, 7 jz will_not_support cmp ax, 15 jz will_not_support cmp ax, 16 jz will_not_support cmp ax, 14 will_not_support: mov dx, offset not_sup jmp pexit use_TR_SNAP: mov dx, offset tok_not_sup jmp pexit istok: mov dx, offset t_tok mov ax, es:40[si] ; Max size from MLID config Table add ax, 14 cmp ax, xbsize jc istok1 mov ax, xbsize istok1: mov word ptr ptab + 4, ax mov class, 1 mov fmin, 14 jmp short gottype gottype: mov ah, 9 int 21h mov rinfo, offset recvcom mov rinfo + 2, cs mov rinfo + 4, offset pcont mov rinfo + 6, cs mov si, cs mov es, si mov si, offset rinfo mov ax, board ifdef defstk mov bx, 8 else mov bx, 10 endif call psup ifdef nopid jz start5 else jz startb endif mov dx, offset rfail jmp pexit ifndef nopid startb: mov rinfo, offset sname mov rinfo + 2, cs mov rinfo + 4, offset recvcom mov rinfo + 6, cs mov rinfo + 8, offset pcont mov rinfo + 10, cs mov si, cs mov es, si mov si, offset rinfo mov ax, board mov bx, 6 call psup jz start51 mov dx, offset rfail jmp pexit start51: mov stackid, bx mov ax, bx mov bx, 21 mov cx, board call psup jz start5 mov ax, stackid mov bx, 7 call psup jz start5 mov dx, offset bfail jmp pexit endif start5: mov word ptr sECB + 10, offset transcom ; Call Transcom when transmit complete mov word ptr sECB + 12, cs ; MW ; Also ptr to transcom mov word ptr sECB + 14, -1 ; stack ID mov ax, board ; Board # mov word ptr sECB + 22, ax ; Board # mov word ptr sECB + 44, 1 ; Fragment0Count mov word ptr sECB + 48, cs ; Fragment0Address LW mov word ptr rECB + 10, offset recvcom2 ; Call Recvcom2 when recieve complete mov word ptr rECB + 12, cs ; mov word ptr rECB + 14, -1 ; stack id mov ax, board ; Board # mov word ptr rECB + 22, ax ; Board # mov word ptr rECB + 44, 1 ; Fragment0Count mov word ptr rECB + 48, cs ; Fragment0Address LW xor ax, ax mov es, ax pushf cli mov bx, myvec mov ax, es:[bx] mov savpko, ax mov ax, es:2[bx] mov savpks, ax mov es:[bx], offset intpk mov es:2[bx], cs popf mov dx, offset goodins mov ah, 9 int 21h mov es, ds:[2ch] mov ah, 49h int 21h mov word ptr ds:[2ch], 0 mov cx, 5 xor bx, bx cloop: mov ah, 3eh int 21h inc bx loop cloop mov dx, offset start int 27h space: cmp byte ptr [bx], ' ' jz space1 cmp byte ptr [bx], 9 jz space1 ret space1: inc bx jmp short space ifdef nopid rinfo dw 4 dup (0) else sname db 8, 'ODITRPKT', 0 rinfo dw 6 dup (0) bfail db 'Failed to bind protocol stack', 13, 10, '$' endif lslname db 'LINKSUP$' already db 'A driver is already installed at this vector.', 13, 10, '$' t_tok db 'Token-Ring_Snap using ethernet framing, class 1', 13, 10, '$' goodins db 'ODITRPKT is installed and ready.', 13, 10, 10, '$' nolsl db 'The Link Support Layer is not loaded.', 13, 10, '$' lslfail db 'The Link Support Layer failed to init.', 13, 10, '$' nocont db 'Cannot get MLID control entry', 13, 10, '$' noconf db 'Cannot get MLID configuration', 13, 10, '$' rfail db 'Failed to register protocol stack', 13, 10, '$' not_sup db 'That Frame type is not supported by this driver. ', 13, 10, db 'This driver only supports binding to Token-Ring_SNAP. (Initialization Failed) ', 13, 10, 10, '$' db 'ODIPKT.COM will support that board. ', 13, 10, 10, '$' tok_not_sup db 'This driver only supports binding to Token-Ring_SNAP. (Initialization Failed) ', 13, 10, 10, '$' CODE ends end at100h