Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5585 → Rev 5586

/programs/network/zeroconf/zeroconf.asm
43,6 → 43,8
 
DEFEND_INTERVAL = 10 ; seconds (min. wait between defensive ARPs)
 
MAX_INTERFACES = 8
 
use32
org 0x0
 
62,68 → 64,174
include 'dhcp.inc'
include '../../dll.inc'
 
struct dhcp_msg
op db ? ; Operation Code
htype db ? ; Hardware type
hlen db ? ; Hardware address length
hops db ?
xid dd ? ; Transaction Identifier
secs dw ? ; Seconds since boot
flags dw ?
ciaddr dd ? ; Client IP address
yiaddr dd ? ; "Your" IP address
siaddr dd ? ; Server IP address
giaddr dd ? ; Gateway IP address
chaddr rb 16 ; Client hardware address
sname rb 64 ; Server name
file rb 128 ; boot filename
cookie dd ? ; Magic cookie (0x63538263)
options rb 512
ends
 
struct interface
number dd ?
state dd ? ; 0 - disconnected, 1 - connected
mode dd ? ; 0 - static, 1 - dhcp, 2 - auto (zero config)
tries dd ?
lease dd ?
ServerIP dd ?
ip dd ?
subnet dd ?
dns dd ?
gateway dd ?
socketNum dd ?
timeout dd ?
ip_conflicts dd ?
ends
 
START:
mcall 68, 11
mcall 68, 11 ; init heap
 
stdcall dll.Load,@IMPORT
stdcall dll.Load, @IMPORT ; load libraries
or eax, eax
jnz fail
jnz exit_immediately
 
DEBUGF 2,"Zero-config service loaded\n"
 
mcall 40, EVM_STACK2
mcall 40, EVM_STACK2 ; We only want low-level network events
 
wait_for_link_up:
mov bh, [device]
; Set up interface list
mov edi, device_list
xor ebx, ebx
@@:
inc ebx
mov eax, ebx
stosd
mov ecx, sizeof.interface/4-1
xor eax,eax
rep stosd
cmp ebx, MAX_INTERFACES
jb @b
 
mov ebp, device_list
mainloop:
cmp [ebp + interface.state], 0
je .link_up?
jmp .maintain_link
 
.next:
cmp [ebp + interface.number], MAX_INTERFACES
je .wait
add ebp, sizeof.interface
jmp mainloop
 
.wait:
mcall 10 ; Wait for event
mov ebp, device_list
jmp mainloop
 
.link_up?:
mov bh, byte[ebp + interface.number]
mov bl, 0 ; Get device type
mcall 74
cmp eax, 1 ; Ethernet
jne .wait
jne mainloop.next
 
mov bl, 10 ; Get Link status
mcall 74
test eax, eax
jnz .go
jz mainloop.next
 
.wait:
mcall 10
jmp wait_for_link_up
mov [ebp + interface.state], 1
 
.go:
call create_str_ini_int
 
; Try to read settings from .ini file
invoke ini.get_str, ini_path, str_ini_int, str_ip_type, inibuf, 16, str_null
test eax, eax
jz @f
; If settings not found, use default settings from 'ip?' section
mov dword[str_ini_int], 'ip?'
@@:
 
mov ebx, API_ETH + 0
mov bh, [device]
mov bh, byte[ebp + interface.number]
mcall 76 ; get MAC of the ethernet interface
mov word[MAC], bx
mov dword[MAC+2], eax
DEBUGF 1,"MAC: %x-%x-%x-%x-%x-%x\n", [MAC+0]:2, [MAC+1]:2, [MAC+2]:2, [MAC+3]:2, [MAC+4]:2, [MAC+5]:2
mov word[tx_msg.chaddr], bx
mov dword[tx_msg.chaddr+2], eax
DEBUGF 1, "MAC: %x-%x-%x-%x-%x-%x\n", \
[tx_msg.chaddr+0]:2, [tx_msg.chaddr+1]:2, [tx_msg.chaddr+2]:2, \
[tx_msg.chaddr+3]:2, [tx_msg.chaddr+4]:2, [tx_msg.chaddr+5]:2
 
invoke ini.get_str, path, str_ipconfig, str_type, inibuf, 16, 0
 
