;
; ETH.INC
;
; made by hidnplayr (hidnplayr@kolibrios.org) for KolibriOS
;
; The given code before every macro is only a simple example
;
;
; HISTORY
;
; v1.0: august 2006  original release
; v1.1: december 2006 bugfixes and improvements
; v1.2: february 2007 more bugfixes and improvements

macro mov arg1,arg2 {
    if arg1 eq arg2
    else
    mov arg1,arg2
    end if
}

TCB_LISTEN = 1
TCB_SYN_SENT = 2
TCB_SYN_RECEIVED = 3
TCB_ESTABLISHED = 4
TCB_FIN_WAIT_1 = 5
TCB_FIN_WAIT_2 = 6
TCB_CLOSE_WAIT = 7
TCB_CLOSING = 8
TCB_LAST_ASK = 9
TCB_TIME_WAIT = 10
TCB_CLOSED = 11

PASSIVE = 0
ACTIVE = 1

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

macro eth.get_IP IP {
    mov  ebx,1
    mov  eax,52
    mcall

    mov  IP ,eax
}

macro eth.get_GATEWAY GATEWAY {
    mov  ebx,9
    mov  eax,52
    mcall
    mov GATEWAY ,eax
}

macro eth.get_SUBNET SUBNET {
    mov  ebx,10
    mov  eax,52
    mcall
    mov SUBNET ,eax
}

macro eth.get_DNS DNS {
    mov  ebx,13
    mov  eax,52
    mcall
    mov  DNS ,eax
}

macro eth.set_IP IP {
    mov  ecx,IP
    mov  ebx,3
    mov  eax,52
    mcall
}

macro eth.set_GATEWAY GATEWAY {
    mov  ecx,GATEWAY
    mov  ebx,11
    mov  eax,52
    mcall
}

macro eth.set_SUBNET SUBNET {
    mov  ecx,SUBNET
    mov  ebx,12
    mov  eax,52
    mcall
}

macro eth.set_DNS DNS {
    mov  ecx,DNS
    mov  ebx,14
    mov  eax,52
    mcall
}

macro eth.set_network_drv conf {
    mov  ecx,conf
    mov  ebx,2
    mov  eax,52
    mcall
}

macro eth.open_udp local,remote,ip,socket {
    mov  ecx, local
    mov  edx, remote
    mov  esi, ip
    mov  ebx, 0
    mov  eax, 53
    mcall

    mov  socket,eax
}

macro eth.close_udp socket {
    mov  ecx, socket
    mov  ebx, 1
    mov  eax, 53
    mcall
}

macro eth.poll socket {
    mov  ecx, socket
    mov  ebx, 2
    mov  eax, 53
    mcall
}

macro eth.read_byte socket, result {
    mov  ecx, socket
    mov  ebx, 3
    mov  eax, 53
    mcall

    mov  result,bl
}

macro eth.read_packet socket, result, buffersize {
    mov  esi, buffersize
    mov  edx, result
    mov  ecx, socket
    mov  ebx, 11
    mov  eax, 53
    mcall
}

macro eth.write_udp socket,length,msg,verify {
    mov  ecx, socket
    mov  edx, length
    mov  esi, msg
    mov  ebx, 4
    mov  eax, 53
    mcall

    if verify eq 1
    call verifysend
    end if

}

verifysend:
    test eax,eax
    jnz  @f
    ret
@@:
    pusha
    mov  eax,5
    mov  ebx,100
    mcall
    popa
    mcall
ret

macro eth.open_tcp local,remote,ip,passive,socket {

    mov  ecx, local
    mov  edx, remote
    mov  esi, ip
    mov  edi, passive	   ; 0 = PASSIVE open
    mov  ebx, 5
    mov  eax, 53
    mcall

    mov  socket,eax
}

macro eth.socket_status socket,result {
    mov  ecx, socket
    mov  ebx, 6
    mov  eax, 53
    mcall

    mov  result,eax
}

macro eth.write_tcp socket,length,msg,verify {
    mov  ecx, socket
    mov  edx, length
    mov  esi, msg
    mov  ebx, 7
    mov  eax, 53
    mcall

    if verify eq 1
    call verifysend
    end if
}

