forked from KolibriOS/kolibrios
602924a5b5
fixed bug in netcfg created in last revision netcfg gives error msg when driver is not loaded zeroconfig now works with latest version of libini also fixed use of static and link-local ip in zeroconfig initial IPv4 variables are now 0.0.0.0 instead of 255.255.255.255 created kernel function that shows number of active network devices fixed the use of temp mac variable in IPV4.inc (variable is now in stack) rewrite of ARP code, needs full testing/debugging (new application needed: ARP manager) port numbers are now in INET byte order, as is in posix standards git-svn-id: svn://kolibrios.org@1196 a494cfbc-eb01-0410-851d-a64ba20cac60
614 lines
15 KiB
NASM
614 lines
15 KiB
NASM
; Zero-config
|
|
; v 1.4
|
|
;
|
|
; DHCP code is based on that by Mike Hibbet (DHCP client for menuetos)
|
|
;
|
|
; Written by HidnPlayr & Derpenguin
|
|
|
|
use32
|
|
org 0x0
|
|
|
|
db 'MENUET01' ; 8 byte id
|
|
dd 0x01 ; header version
|
|
dd START ; start of code
|
|
dd IM_END ; size of image
|
|
dd (I_END+0x100) ; memory for app
|
|
dd (I_END+0x100) ; esp
|
|
dd 0x0 , path ; I_Param , I_Icon
|
|
|
|
; CONFIGURATION
|
|
|
|
|
|
TIMEOUT equ 60 ; in seconds
|
|
BUFFER equ 1024 ; in bytes
|
|
__DEBUG__ equ 1 ; enable/disable
|
|
__DEBUG_LEVEL__ equ 1 ; 1 = all, 2 = errors
|
|
|
|
; CONFIGURATION FOR LINK-LOCAL
|
|
|
|
PROBE_WAIT equ 1 ; second (initial random delay)
|
|
PROBE_MIN equ 1 ; second (minimum delay till repeated probe)
|
|
PROBE_MAX equ 2 ; seconds (maximum delay till repeated probe)
|
|
PROBE_NUM equ 3 ; (number of probe packets)
|
|
|
|
ANNOUNCE_NUM equ 2 ; (number of announcement packets)
|
|
ANNOUNCE_INTERVAL equ 2 ; seconds (time between announcement packets)
|
|
ANNOUNCE_WAIT equ 2 ; seconds (delay before announcing)
|
|
|
|
MAX_CONFLICTS equ 10 ; (max conflicts before rate limiting)
|
|
|
|
RATE_LIMIT_INTERVAL equ 60 ; seconds (delay between successive attempts)
|
|
|
|
DEFEND_INTERVAL equ 10 ; seconds (min. wait between defensive ARPs)
|
|
|
|
|
|
AF_INET4 equ 2 ;;;;;
|
|
IP_PROTO_UDP equ 17
|
|
|
|
|
|
|
|
include '../proc32.inc'
|
|
include '../macros.inc'
|
|
include '../debug-fdo.inc'
|
|
include 'dhcp.inc'
|
|
include 'dll.inc'
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
START: ; start of execution
|
|
|
|
mcall 40, 1 shl 7 ; network event
|
|
|
|
; eth.set_network_drv 0x00000383
|
|
|
|
DEBUGF 1,">Zero-config service:\n"
|
|
|
|
; eth.status eax ; Read the Stack status
|
|
; test eax,eax ; if eax is zero, no driver was found
|
|
; jnz @f
|
|
; DEBUGF 1,"No Card found!\n"
|
|
; jmp close
|
|
|
|
; @@:
|
|
; DEBUGF 1,"Detected card: %x\n",eax
|
|
; @@:
|
|
; eth.check_cable eax
|
|
; test al,al
|
|
; jnz @f
|
|
; DEBUGF 1,"Cable disconnected!\n"
|
|
; mcall 5, 500 ; loop until cable is connected (check every 5 sec)
|
|
; jmp @r
|
|
|
|
; @@:
|
|
; eth.read_mac MAC
|
|
|
|
mcall 75, 1337 shl 16 + 4
|
|
|
|
cmp eax, -1
|
|
je close
|
|
|
|
mov word[MAC], bx
|
|
mov dword[MAC+2], eax
|
|
|
|
DEBUGF 1,"->MAC: %x-%x-%x-%x-%x-%x\n",[MAC]:2,[MAC+1]:2,[MAC+2]:2,[MAC+3]:2,[MAC+4]:2,[MAC+5]:2
|
|
|
|
cld
|
|
mov edi, path ; Calculate the length of zero-terminated string
|
|
xor al , al
|
|
mov ecx, 1024
|
|
repnz scas byte[es:edi]
|
|
dec edi
|
|
|
|
mov esi, filename
|
|
movsd
|
|
movsb
|
|
|
|
DEBUGF 1,"->path to ini: %s\n", path
|
|
|
|
mcall 68,11
|
|
|
|
stdcall dll.Load,@IMPORT
|
|
or eax,eax
|
|
jnz skip_ini
|
|
|
|
|
|
invoke ini.get_str, path, str_ipconfig, str_type, inibuf, 16, 0
|
|
|
|
mov eax,dword[inibuf]
|
|
|
|
cmp eax,'stat'
|
|
jne skip_ini
|
|
|
|
invoke ini.get_str, path, str_ipconfig, str_ip, inibuf, 16, 0
|
|
mov edx, inibuf
|
|
call Ip2dword
|
|
mcall 75, 3, edx
|
|
|
|
invoke ini.get_str, path, str_ipconfig, str_gateway, inibuf, 16, 0
|
|
mov edx, inibuf
|
|
call Ip2dword
|
|
mcall 75, 9, edx
|
|
|
|
invoke ini.get_str, path, str_ipconfig, str_dns, inibuf, 16, 0
|
|
mov edx, inibuf
|
|
call Ip2dword
|
|
mcall 75, 7, edx
|
|
|
|
invoke ini.get_str, path, str_ipconfig, str_subnet, inibuf, 16, 0
|
|
mov edx, inibuf
|
|
call Ip2dword
|
|
mcall 75, 5, edx
|
|
|
|
|
|
mcall -1
|
|
|
|
|
|
skip_ini:
|
|
|
|
DEBUGF 1,"->Skip ini\n"
|
|
|
|
mcall 74, 0, AF_INET4, IP_PROTO_UDP, 0 ; open socket (parameters: domain, type, reserved)
|
|
cmp eax, -1
|
|
je error
|
|
mov [socketNum], eax
|
|
|
|
DEBUGF 1,"->socket %x opened\n", eax
|
|
|
|
mcall 74, 2, [socketNum], sockaddr1, 18 ; bind socket to local port 68
|
|
cmp eax, -1
|
|
je error
|
|
|
|
DEBUGF 1,"->Socket Bound to local port 68\n"
|
|
|
|
mcall 74, 4, [socketNum], sockaddr2, 18 ; connect to 255.255.255.255 on port 67
|
|
cmp eax, -1
|
|
je error
|
|
|
|
DEBUGF 1,"->Connected to 255.255.255.255 on port 67\n"
|
|
|
|
mov byte [dhcpMsgType], 0x01 ; DHCP discover
|
|
mov dword [dhcpLease], esi ; esi is still -1 (-1 = forever)
|
|
|
|
mcall 26, 9
|
|
imul eax,100
|
|
mov [currTime],eax
|
|
|
|
buildRequest: ; Creates a DHCP request packet.
|
|
|
|
DEBUGF 1,"->Building request\n"
|
|
|
|
stdcall mem.Alloc, BUFFER
|
|
mov [dhcpMsg], eax
|
|
test eax,eax
|
|
jz apipa
|
|
|
|
|
|
mov edi, eax
|
|
mov ecx,BUFFER
|
|
xor eax,eax
|
|
cld
|
|
rep stosb
|
|
|
|
mov edx,[dhcpMsg]
|
|
|
|
mov [edx], byte 0x01 ; Boot request
|
|
mov [edx+1], byte 0x01 ; Ethernet
|
|
mov [edx+2], byte 0x06 ; Ethernet h/w len
|
|
mov [edx+4], dword 0x11223344 ; xid
|
|
mov eax,[currTime]
|
|
mov [edx+8], eax ; secs, our uptime
|
|
mov [edx+10], byte 0x80 ; broadcast flag set
|
|
mov eax, dword [MAC] ; first 4 bytes of MAC
|
|
mov [edx+28],dword eax
|
|
mov ax, word [MAC+4] ; last 2 bytes of MAC
|
|
mov [edx+32],word ax
|
|
mov [edx+236], dword 0x63538263 ; magic number
|
|
mov [edx+240], word 0x0135 ; option DHCP msg type
|
|
mov al, [dhcpMsgType]
|
|
mov [edx+240+2], al
|
|
mov [edx+240+3], word 0x0433 ; option Lease time = infinity
|
|
mov eax, [dhcpLease]
|
|
mov [edx+240+5], eax
|
|
mov [edx+240+9], word 0x0432 ; option requested IP address
|
|
mov eax, [dhcpClientIP]
|
|
mov [edx+240+11], eax
|
|
mov [edx+240+15], word 0x0437 ; option request list
|
|
mov [edx+240+17], dword 0x0f060301
|
|
|
|
cmp [dhcpMsgType], byte 0x01 ; Check which msg we are sending
|
|
jne request_options
|
|
|
|
mov [edx+240+21], byte 0xff ; "Discover" options
|
|
|
|
mov [dhcpMsgLen], dword 262 ; end of options marker
|
|
jmp send_request
|
|
|
|
request_options:
|
|
mov [edx+240+21], word 0x0436 ; server IP
|
|
mov eax, [dhcpServerIP]
|
|
mov [edx+240+23], eax
|
|
|
|
mov [edx+240+27], byte 0xff ; end of options marker
|
|
|
|
mov [dhcpMsgLen], dword 268
|
|
|
|
send_request:
|
|
mcall 74, 6, [socketNum], [dhcpMsg], [dhcpMsgLen] ; write to socket ( send broadcast request )
|
|
|
|
mov eax, [dhcpMsg] ; Setup the DHCP buffer to receive response
|
|
mov [dhcpMsgLen], eax ; Used as a pointer to the data
|
|
|
|
mcall 23, TIMEOUT*10 ; wait for data
|
|
|
|
read_data: ; we have data - this will be the response
|
|
|
|
mcall 74, 7, [socketNum], [dhcpMsg], BUFFER ; read data from socket
|
|
|
|
DEBUGF 1,"->%d bytes received\n", eax
|
|
|
|
push eax
|
|
mcall 74, 1, [socketNum] ; close the socket
|
|
pop eax
|
|
|
|
cmp eax, -1
|
|
je error
|
|
|
|
mov [dhcpMsgLen], eax
|
|
|
|
; depending on which msg we sent, handle the response
|
|
; accordingly.
|
|
; If the response is to a dhcp discover, then:
|
|
; 1) If response is DHCP OFFER then
|
|
; 1.1) record server IP, lease time & IP address.
|
|
; 1.2) send a request packet
|
|
; If the response is to a dhcp request, then:
|
|
; 1) If the response is DHCP ACK then
|
|
; 1.1) extract the DNS & subnet fields. Set them in the stack
|
|
|
|
cmp [dhcpMsgType], byte 0x01 ; did we send a discover?
|
|
je discover
|
|
cmp [dhcpMsgType], byte 0x03 ; did we send a request?
|
|
je request
|
|
|
|
jmp close ; really unknown, what we did
|
|
|
|
discover:
|
|
call parseResponse
|
|
|
|
cmp [dhcpMsgType], byte 0x02 ; Was the response an offer?
|
|
jne apipa ; NO - so we do zeroconf
|
|
mov [dhcpMsgType], byte 0x03 ; DHCP request
|
|
jmp buildRequest
|
|
|
|
request:
|
|
call parseResponse
|
|
|
|
cmp [dhcpMsgType], byte 0x05 ; Was the response an ACK? It should be
|
|
jne apipa ; NO - so we do zeroconf
|
|
|
|
jmp close
|
|
|
|
;***************************************************************************
|
|
; Function
|
|
; parseResponse
|
|
;
|
|
; Description
|
|
; extracts the fields ( client IP address and options ) from
|
|
; a DHCP response
|
|
; The values go into
|
|
; dhcpMsgType,dhcpLease,dhcpClientIP,dhcpServerIP,
|
|
; dhcpDNSIP, dhcpSubnet
|
|
; The message is stored in dhcpMsg
|
|
;
|
|
;***************************************************************************
|
|
parseResponse:
|
|
DEBUGF 1,"Data received, parsing response\n"
|
|
mov edx, [dhcpMsg]
|
|
|
|
pusha
|
|
mcall 75, 3, [edx+16]
|
|
mov eax,[edx]
|
|
mov [dhcpClientIP],eax
|
|
DEBUGF 1,"Client: %u.%u.%u.%u\n",[edx+16]:1,[edx+17]:1,[edx+18]:1,[edx+19]:1
|
|
popa
|
|
|
|
add edx, 240 ; Point to first option
|
|
xor ecx, ecx
|
|
|
|
next_option:
|
|
add edx, ecx
|
|
pr001:
|
|
mov al, [edx]
|
|
cmp al, 0xff ; End of options?
|
|
je pr_exit
|
|
|
|
cmp al, dhcp_msg_type ; Msg type is a single byte option
|
|
jne @f
|
|
|
|
mov al, [edx+2]
|
|
mov [dhcpMsgType], al
|
|
add edx, 3
|
|
jmp pr001 ; Get next option
|
|
|
|
@@:
|
|
inc edx
|
|
movzx ecx, byte [edx]
|
|
inc edx ; point to data
|
|
|
|
cmp al, dhcp_dhcp_server_id ; server ip
|
|
jne @f
|
|
mov eax, [edx]
|
|
mov [dhcpServerIP], eax
|
|
DEBUGF 1,"Server: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
|
|
jmp next_option
|
|
|
|
@@:
|
|
cmp al, dhcp_address_time
|
|
jne @f
|
|
|
|
pusha
|
|
mov eax,[edx]
|
|
bswap eax
|
|
mov [dhcpLease],eax
|
|
DEBUGF 1,"lease: %d\n",eax
|
|
popa
|
|
|
|
jmp next_option
|
|
|
|
@@:
|
|
cmp al, dhcp_subnet_mask
|
|
jne @f
|
|
|
|
pusha
|
|
mcall 75, 7, [edx]
|
|
DEBUGF 1,"Subnet: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
|
|
popa
|
|
|
|
jmp next_option
|
|
|
|
@@:
|
|
cmp al, dhcp_router
|
|
jne @f
|
|
|
|
pusha
|
|
mcall 75, 9, [edx]
|
|
DEBUGF 1,"Gateway: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
|
|
popa
|
|
|
|
jmp next_option
|
|
|
|
|
|
@@:
|
|
cmp al, dhcp_domain_server
|
|
jne next_option
|
|
|
|
pusha
|
|
mcall 75, 5, [edx]
|
|
DEBUGF 1,"DNS: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
|
|
popa
|
|
|
|
jmp next_option
|
|
|
|
pr_exit:
|
|
|
|
; DEBUGF 1,"Sending ARP announce\n"
|
|
; eth.ARP_ANNOUNCE [dhcpClientIP] ; send an ARP announce packet
|
|
|
|
jmp close
|
|
|
|
apipa:
|
|
stdcall mem.Free, [dhcpMsg]
|
|
|
|
link_local:
|
|
call random
|
|
mov ecx,0xfea9 ; IP 169.254.0.0 link local net, see RFC3927
|
|
mov cx,ax
|
|
mcall 75, 3, ecx ; mask is 255.255.0.0
|
|
DEBUGF 1,"Link Local IP assinged: 169.254.%u.%u\n",[generator+2]:1,[generator+3]:1
|
|
mcall 75, 5, 0xffff
|
|
mcall 75, 9, 0x0
|
|
mcall 75, 7, 0x0
|
|
|
|
mcall 5, PROBE_WAIT*100
|
|
|
|
xor esi,esi
|
|
probe_loop:
|
|
call random ; create a pseudo random number in eax (seeded by MAC)
|
|
|
|
cmp al,PROBE_MIN*100 ; check if al is bigger then PROBE_MIN
|
|
jge @f ; all ok
|
|
add al,(PROBE_MAX-PROBE_MIN)*100 ; al is too small
|
|
@@:
|
|
|
|
cmp al,PROBE_MAX*100
|
|
jle @f
|
|
sub al,(PROBE_MAX-PROBE_MIN)*100
|
|
@@:
|
|
|
|
movzx ebx,al
|
|
DEBUGF 1,"Waiting %u0ms\n",ebx
|
|
mcall 5
|
|
|
|
DEBUGF 1,"Sending Probe\n"
|
|
; eth.ARP_PROBE MAC
|
|
inc esi
|
|
|
|
cmp esi,PROBE_NUM
|
|
jl probe_loop
|
|
|
|
; now we wait further ANNOUNCE_WAIT seconds and send ANNOUNCE_NUM ARP announces. If any other host has assingned
|
|
; IP within this time, we should create another adress, that have to be done later
|
|
|
|
DEBUGF 1,"Waiting %us\n",ANNOUNCE_WAIT
|
|
mcall 5, ANNOUNCE_WAIT*100
|
|
xor esi,esi
|
|
announce_loop:
|
|
|
|
DEBUGF 1,"Sending Announce\n"
|
|
; eth.ARP_ANNOUNCE MAC
|
|
|
|
inc esi
|
|
cmp esi,ANNOUNCE_NUM
|
|
je @f
|
|
|
|
DEBUGF 1,"Waiting %us\n",ANNOUNCE_INTERVAL
|
|
mcall 5, ANNOUNCE_INTERVAL*100
|
|
jmp announce_loop
|
|
@@:
|
|
; we should, instead of closing, detect ARP conflicts and detect if cable keeps connected ;)
|
|
|
|
error:
|
|
close:
|
|
mcall -1
|
|
|
|
|
|
random: ; Pseudo random actually
|
|
|
|
mov eax,[generator]
|
|
add eax,-43ab45b5h
|
|
ror eax,1
|
|
bswap eax
|
|
xor eax,dword[MAC]
|
|
ror eax,1
|
|
xor eax,dword[MAC+2]
|
|
mov [generator],eax
|
|
|
|
ret
|
|
|
|
; DATA AREA
|
|
|
|
align 16
|
|
@IMPORT:
|
|
|
|
library \
|
|
libini,'libini.obj'
|
|
|
|
import libini, \
|
|
ini.get_str,'ini_get_str'
|
|
|
|
include_debug_strings
|
|
|
|
filename db '.ini',0
|
|
str_ip db 'ip',0
|
|
str_subnet db 'subnet',0
|
|
str_gateway db 'gateway',0
|
|
str_dns db 'dns',0
|
|
str_ipconfig db 'ipconfig',0
|
|
str_type db 'type',0
|
|
|
|
|
|
sockaddr1:
|
|
|
|
dw AF_INET4
|
|
dw 68 shl 8 ; local port
|
|
dd 0 ; local IP
|
|
|
|
rb 10
|
|
|
|
|
|
sockaddr2:
|
|
|
|
dw AF_INET4
|
|
dw 67 shl 8 ; destination port
|
|
dd -1 ; destination IP
|
|
|
|
rb 10
|
|
|
|
|
|
IM_END:
|
|
|
|
inibuf rb 16
|
|
|
|
dhcpClientIP dd ?
|
|
dhcpMsgType db ?
|
|
dhcpLease dd ?
|
|
dhcpServerIP dd ?
|
|
|
|
dhcpMsgLen dd ?
|
|
socketNum dd ?
|
|
|
|
MAC dp ?
|
|
|
|
currTime dd ?
|
|
renewTime dd ?
|
|
generator dd ?
|
|
|
|
dhcpMsg dd ?
|
|
|
|
I_END_2:
|
|
|
|
path rb 1024+5
|
|
|
|
I_END: |