cmp dword[inibuf], 'stat'
invoke ini.get_str, ini_path, str_ini_int, str_ip_type, inibuf, 16, str_null
test eax, eax
jnz .fail
mov eax, dword[inibuf]
or eax, 0x20202020
mov [ebp + interface.mode], 0
cmp eax, 'stat'
je static
jmp try_dhcp
mov [ebp + interface.mode], 1
cmp eax, 'dhcp'
je dhcp
mov [ebp + interface.mode], 2
cmp eax, 'auto'
je dhcp
 
wait_for_link_down:
; TODO: detect ARP conflicts
.fail:
DEBUGF 2, "Invalid network.ini settings\n"
mcall -1 ; Give up
 
mcall 40, EVM_STACK2
.loop:
mcall 10
mov bh, [device]
.maintain_link:
 
; Check for IP conflicts
mov ebx, API_ARP
mov bh, byte[ebp + interface.number]
mov bl, 7
mcall 76 ; Number of IP conflicts
cmp eax, [ebp + interface.ip_conflicts]
je @f
mov [ebp + interface.ip_conflicts], eax
DEBUGF 2, "IP address conflict on interface %u\n", [ebp + interface.number]
; Notify user of the IP address conflict
mov [notify_struct.msg], str_conflict
mcall 70, notify_struct
@@:
 
; Check if device is still there
mov bh, byte[ebp + interface.number]
mov bl, 0 ; Get device type
mcall 74
cmp eax, 0 ; No device
je .down
test eax, eax ; No device
jz .link_down
 
; Check if link is still there
mov bl, 10 ; Get Link status
mcall 74
test eax, eax
jnz .loop
jnz .next
 
.down:
.link_down:
mov [ebp + interface.state], 0
 
; Notify user that the link is down
mov [notify_struct.msg], str_disconnected
mcall 70, notify_struct
 
; CHECKME: should we do this in kernel instead? Should we even do this at all?
xor ecx, ecx
mov ebx, API_IPv4 + 3
mov bh, [device]
mov bh, byte[ebp + interface.number]
mcall 76 ; ip
mov bl, 5
mcall 76 ; dns
132,49 → 240,61
mov bl, 9
mcall 76 ; gateway
 
jmp wait_for_link_up
jmp .next
 
link_up:
 
; Read number of previous IP conflicts
mov ebx, API_ARP
mov bh, byte[ebp + interface.number]
mov bl, 7
mcall 76
mov [ebp + interface.ip_conflicts], eax
 
; Notify user that the link is up and running
mov [notify_struct.msg], str_connected
mcall 70, notify_struct
 
.fail:
mcall 40, EVM_STACK2
jmp mainloop.next
 
static:
DEBUGF 1,"Applying Static IP settings\n"
 
invoke ini.get_str, path, str_ipconfig, str_ip, inibuf, 16, 0
mov edx, inibuf
invoke ini.get_str, ini_path, str_ini_int, str_ip, inibuf, 16, str_null
mov esi, inibuf
call ip_str_to_dword
mov ecx, edx
mov ebx, API_IPv4 + 3 ; set IP
mov bh, [device]
mov bh, byte[ebp + interface.number]
mcall 76
 
invoke ini.get_str, path, str_ipconfig, str_gateway, inibuf, 16, 0
mov edx, inibuf
invoke ini.get_str, ini_path, str_ini_int, str_subnet, inibuf, 16, str_null
mov esi, inibuf
call ip_str_to_dword
mov ecx, edx
mov ebx, API_IPv4 + 9 ; set gateway
mov bh, [device]
mov ebx, API_IPv4 + 7 ; set subnet
mov bh, byte[ebp + interface.number]
mcall 76
 
invoke ini.get_str, path, str_ipconfig, str_dns, inibuf, 16, 0
mov edx, inibuf
invoke ini.get_str, ini_path, str_ini_int, str_gateway, inibuf, 16, str_null
mov esi, inibuf
call ip_str_to_dword
mov ecx, edx
mov ebx, API_IPv4 + 5 ; set DNS
mov bh, [device]
mov ebx, API_IPv4 + 9 ; set gateway
mov bh, byte[ebp + interface.number]
mcall 76
 