macro eth.read_mac mac {
    mov  eax, 52
    mov  ebx, 15
    xor  ecx, ecx
    pusha
    mcall
    mov  dword[mac],eax
    popa
    add  cl, 4
    mcall
    mov  word[mac+4],ax

}

macro eth.close_tcp socket {
    mov  ecx, socket
    mov  ebx, 8
    mov  eax, 53
    mcall
}

macro eth.check_port port,result {
    mov  ecx, port
    mov  ebx, 9
    mov  eax, 53
    mcall

    mov  result,eax
}

macro eth.check_cable result {
    mov  ebx, 10
    mov  eax, 53
    mcall

    mov  result,eax
}

macro eth.status status {
    mov  ebx, 255
    mov  ecx, 6
    mov  eax, 53
    mcall

    mov  status,eax
}

macro eth.search_port port,result {
    mov  edx,port
   @@:
    inc  edx
    eth.check_port edx,eax
    cmp  eax,0
    je	 @r
    mov  result,edx
}

macro eth.ARP_PROBE address{

    mov  edx,address
    mov  eax,52
    mov  ebx,16
    xor  ecx,ecx
    mcall

}


macro eth.ARP_ANNOUNCE address{

    mov  edx,address
    mov  eax,52
    mov  ebx,16
    xor  ecx,ecx
    inc  ecx
    mcall

}

macro eth.read_data socket,dest,endptr,bufferl {
local .getdata,.loop,.end
    mov     eax, dest
    mov     endptr, eax

.getdata:
    cmp     endptr, bufferl
    jg	    .end

    eth.read_packet socket, endptr, 0
    add     endptr,eax

    test    eax, eax
    jnz     .getdata

    xor     edx, edx
.loop:
    eth.poll socket

    test    eax, eax
    jnz     .getdata

    mov     eax,5
    mov     ebx,1
    mcall

    inc     edx
    cmp     edx,30
    jl	    .loop

.end:
}

macro eth.wait_for_data socket,TIMEOUT,abort {
    mov   edx,TIMEOUT

   @@:
    eth.poll socket

    cmp   eax,0
    jne   @f

    dec   edx
    jz	  abort

    mov   eax,5 			      ; wait here for event
    mov   ebx,10
    mcall

    jmp   @r
   @@:

}



Ip2dword:
    push    edx

    ; This code validates if the query is an IP containing 4 numbers and 3 dots

    xor     al, al	      ; make al (dot count) zero

   @@:
    cmp     byte[edx],'0'     ; check if this byte is a number, if not jump to no_IP
    jl	    no_IP	      ;
    cmp     byte[edx],'9'     ;
    jg	    no_IP	      ;

    inc     edx 	      ; the byte was a number, so lets check the next byte

    cmp     byte[edx],0       ; is this byte zero? (have we reached end of query?)
    jz	    @f		      ; jump to next @@ then
    cmp     byte[edx],':'
    jz	    @f

    cmp     byte[edx],'.'     ; is this byte a dot?
    jne     @r		      ; if not, jump to previous @@

    inc     al		      ; the byte was a dot so increment al(dot count)
    inc     edx 	      ; next byte
    jmp     @r		      ; lets check for numbers again (jump to previous @@)

   @@:			      ; we reach this when end of query reached
    cmp     al,3	      ; check if there where 3 dots
    jnz     no_IP	      ; if not, jump to no_IP

    ; The following code will convert this IP into a dword and output it in eax
    ; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1

    pop     esi 	      ; edx (query address) was pushed onto stack and is now popped in esi

    xor     edx, edx	      ; result
    xor     eax, eax	      ; current character
    xor     ebx, ebx	      ; current byte

.outer_loop:
    shl     edx, 8
    add     edx, ebx
    xor     ebx, ebx
.inner_loop:
    lodsb
    test    eax, eax
    jz	    .finish
    cmp     al, '.'
    jz	    .outer_loop
    sub     eax, '0'
    imul    ebx, 10
    add     ebx, eax
    jmp     .inner_loop
.finish:
    shl     edx, 8
    add     edx, ebx

    bswap   edx 	      ; we want little endian order

    ret

no_IP:
    pop     edx
    xor     edx, edx

    ret