!************************************************************************** !* !* Network driver interface for netboot bootrom !* !* Module: ndis.S !* Purpose: NDIS driver to UNDI interface !* Entries: drv_entry, mac_bind !* !************************************************************************** !* !* Copyright (C) 1998-2003 Gero Kuhlmann !* !* This program is free software; you can redistribute it and/or modify !* it under the terms of the GNU General Public License as published by !* the Free Software Foundation; either version 2 of the License, or !* any later version. !* !* This program is distributed in the hope that it will be useful, !* but WITHOUT ANY WARRANTY; without even the implied warranty of !* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !* GNU General Public License for more details. !* !* You should have received a copy of the GNU General Public License !* along with this program; if not, write to the Free Software !* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. !* !* $Id: ndis.S,v 1.7 2003/03/09 00:43:07 gkminix Exp $ !* ! !************************************************************************** ! ! Include assembler macros: ! #include #include #include #include #include #include #include "ndispriv.inc" ! !************************************************************************** ! ! If all features are required, we dont have to specify everything on ! the CPP command line. ! #ifdef NEEDALL # ifndef NEEDMCAST # define NEEDMCAST # endif # ifndef NEEDSETADDR # define NEEDSETADDR # endif # ifndef NEEDSTAT # define NEEDSTAT # endif #endif ! !************************************************************************** ! ! Definition of service flags. See NDIS-2.0 specification for further ! explanation. ! #ifdef NEEDMCAST FLAGS_MCAST equ %0000000000000010 #else FLAGS_MCAST equ %0000000000000000 #endif #ifdef NEEDSETADDR FLAGS_SETADDR equ %0000000000010000 #else FLAGS_SETADDR equ %0000000000000000 #endif FLAGS_STANDARD equ %0001110000001001 FLAGS_BITS equ %0000110000000000 FLAGS_MASK equ FLAGS_STANDARD + FLAGS_MCAST + FLAGS_SETADDR ! !************************************************************************** ! ! Values for initialization flag: ! FLAG_NOTSTART equ 0 ! UNDI driver not started FLAG_NOTINIT equ UNDI_STATE_STARTED ! device not initialized FLAG_INIT equ UNDI_STATE_INITIALIZED ! device is initialized FLAG_OPEN equ UNDI_STATE_OPENED ! device has been opened ! !************************************************************************** ! ! Transmit retry values: ! XMT_RETRY equ 10 ! retry 10 times XMT_WAIT equ 5 ! wait 50 ms between retries ! !************************************************************************** ! ! Definitions for multicast addresses: ! IP_MCAST_NET equ $E0 ! multicast IP addrs are D class HW_MCAST_1 equ $01 ! first byte of hardware mcast addr HW_MCAST_2 equ $00 ! second byte of hardware mcast addr HW_MCAST_3 equ $5E ! third byte of hardware mcast addr ! !************************************************************************** ! ! BSS segment: ! .bss ! start BSS segment extrn mac_cct ! far ptr to MAC CCT extrn irqnum ! hardware IRQ number .lcomm MacDS,2 ! MAC data segment .lcomm GenRequest,4 ! MAC entry point for general requests .lcomm SysRequest,4 ! MAC entry point for system requests .lcomm TransmitChain,4 ! MAC entry point to send a packet .lcomm TransferData,4 ! MAC entry point for data copy .lcomm IndicationOn,4 ! MAC entry point to control indica- .lcomm IndicationOff,4 ! taions (upcalls) from NDIS .lcomm reqconflg,2 ! general request confirmation flag .lcomm txconflg,2 ! transmit request confirmation flag .lcomm indstatus,2 ! last status indication .lcomm macflags,2 ! MAC flags .lcomm hwinfo,2 ! offset to hardware info structure .lcomm txbuf,TXBUF_MINSIZE ! transmit buffer descriptor .lcomm rdbuf,RDBUF_MINSIZE ! receive buffer descriptor .lcomm readsize,2 ! number of bytes in receive buffer .lcomm writebuf,ETH_FRAME_MAX ! send buffer .lcomm readbuf,ETH_FRAME_MAX ! receive buffer .lcomm initflag,1 ! flag to indicate if initialized .lcomm isrflag,1 ! flag set when inside ISR handler .lcomm intcount,1 ! number of interrupts received .lcomm rcvmode,2 ! current receive mode ! !************************************************************************** ! ! Data segment: ! .data ! Common Characteristics Table for bootrom interface according to NDIS ! version 2.0.1. drv_cct: .word CCT_SIZE ! length of structure .byte NDIS_MAJOR_VER ! major version of NDIS protocol .byte NDIS_MINOR_VER ! minor version of NDIS protocol .word 0 ! reserved .byte MAJOR_VER ! major version of module .byte MINOR_VER ! minor version of module .long MODFUNC_LOWER_BIND ! module function flags .ascii "NETBOOT$" ! module name .byte 0,0,0,0,0,0,0,0 ! pad name up to 16 bytes .byte PROT_TRANSPORT ! protocol level at upper boundary .byte TYPE_PRIVATE ! protocol type at upper boundary .byte PROT_MAC ! protocol level at lower boundary .byte TYPE_MAC ! protocol type at lower boundary .word MODID_PROT ! module ID of protocol .word 0 ! module data segment (set by init) .word SystemRequest ! far ptr to system request dispatch .word 0 ! entry point .long 0 ! far ptr to protocol SSC (not used) .long 0 ! far ptr to protocol SSS (not used) .long 0 ! far ptr to protocol UDT (not used) .word drv_ldt ! far ptr to protocol lower dispatch .word 0 ! table .long 0,0 ! reserved ! Protocol lower dispatch table according to NDIS version 2.0.1 specifi- ! cation. drv_ldt: .word drv_cct ! far back ptr to CCT .word 0 .long PROT_IF_LSAP_LLC ! protocol flags .word RequestConfirm ! far ptr to RequestConfirm .word 0 .word TransmitConfirm ! far ptr to TransmitConfirm .word 0 .word ReceiveLookahead ! far ptr to ReceiveLookahead .word 0 .word IndicationComplete ! far ptr to IndicationComplete .word 0 .word ReceiveChain ! far ptr to ReceiveChain .word 0 .word StatusIndication ! far ptr to StatusIndication .word 0 ! Name of network protocol supported by this driver interface prtnam: .asciz "DIX+802.3" ! bootrom requires standard ethernet prtend: ! !************************************************************************** ! ! Start code segment. ! .text public drv_entry ! define entry points public mac_bind ! External variables in code space extrn datseg ! External routines for interrupt handling extrn intstart extrn intstop extrn intset extrn intreset extrn dohwint extrn endhwint ! External routines in general network driver inteface library extrn gethwinfo extrn setmaster extrn wait10ms ! !************************************************************************** ! ! Bind us to the MAC. This will be called by the general network driver ! initialization routine. We cant do it at PXE_UNDI_STARTUP because ! some MACs set the hardware interrupt after binding, which is too late. ! Input: none ! Output: Carry flag set if error ! Registers changed: AX, BX ! mac_bind: ! First we have to set all the pointers in the drivers CCT and LDT. push es mov ax,cs mov bx,ds mov word ptr [drv_cct + CCT_MODULE_DS],bx mov word ptr [drv_cct + CCT_SYSREQ + 2],ax mov word ptr [drv_cct + CCT_LDT + 2],bx mov word ptr [drv_ldt + PROTLDT_CCT + 2],bx mov word ptr [drv_ldt + PROTLDT_REQ_CONFIRM + 2],ax mov word ptr [drv_ldt + PROTLDT_TX_CONFIRM + 2],ax mov word ptr [drv_ldt + PROTLDT_RX_LAH + 2],ax mov word ptr [drv_ldt + PROTLDT_IND_COMPLETE + 2],ax mov word ptr [drv_ldt + PROTLDT_RX_CHAIN + 2],ax mov word ptr [drv_ldt + PROTLDT_STATUS + 2],ax ! Check that the MAC registered with our protocol manager les bx,[mac_cct] mov ax,es or ax,bx jz bind8 ! Now call MAC to request a bind to our module #ifdef IS186 push ds ! push far pointer to protocol CCT push #drv_cct push ds ! push far pointer to MAC CCT pointer push #mac_cct push #0 ! push pad word push #NDIS_BIND ! push bind opcode #else push ds ! push far pointer to protocol CCT mov ax,#drv_cct push ax push ds ! push far pointer to MAC CCT pointer mov ax,#mac_cct push ax xor ax,ax ! push pad word push ax mov ax,#NDIS_BIND ! push bind opcode push ax #endif seg es push word ptr [bx + CCT_MODULE_DS] seg es call far ptr [bx + CCT_SYSREQ] ! call MAC to bind to us or ax,ax jz bind9 bind8: stc bind9: pop es ret ! !************************************************************************** ! ! PXE API entry point. Since we get called by the general network driver ! interface API entry which already checked if the function number is for ! us, we dont have to do that again here. We can safely assume that the ! function number is always correct. Also, the general network driver ! interface API already saved all registers for us. ! Input: ES:DI - pointer to parameter structure ! BX - function number ! Output: AX - error code ! Registers changed: AX, BX, CX, DX, SI, DI, BP, DS, ES ! drv_entry: #if defined(IS386) || defined(IS286) # ifdef IS386 mov eax,cr0 # else smsw ax # endif test ax,#$0001 ! check protected mode flag jz entry1 # ifdef IS386 pushfd pop eax ! check virtual-8086 mode flag test eax,#$00020000 jnz entry1 ! we can continue in virtual-8086 mode # endif ! packet driver interface not mov ax,#PXENV_STATUS_PMODE ! available in protected mode ret #endif entry1: seg cs mov ds,[datseg] shl bx,#1 ! compute offset into jump table seg cs jmp near ptr jmptab[bx] ! call function handler ! !************************************************************************** ! ! Function table ! jmptab: .word pxe_start_undi ! start UNDI interface .word pxe_startup ! startup driver .word pxe_cleanup ! cleanup driver .word pxe_initialize ! initialize driver .word pxe_reset_nic ! reset network interface .word pxe_shutdown ! shutdown driver .word pxe_open ! open network driver .word pxe_close ! close network driver .word pxe_transmit ! transmit a packet #ifdef NEEDMCAST .word pxe_set_multicast ! set multicast address #else .word pxe_unsupported ! set multicast address #endif #ifdef NEEDSETADDR .word pxe_set_addr ! set station address #else .word pxe_unsupported ! set station address #endif .word pxe_set_filter ! set packet filter .word pxe_get_info ! get network driver information #ifdef NEEDSTAT .word pxe_get_stat ! get network statistics .word pxe_clear_stat ! clear statistics #else .word pxe_unsupported ! get network statistics .word pxe_unsupported ! clear statistics #endif .word pxe_unsupported ! initiate diagnostics .word pxe_force_int ! force receive interrupt #ifdef NEEDMCAST .word pxe_get_mcast_addr ! get multicast address #else .word pxe_unsupported ! get multicast address #endif .word pxe_get_nic_type ! get network interface driver type .word pxe_get_iface_info ! get interface info .word pxe_isr ! handle hardware interrupt .word pxe_stop_undi ! stop UNDI interface .word pxe_get_state ! get UNDI state ! !************************************************************************** ! ! Stub for unsupported functions ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX ! pxe_unsupported: mov ax,#PXENV_STATUS_UNSUPPORTED ret ! !************************************************************************** ! ! START_UNDI. This just saves the BIOS parameters passed to the bootrom ! and sets all interrupts required by the driver. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX, SI, DI, ES ! pxe_start_undi: seg es mov ax,[di + o_su_reg_ax] seg es mov bx,[di + o_su_reg_bx] call gethwinfo ! get hardware info structure mov [hwinfo],si call setmaster ! set bus master if necessary call intstart ! set interrupt vectors xor ax,ax ret ! !************************************************************************** ! ! STOP_UNDI. This restores the interrupt vectors. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX, SI, DI, ES ! pxe_stop_undi: mov ax,#PXENV_STATUS_FAILURE cmp byte ptr [initflag],#FLAG_NOTINIT ja pstop9 call closendis ! close NDIS driver interface call intstop ! restore interrupt vectors mov ax,#PXENV_STATUS_KEEP_UNDI jc pstop9 mov byte ptr [initflag],#FLAG_NOTSTART xor ax,ax pstop9: ret ! !************************************************************************** ! ! UNDI_STARTUP. Startup the NDIS driver interface. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX, SI, DI, ES ! pxe_startup: mov ax,#PXENV_STATUS_FAILURE cmp byte ptr [initflag],#FLAG_NOTSTART jne startA ! Check that the MAC uses standard ethernet headers les bx,[mac_cct] seg es les bx,[bx + CCT_SSC] lea di,[bx + MACSSC_TYPE_NAME] mov si,#prtnam mov cx,#prtend - prtnam repe cmpsb ! compare MAC type with required type je start1 start8: mov ax,#PXENV_STATUS_UNDI_NIC_INIT ! invalid NDIS driver startA: #ifdef IS386 jmp start9 #else jmp near start9 #endif ! Now check that the MAC uses correct parameters start1: seg es ! check MTU cmp word ptr [bx + MACSSC_FRAME_SIZE],#ETH_FRAME_MAX jb start8 seg es ! check MAC address size cmp word ptr [bx + MACSSC_ADDR_LEN],#ETH_ALEN jne start8 seg es mov ax,[bx + MACSSC_SF_1] ! save MAC flags mov [macflags],ax #ifdef NEEDMCAST test ax,#MAC_SF1_MULTICAST jz start8 ! check for multicast capability #endif #ifdef NEEDSETADDR test ax,#MAC_SF1_STAT_ADDR jz start8 ! check for settable station address #endif ! We are now bound to the MAC, so we can save all MAC entry points into ! static variables. Unfortunately, this is necessary as per the NDIS ! specification, but it just wastes precious memory space. les bx,[mac_cct] ! get pointer to MAC CCT seg es mov ax,[bx + CCT_MODULE_DS] ! save MAC data segment mov [MacDS],ax #ifdef IS386 seg es mov eax,[bx + CCT_SYSREQ] mov [SysRequest],eax #else seg es mov ax,[bx + CCT_SYSREQ + 0] mov word ptr [SysRequest + 0],ax seg es mov ax,[bx + CCT_SYSREQ + 2] mov word ptr [SysRequest + 2],ax #endif seg es les bx,[bx + CCT_UDT] ! get pointer to MAC UDT #ifdef IS386 seg es mov eax,[bx + MACUDT_REQUEST] mov [GenRequest],eax seg es mov eax,[bx + MACUDT_TX_CHAIN] mov [TransmitChain],eax seg es mov eax,[bx + MACUDT_TX_DATA] mov [TransferData],eax seg es mov eax,[bx + MACUDT_IND_ON] mov [IndicationOn],eax seg es mov eax,[bx + MACUDT_IND_OFF] mov [IndicationOff],eax #else seg es mov ax,[bx + MACUDT_REQUEST + 0] mov word ptr [GenRequest + 0],ax seg es mov ax,[bx + MACUDT_REQUEST + 2] mov word ptr [GenRequest + 2],ax seg es mov ax,[bx + MACUDT_TX_CHAIN + 0] mov word ptr [TransmitChain + 0],ax seg es mov ax,[bx + MACUDT_TX_CHAIN + 2] mov word ptr [TransmitChain + 2],ax seg es mov ax,[bx + MACUDT_TX_DATA + 0] mov word ptr [TransferData + 0],ax seg es mov ax,[bx + MACUDT_TX_DATA + 2] mov word ptr [TransferData + 2],ax seg es mov ax,[bx + MACUDT_IND_ON + 0] mov word ptr [IndicationOn + 0],ax seg es mov ax,[bx + MACUDT_IND_ON + 2] mov word ptr [IndicationOn + 2],ax seg es mov ax,[bx + MACUDT_IND_OFF + 0] mov word ptr [IndicationOff + 0],ax seg es mov ax,[bx + MACUDT_IND_OFF + 2] mov word ptr [IndicationOff + 2],ax #endif mov byte ptr [initflag],#FLAG_NOTINIT xor ax,ax start9: ret ! !************************************************************************** ! ! UNDI_CLEANUP. This will terminate the NDIS driver. Unfortunately NDIS ! drivers do not allow getting removed from memory. Therefore we simply ! close everything, unbind and then restore all interrupt vectors. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX ! pxe_cleanup: mov ax,#PXENV_STATUS_FAILURE cmp byte ptr [initflag],#FLAG_NOTINIT ja pclen9 call closendis ! first close all open connections call intset ! restore interrupts for NDIS driver mov ax,#PXENV_STATUS_KEEP_UNDI jc pclen8 #ifdef IS186 push ds push #drv_cct push #0 push #0 push #NDIS_UNBIND push MacDS #else push ds mov ax,#drv_cct push ax xor ax,ax push ax push ax mov ax,#NDIS_UNBIND push ax push [MacDS] #endif call far ptr [SysRequest] ! call MAC to unbind the protocol xor ax,ax pclen8: push ax call intreset ! restore interrupts pop ax mov byte ptr [initflag],#FLAG_NOTSTART pclen9: ret ! !************************************************************************** ! ! Initialize the NDIS driver interface. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX ! pxe_initialize: mov ax,#PXENV_STATUS_UNDI_ALREADY_INIT cmp byte ptr [initflag],#FLAG_NOTINIT ja pinit9 mov ax,#PXENV_STATUS_FAILURE jb pinit9 call resetndis ! reset MAC mov ax,#PXENV_STATUS_UNDI_PHY_INIT jc pinit9 xor dx,dx mov [rcvmode],dx call setrcvmode ! disable receiver mov ax,#PXENV_STATUS_UNDI_PHY_INIT jc pinit9 mov byte ptr [initflag],#FLAG_INIT xor ax,ax ! return without error pinit9: ret ! !************************************************************************** ! ! Shutdown the NDIS driver interface. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX ! pxe_shutdown: mov ax,#PXENV_STATUS_UNDI_NOT_INIT cmp byte ptr [initflag],#FLAG_NOTINIT jbe pshut9 mov byte ptr [initflag],#FLAG_NOTINIT xor dx,dx mov [rcvmode],dx call setrcvmode ! disable receiver call closendis ! close adapter mov byte ptr [initflag],#FLAG_NOTINIT xor ax,ax pshut9: ret ! !************************************************************************** ! ! Reset the NDIS driver and reinitialize the interface. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX, SI ! pxe_reset_nic: mov ax,#PXENV_STATUS_UNDI_NOT_INIT cmp byte ptr [initflag],#FLAG_NOTINIT jbe prst9 mov byte ptr [initflag],#FLAG_NOTINIT call resetndis ! reset the NDIS driver interface mov ax,#PXENV_STATUS_UNDI_PHY_INIT jc prst9 mov dx,[rcvmode] call setrcvmode ! restore receive mode #ifdef NEEDMCAST lea si,[di + o_ur_mcastbuf] call setmcast mov ax,#PXENV_STATUS_UNDI_MCAST jc prst9 ! reset the multicast address list #endif mov byte ptr [initflag],#FLAG_OPEN prst8: xor ax,ax ! return without error prst9: ret ! !************************************************************************** ! ! Open the network driver interface. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX, SI ! pxe_open: mov ax,#PXENV_STATUS_UNDI_NOT_INIT cmp byte ptr [initflag],#FLAG_INIT jne popen9 mov ax,#PXENV_STATUS_UNDI_ALREADY_OPEN cmp byte ptr [initflag],#FLAG_OPEN je popen9 call openndis ! open MAC interface mov ax,#PXENV_STATUS_FAILURE jc popen9 seg es mov dx,word ptr [di + o_uo_pktfilter] cmp dx,[rcvmode] je popen1 mov [rcvmode],dx call setrcvmode ! set receive mode packet filter mov ax,#PXENV_STATUS_FAILURE jc popen9 popen1: #ifdef NEEDMCAST lea si,[di + o_uo_mcastbuf] call setmcast ! set multicast address list mov ax,#PXENV_STATUS_UNDI_MCAST jc popen9 #endif mov byte ptr [initflag],#FLAG_OPEN xor ax,ax popen9: ret ! !************************************************************************** ! ! Close the network driver interface. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX ! pxe_close: mov ax,#PXENV_STATUS_UNDI_NOT_OPEN cmp byte ptr [initflag],#FLAG_OPEN jne pclos9 call closendis ! close MAC mov ax,#PXENV_STATUS_FAILURE jc pclos9 mov byte ptr [initflag],#FLAG_INIT xor ax,ax ! return without error pclos9: ret ! !************************************************************************** ! ! Transmit a packet ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX, SI, DI, BP, ES ! pxe_transmit: mov ax,#PXENV_STATUS_UNDI_NOT_OPEN cmp byte ptr [initflag],#FLAG_OPEN #ifdef IS386 jne near pxmitE #else je pxmit0 jmp near pxmitE #endif pxmit0: cld push ds push es mov ax,ds ! DS:BX - ptr to parameter structure mov es,ax ! ES:DI - ptr to send buffer mov bx,di mov di,#writebuf pop ds xor bp,bp ! BP - total size of send buffer ! First setup the MAC level header. If the protocol value in the parameter ! structure is 0, the upper layer has already filled in the MAC header. ! Otherwise, if the transmit flag is 0, we have to fill in the broadcast ! address for the destination address. Otherwise the hardware destination ! address can be found in the protocol structure. mov dl,byte ptr [bx + o_ut_protocol] or dl,dl jz pxmit4 pxmitA: mov cx,#ETH_ALEN / 2 cmp byte ptr [bx + o_ut_xmtflag],#UNDI_XMT_DESTADDR je pxmit1 mov ax,#$FFFF ! set destination address to broadcast rep stosw jmp pxmit2 pxmit1: push ds lds si,[bx + o_ut_dest_off] rep ! copy destination address into send movsw ! buffer pop ds pxmit2: push ds seg es lds si,[mac_cct] lds si,[si + CCT_SSC] #ifdef NEEDSETADDR lea si,[si + MACSSC_CUR_ADDR] #else lea si,[si + MACSSC_PERM_ADDR] #endif mov cx,#ETH_ALEN / 2 rep ! copy source address into send buffer movsw pop ds mov ax,#ETH_P_IP cmp dl,#UNDI_PROT_IP ! determine type of packet je pxmit3 mov ax,#ETH_P_ARP cmp dl,#UNDI_PROT_ARP je pxmit3 mov ax,#ETH_P_RARP pxmit3: xchg al,ah ! write packet type into MAC header stosw add bp,#ETH_HLEN ! adjust buffer size to MAC header size ! The parameter structure contains a couple of buffers. One of them is the ! so called immediate buffer. Copy it into the send buffer. pxmit4: lds bx,[bx + o_ut_tbd_off] mov cx,word ptr [bx + o_tbd_xmtlength] jcxz pxmit5 add bp,cx cmp bp,#ETH_FRAME_MAX ja pxmitF push ds lds si,[bx + o_tbd_xmt_off] shr cx,#1 rep movsw jnc pxmitB movsb pxmitB: pop ds ! Now copy all the different transmit buffers into the send buffer. pxmit5: mov dx,word ptr [bx + o_tbd_blocks] or dx,dx jz pxmit8 lea bx,[bx + o_tbd_datablock] pxmit6: mov cx,word ptr [bx + o_tbd_tdlength] jcxz pxmit7 add bp,cx cmp bp,#ETH_FRAME_MAX ja pxmitF push ds lds si,[bx + o_tbd_tdaddr] shr cx,#1 rep movsw jnc pxmitC movsb pxmitC: pop ds pxmit7: add bx,#datablk_size ! continue with next buffer dec dx jnz pxmit6 jmp pxmit8 ! Handle transmit errors pxmitF: pop ds jmp pxmitG ! We can now fillup the send buffer to the minimum size. pxmit8: cmp bp,#ETH_FRAME_MIN jae pxmit9 mov cx,#ETH_FRAME_MIN sub cx,bp xor al,al ! pad send buffer to minimum size rep stosb mov bp,#ETH_FRAME_MIN pxmit9: pop ds mov si,#writebuf ! Send the buffer using the MAC. For this, we have to first setup the ! frame buffer descriptor. This looks almost exactly like the UNDI ! send buffer structure. Unfortunately, because we have to insert the ! source and destination addresses, we cant simply pass the UNDI values ! to the NDIS driver, but have to use a temporary buffer and fill it using ! the code above. mov word ptr [txconflg],#NDISERR_QUEUED mov word ptr [txbuf + TXBUF_IMMED_LEN],#0 mov word ptr [txbuf + TXBUF_DATA_COUNT],#1 mov byte ptr [txbuf + TXBUF_DATA_BUFS + TXBUF_PTR_TYPE],#TXBUF_PTR_PHYSICAL mov word ptr [txbuf + TXBUF_DATA_BUFS + TXBUF_DATA_LEN],bp mov word ptr [txbuf + TXBUF_DATA_BUFS + TXBUF_DATA_PTR + 0],si mov word ptr [txbuf + TXBUF_DATA_BUFS + TXBUF_DATA_PTR + 2],ds mov cx,#XMT_RETRY pxmitJ: push cx #ifdef IS186 push #MODID_PROT ! push module ID for protocol push cs ! push request handle push ds ! push far ptr to txbuf descriptor push #txbuf push [MacDS] ! push MAC data segment #else mov ax,#MODID_PROT ! push module ID for protocol push ax push cs ! push request handle push ds ! push far ptr to txbuf descriptor mov ax,#txbuf push ax push [MacDS] ! push MAC data segment #endif call far ptr [TransmitChain] ! call MAC to transmit the buffer sti ! sti required due to sume buggy MACs pop cx pxmitK: cmp ax,#NDISERR_TRANSMIT ! check if transmit error jne pxmitH ! if we cant send the packet, retry it mov bx,#XMT_WAIT ! a couple of times, as the sender might call wait10ms ! just be busy right now loop pxmitJ jmp pxmitG pxmitH: cmp ax,#NDISERR_QUEUED ! poll until request processed jne pxmitD ! this is necessary because the UNDI mov ax,[txconflg] ! specification requires the transmit jmp pxmitK ! to block until the request finished pxmitD: or ax,ax jz pxmitE ! return on error pxmitG: mov ax,#PXENV_STATUS_FAILURE pxmitE: ret #ifdef NEEDMCAST ! !************************************************************************** ! ! Set multicast address list ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX, SI ! pxe_set_multicast: mov ax,#PXENV_STATUS_UNDI_NOT_OPEN cmp byte ptr [initflag],#FLAG_OPEN jne psetm9 lea si,[di + o_usma_mcastbuf] call setmcast ! set multicast address list mov ax,#PXENV_STATUS_UNDI_MCAST jmp near pfint2 psetm9: ret #endif #ifdef NEEDSETADDR ! !************************************************************************** ! ! Set station address ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX, SI ! pxe_set_addr: mov bl,[initflag] mov ax,#PXENV_STATUS_UNDI_ALREADY_OPEN cmp bl,#FLAG_OPEN ! UNDI should not be open yet je pseta9 mov ax,#PXENV_STATUS_UNDI_NOT_INIT cmp bl,#FLAG_INIT ! is UNDI initialized already? jne pseta9 lea si,[di + o_ussa_addr] call setaddr mov ax,#PXENV_STATUS_UNDI_INV_HWADDR jmp near pfint2 pseta9: ret #endif ! !************************************************************************** ! ! Set packet filter ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, DX ! pxe_set_filter: mov ax,#PXENV_STATUS_UNDI_NOT_OPEN cmp byte ptr [initflag],#FLAG_OPEN jne psetf9 seg es mov dx,word ptr [di + o_uo_pktfilter] cmp dx,[rcvmode] je psetf8 mov [rcvmode],dx call setrcvmode psetf8: jmp near pfint1 psetf9: ret ! !************************************************************************** ! ! Get information about network driver ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX, CX, SI ! pxe_get_info: mov ax,#PXENV_STATUS_UNDI_NOT_INIT cmp byte ptr [initflag],#FLAG_INIT jne pgeti9 cld push di push ds add di,#o_ugi_intnumber mov ax,[irqnum] ! get interrupt IRQ number stosw lds bx,[mac_cct] lds bx,[bx + CCT_SSC] mov ax,[bx + MACSSC_FRAME_SIZE] ! get MTU sub ax,#ETH_HLEN ! without MAC header stosw mov ax,#UNDI_TYPE_ETHER ! get ethernet hardware type stosw mov ax,#ETH_ALEN ! get hardware address length stosw #ifdef NEEDSETADDR lea si,[bx + MACSSC_CUR_ADDR] #else lea si,[bx + MACSSC_PERM_ADDR] #endif mov cx,#ETH_ALEN / 2 ! copy current hardware address rep movsw add di,#UNDI_ADDR_LEN - ETH_ALEN lea si,[bx + MACSSC_PERM_ADDR] mov cx,#ETH_ALEN / 2 ! copy default hardware address rep movsw pop ds pop di mov ax,#1 ! save size of send/receive queues seg es mov word ptr [di + o_ugi_rxbufcnt],ax seg es mov word ptr [di + o_ugi_txbufcnt],ax xor ax,ax pgeti9: ret #ifdef NEEDSTAT ! !************************************************************************** ! ! Read network driver statistics ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: (E)AX, DX ! pxe_get_stat: mov ax,#PXENV_STATUS_UNDI_NOT_INIT cmp byte ptr [initflag],#FLAG_INIT jne pgets9 call setstat ! update statistics mov ax,#PXENV_STATUS_FAILURE jc pgets9 push ds lds bx,[mac_cct] lds bx,[bx + CCT_SSS] ! get pointer to network statistics cli ! interrupts have to be disabled #ifdef IS386 mov eax,[bx + MACSSS_TX_FRAMES] sub eax,[bx + MACSSS_TX_HARDWARE] sub eax,[bx + MACSSS_TX_TIMEOUT] seg es mov [di + o_ugs_xmtgood],eax mov eax,[bx + MACSSS_RX_FRAMES] sub eax,[bx + MACSSS_RX_ERROR] seg es mov [di + o_ugs_rcvgood],eax mov eax,[bx + MACSSS_RX_DISCARDED] seg es mov [di + o_ugs_rcvreserr],eax mov eax,[bx + MACSSS_RX_CRC_FRAMES] seg es mov [di + o_ugs_rcvcrcerr],eax #else /* IS386 */ mov ax,word ptr [bx + MACSSS_TX_FRAMES + 0] mov dx,word ptr [bx + MACSSS_TX_FRAMES + 2] sub ax,word ptr [bx + MACSSS_TX_HARDWARE + 0] sbb dx,word ptr [bx + MACSSS_TX_HARDWARE + 2] sub ax,word ptr [bx + MACSSS_TX_TIMEOUT + 0] sbb dx,word ptr [bx + MACSSS_TX_TIMEOUT + 2] seg es mov word ptr [di + o_ugs_xmtgood + 0],ax seg es mov word ptr [di + o_ugs_xmtgood + 2],dx mov ax,word ptr [bx + MACSSS_RX_FRAMES + 0] mov dx,word ptr [bx + MACSSS_RX_FRAMES + 2] sub ax,word ptr [bx + MACSSS_RX_ERROR + 0] sbb dx,word ptr [bx + MACSSS_RX_ERROR + 2] seg es mov word ptr [di + o_ugs_rcvgood + 0],ax seg es mov word ptr [di + o_ugs_rcvgood + 2],dx mov ax,word ptr [bx + MACSSS_RX_DISCARDED + 0] mov dx,word ptr [bx + MACSSS_RX_DISCARDED + 2] seg es mov word ptr [di + o_ugs_rcvreserr + 0],ax seg es mov word ptr [di + o_ugs_rcvreserr + 2],dx mov ax,word ptr [bx + MACSSS_RX_CRC_FRAMES + 0] mov dx,word ptr [bx + MACSSS_RX_CRC_FRAMES + 2] seg es mov word ptr [di + o_ugs_rcvcrcerr + 0],ax seg es mov word ptr [di + o_ugs_rcvcrcerr + 2],dx #endif /* IS386 */ sti xor ax,ax ! return without error pgets9: ret #endif #ifdef NEEDSTAT ! !************************************************************************** ! ! Clear network driver statistics ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: (E)AX ! pxe_clear_stat: mov ax,#PXENV_STATUS_UNDI_NOT_INIT cmp byte ptr [initflag],#FLAG_INIT jne pfint9 call clrstat ! clear statistics jmp pfint1 #endif ! !************************************************************************** ! ! Force a hardware interrupt. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: (E)AX ! pxe_force_int: mov ax,#PXENV_STATUS_UNDI_NOT_OPEN cmp byte ptr [initflag],#FLAG_OPEN jne pfint9 call forceint pfint1: mov ax,#PXENV_STATUS_FAILURE pfint2: jc pfint9 pfint8: xor ax,ax pfint9: ret #ifdef NEEDMCAST ! !************************************************************************** ! ! Determine hardware multicast address fro IP multicast address. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, CX, SI, DI ! pxe_get_mcast_addr: lea bx,[di + o_ugma_inetaddr] seg es mov al,[bx] and al,#$F0 ! check that the IP address really is cmp al,#IP_MCAST_NET ! a multicast address mov ax,#PXENV_STATUS_UNDI_INV_HWADDR jne pgmca9 cld lea di,[di + o_ugma_hwaddr] mov ax,#HW_MCAST_2 * 256 + HW_MCAST_1 stosw mov al,#HW_MCAST_3 ! set hardware multicast for ethernet stosb ! devices seg es mov al,[bx + 1] and al,#$7F ! only 23 bits of the IP address will stosb ! be copied seg es mov ax,[bx + 2] stosw xor al,al ! return without error pgmca9: ret #endif ! !************************************************************************** ! ! Return NIC type information. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, CX, SI, DI ! pxe_get_nic_type: cld mov si,[hwinfo] mov cx,#getnic_size rep ! just copy the hardware info structure movsb ! into destination parameter structure xor ax,ax ret ! !************************************************************************** ! ! Return interface info. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: (E)AX, BX, CX, SI, DI ! pxe_get_iface_info: cld push ds lds bx,[mac_cct] lds bx,[bx + CCT_SSC] lea di,[di + o_ugii_ifacetype] lea si,[bx + MACSSC_TYPE_NAME] mov cx,#o_ugii_ifacelen rep movsb #ifdef IS386 mov eax,[bx + MACSSC_LINK_SPEED] stosd mov eax,[bx + MACSSC_SF_1] or eax,#FLAGS_BITS and eax,#FLAGS_MASK stosd xor ax,ax #else mov ax,[bx + MACSSC_LINK_SPEED + 0] stosw mov ax,[bx + MACSSC_LINK_SPEED + 2] stosw mov ax,[bx + MACSSC_SF_1] or ax,#FLAGS_BITS and ax,#FLAGS_MASK stosw xor ax,ax stosw #endif pop ds ret ! !************************************************************************** ! ! Handle hardware interrupt. Note that the low-level handling has already ! been done by the PXE entry dispatcher. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX, BX ! pxe_isr: ! Dont check for the initflag status. This will be done in the receiver ! routine. Otherwise, we would block the interrupt system on the NIC by ! not calling the NDIS driver hardware interrupt handler. seg es mov bx,word ptr [di + o_uisr_funcflag] cmp bx,#UNDI_ISR_IN_START je pisr1 pushf ! we have to disable interrupts cli ! here cmp bx,#UNDI_ISR_IN_PROCESS je pisr3 mov al,[isrflag] ! IN_GET_NEXT is only valid or al,al ! if following a IN_PROCESS jz pisr2 cmp bx,#UNDI_ISR_IN_GET_NEXT ! we only have one rx buffer so je pisr5 ! terminate ISR on IN_GET_NEXT pisr2: popf mov ax,#PXENV_STATUS_FAILURE pisr6: jmp near pisr9 ! Handle function UNDI_ISR_IN_START. It will let the NDIS driver handle ! the interrupt. pisr1: inc byte ptr [intcount] call dohwint mov ax,#UNDI_ISR_OUT_NOT_OURS jc pisrB mov ax,#UNDI_ISR_OUT_OURS pisrB: jmp pisr8 ! Handle function UNDI_ISR_IN_PROCESS. It returns the address of the receive ! buffer to the kernel. pisr3: mov al,#1 xchg al,[isrflag] ! check that we are not inside our or al,al ! own handler mov ax,#UNDI_ISR_OUT_BUSY jnz pisr7 mov ax,[readsize] or ax,ax ! check that we have something to jz pisr5 ! receive seg es mov word ptr [di + o_uisr_buflength],ax seg es mov word ptr [di + o_uisr_framelength],ax seg es mov word ptr [di + o_uisr_headerlength],#ETH_HLEN mov si,#readbuf seg es mov word ptr [di + o_uisr_frame + 0],si seg es mov word ptr [di + o_uisr_frame + 2],ds call getaddrtype seg es mov byte ptr [di + o_uisr_pkttype],bl mov ax,[si + ETH_ALEN * 2] xchg al,ah mov bx,#UNDI_PROT_IP cmp ax,#ETH_P_IP je pisr4 mov bx,#UNDI_PROT_ARP cmp ax,#ETH_P_ARP je pisr4 mov bx,#UNDI_PROT_RARP cmp ax,#ETH_P_RARP je pisr4 mov bx,#UNDI_PROT_OTHERS pisr4: seg es mov word ptr [di + o_uisr_prottype],bx mov ax,#UNDI_ISR_OUT_RECEIVE jmp pisr7 ! Terminate hardware interrupt processing. pisr5: cmp byte ptr [intcount],#0 je pisrA call endhwint pisrA: mov word ptr [readsize],#0 mov byte ptr [isrflag],#0 mov byte ptr [intcount],#0 mov ax,#UNDI_ISR_OUT_DONE ! terminate ISR handling pisr7: popf pisr8: seg es mov word ptr [di + o_uisr_funcflag],ax xor ax,ax pisr9: ret ! !************************************************************************** ! ! Return UNDI state. ! Input: ES:DI - pointer to parameter structure ! Output: AX - error code ! Registers changed: AX ! pxe_get_state: mov al,[initflag] seg es mov byte ptr [di + o_gs_state],al xor ax,ax ret ! !************************************************************************** ! ! Determine type of destination address ! Input: DS:SI - pointer to MAC header hardware address ! Output: BX - type of hardware address (UNDI_PKT_*) ! Registers changed: AX, BX ! getaddrtype: ! Check if the first bit of the hardware address is zero. If it is, the ! address has to be directed. mov bx,#UNDI_PKT_DIRECTED test byte ptr [si],#$01 jz getad9 ! Now check if we have a broadcast address. mov bx,#UNDI_PKT_BROADCAST if ETH_ALEN = 6 mov ax,[si + 0] and ax,[si + 2] and ax,[si + 4] inc ax else cld push cx mov cx,#ETH_ALEN mov ah,#$FF getad1: lodsb and ah,al loop getad1 pop cx sub si,#ETH_ALEN inc ah endif jz getad9 ! None of the conditions above applied, so we assume a multicast packet. #ifdef NEEDMCAST mov bx,#UNDI_PKT_MULTICAST #else mov bx,#UNDI_PKT_DIRECTED #endif getad9: ret ! !************************************************************************** ! ! Handle MAC general requests ! !************************************************************************** ! ! Reset NDIS driver interface. This will not change the packet filter, ! station address or open/close state of the MAC. ! Input: none ! Output: Carry flag set if error ! Registers changed: AX, BX, CX, DX ! resetndis: test word ptr [macflags],#MAC_SF1_RESET_MAC jz reset9 mov word ptr [indstatus],#NDIS_START_RESET mov ax,#NDIS_RESET_MAC xor bx,bx xor cx,cx xor dx,dx call dogenreq ! do reset request or ax,ax jz reset1 stc jmp reset9 ! Wait for the reset request to terminate reset1: cmp word ptr [indstatus],#NDIS_END_RESET jne reset1 xor ax,ax reset9: ret ! !************************************************************************** ! ! Open NDIS driver interface. ! Input: none ! Output: Carry flag set if error ! Registers changed: AX, BX, CX, DX ! openndis: test word ptr [macflags],#MAC_SF1_OPEN_CLOSE jz open9 mov ax,#NDIS_OPEN_ADAPTER open1: xor bx,bx open2: xor cx,cx xor dx,dx call dogenreq ! do reset request or ax,ax jz open9 open8: stc open9: ret ! !************************************************************************** ! ! Close NDIS driver interface. ! Input: none ! Output: Carry flag set if error ! Registers changed: AX, BX, CX, DX ! closendis: test word ptr [macflags],#MAC_SF1_OPEN_CLOSE jz open9 mov ax,#NDIS_CLOSE_ADAPTER jmp open1 ! !************************************************************************** ! ! Force a hardware interrupt. ! Input: none ! Output: Carry flag set if error ! Registers changed: AX, BX, CX, DX ! forceint: test word ptr [macflags],#MAC_SF1_INTERRUPT jz open8 mov ax,#NDIS_REQUEST_INT jmp open1 ! !************************************************************************** ! ! Set receive mode. UNDI filter values are the same as for NDIS. ! Input: DX - UNDI packet filter value ! Output: Carry flag set if error ! Registers changed: AX, BX, CX, DX ! setrcvmode: mov ax,#NDIS_SET_PKT_FLT mov bx,dx jmp open2 #ifdef NEEDSTAT ! !************************************************************************** ! ! Update network statistics ! Input: None ! Output: Carry flag set if error ! Registers changed: AX, BX, CX, DX ! setstat: mov ax,#NDIS_UPDATE_STATS jmp open1 #endif #ifdef NEEDSTAT ! !************************************************************************** ! ! Clear network statistics ! Input: None ! Output: Carry flag set if error ! Registers changed: AX, BX, CX, DX ! clrstat: mov ax,#NDIS_CLEAR_STATS jmp open1 #endif ! !************************************************************************** ! ! Let the MAC generate a hardware interrupt. ! Input: none ! Output: Carry flag set if error or unsupported ! Registers changed: AX, BX, CX, DX ! doint: test word ptr [macflags],#MAC_SF1_INTERRUPT jz open8 mov ax,#NDIS_REQUEST_INT jmp open1 #ifdef NEEDMCAST ! !************************************************************************** ! ! Set multicast addresses from UNDI address list. ! Input: ES:SI - pointer to UNDI multicast address structure ! Output: Carry flag set if error ! Registers changed: AX, BX, CX, DX, SI ! setmcast: ! First we have to delete the current multicast address list. push es les bx,[mac_cct] seg es les bx,[bx + CCT_SSC] seg es les bx,[bx + MACSSC_MCAST_ADDR] mov cx,[bx + 2] lea bx,[bx + 4] jcxz setmc3 setmc1: push bx push cx mov ax,#NDIS_DEL_MULT_ADDR mov dx,bx mov cx,es ! delete each multicast address xor bx,bx ! successively call dogenreq pop cx pop bx add bx,#NDIS_HWADDR_SIZE loop setmc1 setmc3: pop es ! Now we can set all multicast addresses. seg es mov cx,[si] lea si,[si + 2] jcxz setmc7 setmc2: push cx mov ax,#NDIS_ADD_MULT_ADDR mov dx,si mov cx,es xor bx,bx ! set each multicast address call dogenreq ! successively pop cx or ax,ax jnz setmc8 add si,#UNDI_ADDR_LEN loop setmc2 setmc7: clc jmp setmc9 setmc8: stc setmc9: ret #endif #ifdef NEEDSETADDR ! !************************************************************************** ! ! Set hardware station address. ! Input: ES:SI - pointer to new hardware station address ! Output: Carry flag set if error ! Registers changed: AX, BX, CX, DX ! setaddr: push es mov ax,#NDIS_SET_STA_ADDR xor bx,bx mov cx,es mov dx,si call dogenreq pop es or ax,ax jz setad9 stc setad9: ret #endif ! !************************************************************************** ! ! Handle general requests to the MAC driver. ! Input: AX - request opcode ! BX - request word parameter ! CX:DX - request dword parameter ! Output: AX - error code ! Registers changed: AX, BX, CX, DX ! dogenreq: mov word ptr [reqconflg],#NDISERR_QUEUED push es #ifdef IS186 push #MODID_PROT ! push module ID push cs ! push unique request handle push bx ! push request word parameter #else push bx ! push request word parameter push cs ! push unique request handle mov bx,#MODID_PROT push bp mov bp,sp xchg bx,[bp + 4] ! replace word parameter with pop bp ! module ID push bx ! push request word parameter #endif push cx ! push dword parameter push dx push ax ! push opcode push [MacDS] ! push MAC data segment call far ptr [GenRequest] ! call MAC with general request sti ! needed because of some MAC bugs dogen1: cmp ax,#NDISERR_QUEUED ! poll until request processed jne dogen9 mov ax,[reqconflg] jmp dogen1 dogen9: pop es ret ! !************************************************************************** ! ! MAC upcalls ! !************************************************************************** ! ! Handle RequestConfirm. It gets called when an asynchronous general ! request has been finished processing. ! Input: 1. Arg - protocol data segment ! 2. Arg - request opcode ! 3. Arg - status ! 4. Arg - unique request handle (our code segment) ! 5. Arg - MAC ID ! 6. Arg - protocol ID ! Output: AX - error code ! Registers changed: AX ! RequestConfirm: penter (0) push ds push bx getcarg (ds,1) ! get driver data segment getcarg (bx,4) ! check unique request handle mov ax,cs cmp ax,bx mov ax,#NDISERR_PARAM jne rqcon9 getcarg (bx,5) ! check MAC module ID cmp bx,#MODID_MAC jne rqcon9 getcarg (bx,6) cmp bx,#MODID_PROT ! check protocol module ID jne rqcon9 getcarg (bx,3) mov [reqconflg],bx ! save request status xor ax,ax rqcon9: pop bx pop ds pleave retf 12 ! !************************************************************************** ! ! Handle TransmitConfirm. It gets called when an asynchronous transmit ! request has been finished processing. ! Input: 1. Arg - protocol data segment ! 2. Arg - status ! 3. Arg - unique request handle (our code segment) ! 4. Arg - MAC ID ! 5. Arg - protocol ID ! Output: AX - error code ! Registers changed: AX ! TransmitConfirm: penter (0) push ds push bx getcarg (ds,1) ! get driver data segment getcarg (bx,3) ! check unique request handle mov ax,cs cmp ax,bx mov ax,#NDISERR_PARAM jne txcon9 getcarg (bx,4) ! check MAC module ID cmp bx,#MODID_MAC jne txcon9 getcarg (bx,5) cmp bx,#MODID_PROT ! check protocol module ID jne txcon9 getcarg (bx,2) mov [txconflg],bx ! save request status xor ax,ax txcon9: pop bx pop ds pleave retf 10 ! !************************************************************************** ! ! Handle StatusIndication ! Input: 1. Arg - protocol data segment ! 2. Arg - status indication opcode ! 3./4. Arg - far pointer to indicate flag ! 5. Arg - word parameter ! 6. Arg - MAC ID ! Output: AX - error code ! Registers changed: AX ! StatusIndication: penter (0) push ds getcarg (ds,1) ! get driver data segment getcarg (ax,6) ! check MAC module ID cmp ax,#MODID_MAC jne stind9 getcarg (ax,2) mov [indstatus],ax ! save indication opcode stind9: xor ax,ax ! always return success pop ds pleave retf 12 ! !************************************************************************** ! ! Handle IndicationComplete ! Input: 1. Arg - protocol data segment ! 2. Arg - MAC ID ! Output: AX - error code ! Registers changed: AX ! IndicationComplete: penter (0) push ds getcarg (ds,1) ! get driver data segment getcarg (ax,2) ! check MAC module ID cmp ax,#MODID_MAC jne indcm9 ! In case we previously had a StartReset indication, but no EndReset ! indication (an error in the NDIS 1.0.1 specification), set the ! EndReset indication now. pushf cli cmp word ptr [indstatus],#NDIS_START_RESET jne indcm8 mov word ptr [indstatus],#NDIS_END_RESET indcm8: popf indcm9: xor ax,ax ! always return success pop ds pleave retf 4 ! !************************************************************************** ! ! Handle ReceiveLookahead. ! Input: 1. Arg - protocol data segment ! 2./3. Arg - far ptr to indicate flag ! 4./5. Arg - far ptr to lookahead buffer ! 6. Arg - number of bytes in lookahead buffer ! 7. Arg - total size of frame ! 8. Arg - MAC ID ! Output: AX - error code ! Registers changed: AX ! ReceiveLookahead: penter (0) push ds push es push bx push cx push dx getcarg (ds,1) ! get driver data segment mov bx,#NDISERR_REJECT cmp byte ptr [initflag],#FLAG_OPEN jne rxlah9 getcarg (ax,8) ! check MAC module ID cmp ax,#MODID_MAC jne rxlah9 getcarg (cx,7) ! get length of received frame or cx,cx jnz rxlah1 mov cx,#ETH_FRAME_MAX rxlah1: cmp cx,#ETH_FRAME_MAX ! check that its not too large ja rxlah9 mov ax,[readsize] ! buffer free? if not, discard or ax,ax ! the current frame jnz rxlah9 ! We accept all packets, so copy the received packet into our own ! receive buffer. For TransferData we need to setup a receive buffer ! descriptor. mov word ptr [rdbuf + RDBUF_DATA_COUNT],#1 mov byte ptr [rdbuf + RDBUF_DATA_BUFS + RDBUF_PTR_TYPE],#RDBUF_PTR_PHYSICAL mov word ptr [rdbuf + RDBUF_DATA_BUFS + RDBUF_DATA_LEN],cx mov word ptr [rdbuf + RDBUF_DATA_BUFS + RDBUF_DATA_PTR + 0],#readbuf mov word ptr [rdbuf + RDBUF_DATA_BUFS + RDBUF_DATA_PTR + 2],ds #ifdef IS186 push ds push #readsize ! push far ptr to receive size value push #0 ! push offset into received frame push ds push #rdbuf ! push far ptr to rdbuf descriptor push [MacDS] ! push MAC data segment #else push ds mov ax,#readsize ! push far ptr to receive size value push ax xor ax,ax ! push offset into received frame push ax push ds mov ax,#rdbuf ! push far ptr to rdbuf descriptor push ax push [MacDS] ! push MAC data segment #endif call far ptr [TransferData] ! ask MAC to copy the frame mov bx,#NDISERR_REJECT ! reject frame if copy error or ax,ax jnz rxlah9 xor bx,bx ! return without error rxlah9: mov ax,bx pop dx pop cx pop bx pop es pop ds pleave retf 16 ! !************************************************************************** ! ! Handle ReceiveChain ! Input: 1. Arg - protocol data segment ! 2./3. Arg - far ptr to indicate flag ! 4./5. Arg - far ptr to receive buffer descriptor ! 6. Arg - unique handle for this request ! 7. Arg - total size of frame ! 8. Arg - MAC ID ! Output: AX - error code ! Registers changed: AX ! ReceiveChain: penter (0) push ds push es push bx push cx push dx push si push di getcarg (ds,1) ! get driver data segment mov bx,#NDISERR_REJECT cmp byte ptr [initflag],#FLAG_OPEN jne rxchn9 getcarg (ax,8) ! check MAC module ID cmp ax,#MODID_MAC jne rxchn9 getcarg (cx,7) ! get length of received frame cmp cx,#ETH_FRAME_MAX ! check that its not too large ja rxchn9 mov ax,[readsize] ! buffer free? if not, discard or ax,ax ! the current frame jnz rxchn9 ! We accept all frames, so copy the received frame into our local receive ! buffer. cld push ds mov ax,ds mov es,ax ! set ES:DI to local receive buffer mov di,#readbuf getcarg (bx,4) ! set DS:BX to recieve buffer descriptor getcarg (ds,5) mov cx,[bx + RXBUF_DATA_COUNT] lea bx,[bx + RXBUF_DATA_BUFS] rxchn1: push ds push cx mov cx,[bx + RXBUF_DATA_LEN] lds si,[bx + RXBUF_DATA_PTR] shr cx,#1 rep movsw ! copy buffer into local receive buffer jnc rxchn2 movsb rxchn2: pop cx pop ds add bx,#RXBUF_SIZE ! proceed with next buffer loop rxchn1 pop ds sub di,#readbuf mov [readsize],di ! save size of received data xor bx,bx ! return without error rxchn9: mov ax,bx pop di pop si pop dx pop cx pop bx pop es pop ds pleave retf 16 ! !************************************************************************** ! ! Handle SystemRequest. We should never be called with a system request, ! so this is just an error return. ! Input: 1. Arg - request dependent double word parameter 0 ! 2. Arg - request dependent double word parameter 1 ! 3. Arg - request dependent word parameter 0 ! 4. Arg - opcode ! 5. Arg - our own data segment ! Output: AX - error code ! Registers changed: AX ! SystemRequest: mov ax,#NDISERR_FUNCTION retf 14 ! !************************************************************************** ! end