invoke ini.get_str, path, str_ipconfig, str_subnet, inibuf, 16, 0
mov edx, inibuf
.dns:
invoke ini.get_str, ini_path, str_ini_int, str_dns, inibuf, 16, str_null
mov esi, inibuf
call ip_str_to_dword
mov ecx, edx
mov ebx, API_IPv4 + 7 ; set subnet
mov bh, [device]
mov ebx, API_IPv4 + 5 ; set DNS
mov bh, byte[ebp + interface.number]
mcall 76
 
mov [notify_struct.msg], str_connected
mcall 70, notify_struct
jmp wait_for_link_down
jmp link_up
 
 
try_dhcp:
dhcp:
 
DEBUGF 2,"Trying to contact DHCP server\n"
 
182,126 → 302,128
 
mcall 75, 0, AF_INET4, SOCK_DGRAM, 0 ; open socket (parameters: domain, type, reserved)
cmp eax, -1
je socket_error
mov [socketNum], eax
je dhcp_error
mov [ebp + interface.socketNum], eax
 
DEBUGF 1,"Socket %x opened\n", eax
 
mcall 75, 2, [socketNum], sockaddr1, 18 ; bind socket to local port 68
mcall 75, 2, [ebp + interface.socketNum], sock_local, 18 ; bind socket to local port 68
cmp eax, -1
je socket_error
 
DEBUGF 1,"Socket Bound to local port 68\n"
 
mcall 75, 4, [socketNum], sockaddr2, 18 ; connect to 255.255.255.255 on port 67
pushd [ebp + interface.number]
pushd 4 ; length of option
pushd 1 shl 9 ; SO_BINDTODEVICE
pushd 0 ; SOL_SOCKET
mcall 75, 8, [ebp + interface.socketNum], esp
add esp, 16
cmp eax, -1
je socket_error
 
DEBUGF 1, "Socket Bound to local interface %u\n", [ebp + interface.number]
 
mcall 75, 4, [ebp + interface.socketNum], sock_remote, 18 ; connect to 255.255.255.255 on port 67
cmp eax, -1
je socket_error
 
DEBUGF 1,"Connected to 255.255.255.255 on port 67\n"
 
mov [dhcpMsgType_tx], 0x01 ; DHCP discover
mov [dhcpLease], esi ; esi is still -1 (-1 = forever)
; Read preferred IP address from settings file
invoke ini.get_str, ini_path, str_ini_int, str_ip, inibuf, 16, str_null
mov esi, inibuf
call ip_str_to_dword
mov [ebp + interface.ip], ecx
 
call random
mov [dhcpXID], eax
mov [tx_msg.xid], eax ; randomize session ID
mov [tx_msg_type], 1 ; DHCP discover
 
build_request: ; Creates a DHCP request packet.
build_dhcp_packet:
 
DEBUGF 1,"Building request\n"
DEBUGF 1, "Building DHCP packet\n"
 
mcall 26, 9 ; Get system time
imul eax, 100
mov [currTime], eax
mov [ebp + interface.tries], DHCP_TRIES
 
mov [tries], DHCP_TRIES
; Boot protocol legacy
mov [tx_msg.op], 1 ; Boot request
mov [tx_msg.htype], 1 ; Ethernet
mov [tx_msg.hlen], 6 ; Ethernet address h/w len
mov [tx_msg.hops], 0
mcall 26, 9 ; Time since boot
xor edx, edx
mov ebx, 100
div ebx ; Divide by 100 to get number of seconds
mov [tx_msg.secs], ax
mov [tx_msg.flags], 0
 
stdcall mem.Alloc, BUFFER
test eax, eax
jz dhcp_fail2
mov [dhcpMsg], eax
; DHCP extension
mov [tx_msg.cookie], 0x63538263 ; magic cookie
 
; Fill buffer with zeros
mov edi, eax
mov ecx, BUFFER
xor eax, eax
rep stosb
mov word[tx_msg+240], 0x0135 ; option DHCP msg type
mov al,[tx_msg_type]
mov [tx_msg+240+2], al
 
mov edx, [dhcpMsg]
mov word[tx_msg+240+3], 0x0433 ; option Lease time
mov dword[tx_msg+240+5], -1 ; infinite
 
; Boot protocol legacy
mov [edx], byte 0x01 ; Boot request
mov [edx+1], byte 0x01 ; Ethernet
mov [edx+2], byte 0x06 ; Ethernet h/w len
mov eax, [dhcpXID]
mov [edx+4], eax ; 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 word[tx_msg+240+9], 0x0432 ; option requested IP address
mov eax,[ebp + interface.ip]
mov [tx_msg+240+11], eax
 
; DHCP extension
mov [edx+236], dword 0x63538263 ; magic cookie
mov [edx+240], word 0x0135 ; option DHCP msg type
mov al, [dhcpMsgType_tx]
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, [dhcp.ip]
mov [edx+240+11], eax
mov [edx+240+15], word 0x0437 ; option request list
mov [edx+240+17], dword 0x0f060301
mov word[tx_msg+240+15], 0x0437 ; option request list
mov dword[tx_msg+240+17], 0x0f060301
 
cmp [dhcpMsgType_tx], 0x01 ; Check which msg we are sending
jne .options
cmp [tx_msg_type], 1 ; Check which msg we are sending
jne .request
 
mov [edx+240+21], byte 0xff ; end of options marker
mov byte[tx_msg+240+21], 0xff ; end of options marker
 
mov [dhcpMsgLen], 262 ; length
jmp send_dhcpmsg
mov [tx_msg_len], 262 ; length
jmp send_dhcp_packet
 
.options:
mov [edx+240+21], word 0x0436 ; server IP
mov eax, [dhcpServerIP]
mov [edx+240+23], eax
.request:
mov word[tx_msg+240+21], 0x0436 ; server IP
mov eax,[ebp + interface.ServerIP]
mov [tx_msg+240+23], eax
 
mov [edx+240+27], byte 0xff ; end of options marker
mov byte[tx_msg+240+27], 0xff ; end of options marker
 
mov [dhcpMsgLen], 268 ; length
mov [tx_msg_len], 268 ; length
 
send_dhcpmsg:
DEBUGF 1,"Sending DHCP discover/request\n"
mcall 75, 6, [socketNum], [dhcpMsg], [dhcpMsgLen] ; write to socket (send broadcast request)
 
; Wait for data
send_dhcp_packet:
DEBUGF 1, "Sending DHCP packet\n"
lea edx, [tx_msg]
mcall 75, 6, [ebp + interface.socketNum], , [tx_msg_len]
 
; Wait for reply
mcall 26, 9
add eax, TIMEOUT*100
mov [timeout], eax
mov [ebp + interface.timeout], eax
mov ebx, TIMEOUT*100
.wait:
mcall 23, TIMEOUT
 
read_data: ; we have data - this will be the response
mcall 75, 7, [socketNum], [dhcpMsg], BUFFER, MSG_DONTWAIT ; read data from socket
mcall 23 ; Wait for event with timeout
read_packet: ; we have data - this will be the response
lea edx, [rx_msg]
mcall 75, 7, [ebp + interface.socketNum], , BUFFER, MSG_DONTWAIT ; read data from socket
cmp eax, -1
jne .got_data
 
mcall 26, 9
cmp eax, [timeout]
jb send_dhcpmsg.wait
mov ebx, eax
sub ebx, [ebp + interface.timeout]
ja send_dhcp_packet.wait
 
DEBUGF 2,"No answer from DHCP server\n"
dec [tries]
jnz send_dhcpmsg ; try again
stdcall mem.Free, [dhcpMsg]
dec [ebp + interface.tries]
jnz send_dhcp_packet
jmp dhcp_fail
 
.got_data:
DEBUGF 1,"%d bytes received\n", eax
mov [dhcpMsgLen], eax
mov [rx_msg_len], eax
 
; depending on which msg we sent, handle the response
; accordingly.
313,120 → 435,101
; 1) If the response is DHCP ACK then
; 1.1) extract the DNS & subnet fields. Set them in the stack
 
cmp [dhcpMsgType_tx], 0x01 ; did we send a discover?
cmp [tx_msg_type], 1 ; did we send a discover?
je discover_sent
 
cmp [dhcpMsgType_tx], 0x03 ; did we send a request?
cmp [tx_msg_type], 3 ; did we send a request?
je request_sent
jmp exit_immediately
 
; we should never reach here ;)
stdcall mem.Free, [dhcpMsg]
jmp fail
 
discover_sent:
call parse_response
cmp [dhcpMsgType_rx], 0x02 ; Was the response an offer?
jne read_data
call parse_dhcp_reply
cmp [rx_msg_type], 2 ; Was the response an offer?
jne read_packet
 
DEBUGF 1, "Got offer, making request\n"
mov [dhcpMsgType_tx], 0x03 ; make it a request
jmp build_request
mov [tx_msg_type], 3 ; make it a request
jmp build_dhcp_packet
 
request_sent:
call parse_response
cmp [dhcpMsgType_rx], 0x05 ; Was the response an ACK? It should be
jne read_data ; NO - read next packets
call parse_dhcp_reply
cmp [rx_msg_type], 5 ; Was the response an ACK? It should be
jne read_packet ; NO - read next packets
 
DEBUGF 2, "IP assigned by DHCP server successfully\n"
 
mov [notify_struct.msg], str_connected
mcall 70, notify_struct
mcall close, [ebp + interface.socketNum]
 
mcall close, [socketNum]
 
mov ebx, API_IPv4 + 3
mov bh, [device]
mcall 76, , [dhcp.ip] ; ip
mov bh, byte[ebp + interface.number]
mcall 76, , [ebp + interface.ip] ; ip
mov bl, 5
mcall 76, , [dhcp.dns] ; dns
mov bl, 7
mcall 76, , [dhcp.subnet] ; subnet
mcall 76, , [ebp + interface.subnet] ; subnet
mov bl, 9
mcall 76, , [dhcp.gateway] ; gateway
mcall 76, , [ebp + interface.gateway] ; gateway
 
jmp wait_for_link_down
invoke ini.get_str, ini_path, str_ini_int, str_dns_type, inibuf, 16, str_null
test eax, eax
jnz @f
mov eax, dword[inibuf]
or eax, 0x202020
cmp eax, 'stat'
je static.dns
@@:
mcall 76, , [ebp + interface.dns] ; dns
mov bl, 7
 
jmp link_up
 
;***************************************************************************
; 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
;
;***************************************************************************
parse_response:
 
parse_dhcp_reply:
 
DEBUGF 1,"Parsing response\n"
mov edx, [dhcpMsg]
mov [dhcpMsgType_rx], 0
mov [rx_msg_type], 0
 
; Verify if session ID matches
mov eax, [dhcpXID]
cmp dword[edx+4], eax
mov eax, [tx_msg.xid]
cmp [rx_msg.xid], eax
jne .done
 
push dword [edx+16]
pop [dhcp.ip]
DEBUGF 1,"Client: %u.%u.%u.%u\n", [edx+16]:1, [edx+17]:1, [edx+18]:1, [edx+19]:1
pushd [rx_msg.yiaddr]
pop [ebp + interface.ip]
DEBUGF 1, "Client: %u.%u.%u.%u\n", \
[rx_msg.yiaddr]:1, [rx_msg.yiaddr+1]:1, [rx_msg.yiaddr+2]:1, [rx_msg.yiaddr+3]:1
 
; TODO: check if there really are options
; Verify magic cookie
cmp [rx_msg.cookie], 0x63538263
jne .done
 
mov al, 240 ; Point to first option
movzx ecx, al
 
; Parse the DHCP options
lea esi, [rx_msg]
mov ecx, 240 ; point to the first option
.next_option:
add edx, ecx
; TODO: check if we still are inside the buffer!
add esi, ecx
 
mov al, [edx] ; get message identifier
 
cmp al, 0xff ; End of options?
lodsb ; get message identifier
mov bl, al
cmp bl, 0xff ; End of options?
je .done
test bl, bl
jz .pad
 
cmp al, 0
je .pad
 
; TODO: check if we still are inside the buffer
 
inc edx
movzx ecx, byte [edx] ; get data length
inc edx ; point to data
 
cmp al, dhcp_msg_type ; Msg type is a single byte option
lodsb ; load data length
movzx ecx, al
cmp bl, dhcp_msg_type ; Msg type is a single byte option
je .msgtype
 
cmp al, dhcp_dhcp_server_id
cmp bl, dhcp_dhcp_server_id
je .server
 
cmp al, dhcp_address_time
cmp bl, dhcp_address_time
je .lease
 
cmp al, dhcp_subnet_mask
cmp bl, dhcp_subnet_mask
je .subnet
 
cmp al, dhcp_router
cmp bl, dhcp_router
je .router
 
cmp al, dhcp_domain_server
cmp bl, dhcp_domain_server
je .dns
 
DEBUGF 1,"Unsupported DHCP option: %u\n", al
 
DEBUGF 1, "Unsupported DHCP option: %u\n", bl
jmp .next_option
 
.pad:
435,65 → 538,73
jmp .next_option
 
.msgtype:
mov al, [edx]
mov [dhcpMsgType_rx], al
mov al, [esi]
mov [rx_msg_type], al
 
DEBUGF 1,"DHCP Msg type: %u\n", al
jmp .next_option ; Get next option
 
.server:
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
pushd [esi]
pop [ebp + interface.ServerIP]
DEBUGF 1, "Server: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
jmp .next_option
 
.lease:
pusha
mov eax,[edx]
mov eax,[esi]
bswap eax
mov [dhcpLease],eax
mov [ebp + interface.lease], eax
DEBUGF 1,"Lease: %d\n",eax
popa
jmp .next_option
 
.subnet:
push dword [edx]
pop [dhcp.subnet]
DEBUGF 1,"Subnet: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
pushd [esi]
pop [ebp + interface.subnet]
DEBUGF 1, "Subnet: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
jmp .next_option
 
.router:
push dword [edx]
pop [dhcp.gateway]
DEBUGF 1,"Gateway: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
pushd [esi]
pop [ebp + interface.gateway]
DEBUGF 1, "Gateway: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
jmp .next_option
 
.dns:
push dword [edx]
pop [dhcp.dns]
DEBUGF 1,"DNS: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
pushd [esi]
pop [ebp + interface.dns]
DEBUGF 1, "DNS: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
jmp .next_option
 
.done:
stdcall mem.Free, [dhcpMsg]
ret
 
exit_immediately:
DEBUGF 2, "Zeroconf failed!\n"
mcall -1
 
socket_error:
DEBUGF 2, "Socket error!\n"
 
dhcp_fail:
mcall close, [ebp + interface.socketNum]
 
mcall close, [socketNum]
 
dhcp_fail2:
dhcp_error:
DEBUGF 1,"DHCP failed\n"
cmp [ebp + interface.mode], 2 ; zero config mode?
jne link_up
 
link_local:
 
link_local:
; TODO: send ARP probes before setting the IP address in stack!
 
call random
mov cx, ax
shl ecx, 16
mov cx, 0xfea9 ; IP 169.254.0.0 link local net, see RFC3927
mov ebx, API_IPv4 + 3
mov bh, [device]
mov bh, byte[ebp + interface.number]
mcall 76, , ecx ; mask is 255.255.0.0
DEBUGF 2,"Link Local IP assigned: 169.254.%u.%u\n", [generator+0]:1, [generator+1]:1
mov bl, 7
503,66 → 614,9
mov bl, 5
mcall 76, , 0x0
 
mcall 5, PROBE_WAIT*100
jmp link_up
 
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
jae @f ; all ok
add al, (PROBE_MAX-PROBE_MIN)*100 ; al is too small
@@:
 
cmp al, PROBE_MAX*100
jbe @f
sub al, (PROBE_MAX-PROBE_MIN)*100
@@:
 
movzx ebx,al
DEBUGF 1,"Waiting %u0ms\n",ebx
mcall 5
 
DEBUGF 1,"Sending Probe\n"
mov ebx, API_ARP + 6
mov bh, [device]
mcall 76
inc esi
 
cmp esi, PROBE_NUM
jb 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"
mov ebx, API_ARP + 6
mov bh, [device]
mcall 76
 
inc esi
cmp esi,ANNOUNCE_NUM
je @f
 
DEBUGF 1,"Waiting %us\n", ANNOUNCE_INTERVAL
mcall 5, ANNOUNCE_INTERVAL*100
jmp announce_loop
@@:
jmp wait_for_link_down
 
 
socket_error:
DEBUGF 2,"Socket error\n"
fail:
DEBUGF 2,"Zeroconf failed!\n"
mcall -1
 
 
random: ; Pseudo random actually
 
mov eax, [generator]
569,9 → 623,9
add eax, -43ab45b5h
ror eax, 1
bswap eax
xor eax, dword[MAC]
xor eax, dword[tx_msg.chaddr]
ror eax, 1
xor eax, dword[MAC+2]
xor eax, dword[tx_msg.chaddr+2]
mov [generator], eax
 
ret
578,72 → 632,66
 
 
 
ip_str_to_dword:
create_str_ini_int:
mov eax, [ebp + interface.number]
mov ebx, 10
xor edx, edx
push 0
@@:
div ebx
add dl, '0'
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
 
test eax, eax
jnz @r
@@:
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 ;
mov edi, str_ini_int+2
@@:
pop eax
stosb
test eax, eax
jnz @r
 
inc edx ; the byte was a number, so lets check the next byte
ret
 
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 @@)
; In: esi = ptr to ASCIIZ IP address
; Out: ecx = IP (0 on error)
 
@@: ; 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
ip_str_to_dword:
 
; 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:
xor ecx, ecx ; end result
.charloop:
lodsb
test eax, eax
test al, al
jz .finish
cmp al, '.'
jz .outer_loop
sub eax, '0'
imul ebx, 10
add ebx, eax
jmp .inner_loop
je .dot
sub al, '0'
jb .fail
cmp al, 9
ja .fail
mov dl, cl
shl cl, 2
jc .fail
add cl, dl
jc .fail
add cl, cl
jc .fail
add cl, al
jc .fail
jmp .charloop
.dot:
shl ecx, 8
jc .fail
xor cl, cl
jmp .charloop
.finish:
shl edx, 8
add edx, ebx
 
bswap edx ; we want little endian order
 
bswap ecx ; we want little endian order
ret
 
no_IP:
pop edx
xor edx, edx
 
.fail:
xor ecx, ecx
ret
 
; DATA AREA
655,7 → 703,8
libini,'libini.obj'
 
import libini, \
ini.get_str,'ini_get_str'
ini.get_str, 'ini_get_str',\
ini.set_str, 'ini_set_str'
 
include_debug_strings
 
663,25 → 712,26
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
 
str_ip_type db 'ip_type', 0
str_dns_type db 'dns_type', 0
 
sockaddr1:
str_ini_int db 'ip1', 0
rb 10
 
str_null db 0
 
sock_local:
dw AF_INET4
dw 68 shl 8 ; local port
dd 0 ; local IP
 
rb 10
 
 
sockaddr2:
 
sock_remote:
dw AF_INET4
dw 67 shl 8 ; destination port
dd -1 ; destination IP
 
rb 10
 
notify_struct:
693,38 → 743,24
db '/sys/@notify', 0
 
str_connected db '"You are now connected to the network." -N', 0
str_disconnected db '"You are now disconnected from the network." -N', 0
str_conflict db '"An IP address conflict has been detected on the network." -W', 0
 
path db '/sys/settings/network.ini',0
ini_path db '/sys/settings/network.ini',0
 
IM_END:
 
device db 1
generator dd ?
 
inibuf rb 16
tries db ?
 
dhcpMsgType_tx db ? ; sent
dhcpMsgType_rx db ? ; received
dhcpXID dd ?
dhcpLease dd ?
dhcpServerIP dd ?
tx_msg_len dd ?
rx_msg_len dd ?
tx_msg_type db ?
rx_msg_type db ?
tx_msg dhcp_msg
rx_msg dhcp_msg
 
dhcp:
.ip dd ?
.subnet dd ?
.dns dd ?
.gateway dd ?
device_list rd MAX_INTERFACES*sizeof.interface
 
 
dhcpMsgLen dd ?
socketNum dd ?
 
MAC dp ?
 
currTime dd ?
generator dd ?
 
dhcpMsg dd ?
 
timeout dd ?
 
I_END: