/programs/network/autodhcp/trunk/debug.inc |
---|
File deleted |
\ No newline at end of file |
/programs/network/autodhcp/trunk/ETH.INC |
---|
0,0 → 1,619 |
; |
; ETH.INC |
; |
; made by hidnplayr (hidnplayr@gmail.com) 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: februari 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 |
int 0x40 |
mov IP ,eax |
} |
macro eth.get_GATEWAY GATEWAY { |
mov ebx,9 |
mov eax,52 |
int 0x40 |
mov GATEWAY ,eax |
} |
macro eth.get_SUBNET SUBNET { |
mov ebx,10 |
mov eax,52 |
int 0x40 |
mov SUBNET ,eax |
} |
macro eth.get_DNS DNS { |
mov ebx,13 |
mov eax,52 |
int 0x40 |
mov DNS ,eax |
} |
macro eth.set_IP IP { |
mov ecx,IP |
mov ebx,3 |
mov eax,52 |
int 0x40 |
} |
macro eth.set_GATEWAY GATEWAY { |
mov ecx,GATEWAY |
mov ebx,11 |
mov eax,52 |
int 0x40 |
} |
macro eth.set_SUBNET SUBNET { |
mov ecx,SUBNET |
mov ebx,12 |
mov eax,52 |
int 0x40 |
} |
macro eth.set_DNS DNS { |
mov ecx,DNS |
mov ebx,14 |
mov eax,52 |
int 0x40 |
} |
macro eth.open_udp local,remote,ip,socket { |
mov ecx, local |
mov edx, remote |
mov esi, ip |
mov ebx, 0 |
mov eax, 53 |
int 0x40 |
mov socket,eax |
} |
macro eth.close_udp socket { |
mov ecx, socket |
mov ebx, 1 |
mov eax, 53 |
int 0x40 |
} |
macro eth.poll socket { |
mov ecx, socket |
mov ebx, 2 |
mov eax, 53 |
int 0x40 |
} |
macro eth.read_byte socket, result { |
mov ecx, socket |
mov ebx, 3 |
mov eax, 53 |
int 0x40 |
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 |
int 0x40 |
} |
macro eth.write_udp socket,length,msg,verify { |
mov ecx, socket |
mov edx, length |
mov esi, msg |
mov ebx, 4 |
mov eax, 53 |
int 0x40 |
if verify eq 1 |
call verifysend |
end if |
} |
verifysend: |
test eax,eax |
jnz @f |
ret |
@@: |
pusha |
mov eax,5 |
mov ebx,100 |
int 0x40 |
popa |
int 0x40 |
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 |
int 0x40 |
mov socket,eax |
} |
macro eth.socket_status socket,result { |
mov ecx, socket |
mov ebx, 6 |
mov eax, 53 |
int 0x40 |
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 |
int 0x40 |
if verify eq 1 |
call verifysend |
end if |
} |
macro eth.read_mac mac { |
mov eax, 52 |
mov ebx, 15 |
xor ecx, ecx |
pusha |
int 0x40 |
mov dword[mac],eax |
popa |
add cl, 4 |
int 0x40 |
mov word[mac+4],ax |
} |
macro eth.close_tcp socket { |
mov ecx, socket |
mov ebx, 8 |
mov eax, 53 |
int 0x40 |
} |
macro eth.check_port port,result { |
mov ecx, port |
mov ebx, 9 |
mov eax, 53 |
int 0x40 |
mov result,eax |
} |
macro eth.check_cable result { |
mov ebx, 10 |
mov eax, 53 |
int 0x40 |
mov result,eax |
} |
macro eth.status status { |
mov ebx, 255 |
mov ecx, 6 |
mov eax, 53 |
int 0x40 |
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 |
int 0x40 |
} |
macro eth.ARP_ANNOUNCE address{ |
mov edx,address |
mov eax,52 |
mov ebx,16 |
xor ecx,ecx |
inc ecx |
int 0x40 |
} |
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, bufferl |
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 |
int 0x40 |
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 |
int 0x40 |
jmp @r |
@@: |
} |
; The function 'resolve' resolves the address in edx and puts the resulting IP in eax. |
; When the input is an IP-adress, the function will output this IP in eax. |
; If something goes wrong, the result in eax should be 0 |
; |
; example: |
; |
; resolve query1,IP,PORT |
; resolve '192.168.0.1',IP,PORT |
; resolve query2,IP,PORT |
; |
; query1 db 'www.google.com',0 |
; query2 db '49.78.84.45',0 |
; IP dd ? |
; PORT dd ? |
macro resolve query,result { |
if query eqtype 0 |
mov edx,query |
else |
local ..string, ..label |
jmp ..label |
..string db query,0 |
..label: |
mov edx,..string |
end if |
call __resolve |
mov result,eax |
} |
if used __resolve |
__resolve: |
if __DEBUG__ eq 1 |
DEBUGF 1,'DNS: Resolving started\n' |
end if |
; This code validates if the query is an IP containing 4 numbers and 3 dots |
push edx ; push edx (query address) onto stack |
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 (this is where the DNS will take over) |
; 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 |
mov eax, edx |
ret |
no_IP: |
pop edx |
; The query is not an IP address, we will send the query to a DNS server and hope for answer ;) |
if __DEBUG__ eq 1 |
DEBUGF 1,'DNS: The query is no ip, Building request string from:%u\n',edx |
end if |
; Build the request string |
mov eax, 0x00010100 |
mov [dnsMsg], eax |
mov eax, 0x00000100 |
mov [dnsMsg+4], eax |
mov eax, 0x00000000 |
mov [dnsMsg+8], eax |
; domain name goes in at dnsMsg+12 |
mov esi, dnsMsg + 12 ; location of label length |
mov edi, dnsMsg + 13 ; label start |
mov ecx, 12 ; total string length so far |
td002: |
mov [esi], byte 0 |
inc ecx |
td0021: |
mov al, [edx] |
cmp al, 0 |
je td001 ; we have finished the string translation |
cmp al, '.' |
je td004 ; we have finished the label |
inc byte [esi] |
inc ecx |
mov [edi], al |
inc edi |
inc edx |
jmp td0021 |
td004: |
mov esi, edi |
inc edi |
inc edx |
jmp td002 |
; write label len + label text |
td001: |
mov [edi], byte 0 |
inc ecx |
inc edi |
mov [edi], dword 0x01000100 |
add ecx, 4 |
mov [dnsMsgLen], ecx ; We'll need the length of the message when we send it |
; Now, lets send this and wait for an answer |
eth.search_port 1024,edx ; Find a free port starting from 1025 and store in edx |
eth.get_DNS esi ; Read DNS IP from stack into esi |
eth.open_udp edx,53,esi,[socketNum] ; First, open socket |
if __DEBUG__ eq 1 |
DEBUGF 1,'DNS: Socket opened: %u (port %u)\n',[socketNum],ecx |
end if |
eth.write_udp [socketNum],[dnsMsgLen],dnsMsg ; Write to socket ( request DNS lookup ) |
if __DEBUG__ eq 1 |
DEBUGF 1,'DNS: Data written, length:%u offset:%u\n',[dnsMsgLen],dnsMsg |
DEBUGF 1,'DNS: Waiting for data: (timeout is %us)\n',TIMEOUT |
end if |
eth.wait_for_data [socketNum],TIMEOUT,abort ; Now, we wait for data from remote |
eth.read_data dword[socketNum],dnsMsg,dword[dnsMsgLen],dnsMsg+BUFFER ; Read the data into the buffer |
if __DEBUG__ eq 1 |
DEBUGF 1,'Data received, offset:%u buffer size:%u length:%u\n',dnsMsg,BUFFER,esi-dnsMsg |
end if |
eth.close_udp [socketNum] ; We're done, close the socket |
if __DEBUG__ eq 1 |
DEBUGF 1,'Closed Socket\n' |
end if |
; Now parse the message to get the host IP. Man, this is complicated. It's described in RFC 1035 |
; 1) Validate that we have an answer with > 0 responses |
; 2) Find the answer record with TYPE 0001 ( host IP ) |
; 3) Finally, copy the IP address to the display |
; Note: The response is in dnsMsg, the end of the buffer is pointed to by [dnsMsgLen] |
mov esi, dnsMsg |
mov al, [esi+2] ; Is this a response to my question? |
and al, 0x80 |
cmp al, 0x80 |
jne abort |
if __DEBUG__ eq 1 |
DEBUGF 1,'DNS: It was a response to my question\n' |
end if |
mov al, [esi+3] ; Were there any errors? |
and al, 0x0F |
cmp al, 0x00 |
jne abort |
if __DEBUG__ eq 1 |
DEBUGF 1,'DNS: There were no errors\n' |
end if |
mov ax, [esi+6] ; Is there ( at least 1 ) answer? |
cmp ax, 0x00 |
je abort |
; Header validated. Scan through and get my answer |
add esi, 12 ; Skip to the question field |
call skipName ; Skip through the question field |
add esi, 4 ; skip past the questions qtype, qclass |
ctr002z: |
; Now at the answer. There may be several answers, find the right one ( TYPE = 0x0001 ) |
call skipName |
mov ax, [esi] |
cmp ax, 0x0100 ; Is this the IP address answer? |
jne ctr002c |
add esi, 10 ; Yes! Point eax to the first byte of the IP address |
mov eax,[esi] |
ret |
ctr002c: ; Skip through the answer, move to the next |
add esi, 8 |
movzx eax, byte [esi+1] |
mov ah, [esi] |
add esi, eax |
add esi, 2 |
cmp esi, [dnsMsgLen] ; Have we reached the end of the msg? This is an error condition, should not happen |
jl ctr002z ; Check next answer |
abort: |
if __DEBUG__ eq 1 |
DEBUGF 1,'DNS: Something went wrong, aborting\n' |
end if |
xor eax,eax |
ret |
skipName: |
; Increment esi to the first byte past the name field |
; Names may use compressed labels. Normally do. |
; RFC 1035 page 30 gives details |
mov al, [esi] |
cmp al, 0 |
je sn_exit |
and al, 0xc0 |
cmp al, 0xc0 |
je sn001 |
movzx eax, byte [esi] |
inc eax |
add esi, eax |
jmp skipName |
sn001: |
add esi, 2 ; A pointer is always at the end |
ret |
sn_exit: |
inc esi |
ret |
dnsMsgLen: dd 0 |
socketNum: dd 0xFFFF |
if ~defined dnsMsg |
dnsMsg: rb BUFFER |
end if |
end if |
/programs/network/autodhcp/trunk/autodhcp.asm |
---|
1,16 → 1,17 |
; |
; Automated dhcp client |
; v 1.3 |
; |
; v 1.1 |
; with thanks to authors of DHCP client for menuetos: Mike Hibbet |
; |
; by the hidden player |
; |
; by HidnPlayr & Derpenguin |
DEBUG equ 1 |
TIMEOUT equ 60 ; in seconds |
BUFFER equ 1024 |
__DEBUG__ equ 1 |
__DEBUG_LEVEL__ equ 1; 1 = all, 2 = errors |
use32 |
org 0x0 |
db 'MENUET01' ; 8 byte id |
21,13 → 22,33 |
dd I_END ; esp |
dd 0x0 , 0x0 ; I_Param , I_Icon |
include 'macros.inc' |
;include 'macros.inc' |
include 'eth.inc' |
include 'debug-fdo.inc' |
if DEBUG = 1 |
include 'debug.inc' |
end if |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
; 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) ; |
; ; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
START: ; start of execution |
mov eax,40 ; Report events |
34,61 → 55,69 |
mov ebx,10000000b ; Only Stack |
int 0x40 |
mov eax,52 ; first, enable the stack |
mov eax,52 ; first, enable the stack (packet driver) |
mov ebx,2 |
mov ecx,0x00000383 |
int 0x40 |
if DEBUG = 1 |
newline |
dps "DHCP: Stack Initialized" |
newline |
end if |
DEBUGF 1,"DHCP: Stack Initialized.\n" |
mov eax, 53 ; then, read in the status |
mov ebx, 255 |
mov ecx, 6 |
int 0x40 |
eth.status eax ; Read the Stack status |
test eax,eax ; if eax is zero, no driver was found |
jnz @f |
DEBUGF 1,"DHCP: No Card detected\n" |
jmp close |
cmp eax,0 ; if eax is zero, no driver was found |
jne @f |
@@: |
DEBUGF 1,"DHCP: Detected card: %x\n",eax |
@@: |
eth.check_cable eax |
test al,al |
jnz @f |
DEBUGF 1,"DHCP: Ethernet Cable not connected\n" |
if DEBUG = 1 |
dps "DHCP: No Card detected" |
newline |
end if |
mov eax,5 |
mov ebx,500 ; loop until cable is connected (check every 5 sec) |
int 0x40 |
jmp close |
jmp @r |
@@: |
if DEBUG = 1 |
dps "DHCP: Detected card: " |
dph eax |
newline |
end if |
DEBUGF 1,"DHCP: Ethernet Cable status: %d\n",al |
; now that the stack is running, lets start the dhcp request |
eth.read_mac MAC |
DEBUGF 1,"DHCP: MAC address: %x-%x-%x-%x-%x-%x\n",[MAC]:2,[MAC+1]:2,[MAC+2]:2,[MAC+3]:2,[MAC+4]:2,[MAC+5]:2 |
; First, open socket |
mov eax, 53 |
mov ebx, 0 |
mov ecx, 68 ; local port dhcp client |
mov edx, 67 ; remote port - dhcp server |
mov esi, -1 ; broadcast |
int 0x40 |
; jmp apipa ; comment this out if you want to skip DHCP and continue with link-local |
mov [socketNum], eax |
;*************************************************************************** |
; |
; DHCP rubish starts here |
; |
;*************************************************************************** |
if DEBUG = 1 |
dps "DHCP: Socket opened: " |
dpd eax |
newline |
end if |
eth.check_port 68,eax ; Check if port 68 is available |
cmp eax,1 |
je @f |
DEBUGF 1,"DHCP: Port 68 is already in use.\n" |
jmp close |
@@: |
eth.open_udp 68,67,-1,[socketNum] ; open socket (local,remote,ip,socket) |
DEBUGF 1,"DHCP: Socket opened: %d\n",eax |
; Setup the first msg we will send |
mov byte [dhcpMsgType], 0x01 ; DHCP discover |
mov dword [dhcpLease], esi ; esi is still -1 (-1 = forever) |
mov eax,26 |
mov ebx,9 |
int 0x40 |
imul eax,100 |
mov [currTime],eax |
;*************************************************************************** |
; Function |
; buildRequest |
98,10 → 127,9 |
; |
;*************************************************************************** |
buildRequest: |
; Clear dhcpMsg to all zeros |
xor eax,eax |
xor eax,eax ; Clear dhcpMsg to all zeros |
mov edi,dhcpMsg |
mov ecx,512 |
mov ecx,BUFFER |
cld |
rep stosb |
111,111 → 139,76 |
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 |
; option DHCP msg type |
mov [edx+240], word 0x0135 |
mov [edx+240], word 0x0135 ; option DHCP msg type |
mov al, [dhcpMsgType] |
mov [edx+240+2], al |
; option Lease time = infinity |
mov [edx+240+3], word 0x0433 |
mov [edx+240+3], word 0x0433 ; option Lease time = infinity |
mov eax, [dhcpLease] |
mov [edx+240+5], eax |
; ; option requested IP address |
mov [edx+240+9], word 0x0432 |
; mov eax, [dhcpClientIP] |
; mov [edx+240+11], eax |
mov [edx+240+9], word 0x0432 ; option requested IP address |
mov eax, [dhcpClientIP] |
mov [edx+240+11], eax |
; option request list |
mov [edx+240+15], word 0x0437 |
mov [edx+240+15], word 0x0437 ; option request list |
mov [edx+240+17], dword 0x0f060301 |
; Check which msg we are sending |
cmp [dhcpMsgType], byte 0x01 |
cmp [dhcpMsgType], byte 0x01 ; Check which msg we are sending |
jne br001 |
; "Discover" options |
; end of options marker |
mov [edx+240+21], byte 0xff |
mov [edx+240+21], byte 0xff ; "Discover" options |
mov [dhcpMsgLen], dword 262 |
mov [dhcpMsgLen], dword 262 ; end of options marker |
jmp ctr000 |
br001: |
; "Request" options |
br001: ; "Request" options |
; server IP |
mov [edx+240+21], word 0x0436 |
mov [edx+240+21], word 0x0436 ; server IP |
mov eax, [dhcpServerIP] |
mov [edx+240+23], eax |
; end of options marker |
mov [edx+240+27], byte 0xff |
mov [edx+240+27], byte 0xff ; end of options marker |
mov [dhcpMsgLen], dword 268 |
ctr000: |
; write to socket ( send broadcast request ) |
mov eax, 53 |
mov ebx, 4 |
mov ecx, [socketNum] |
mov edx, [dhcpMsgLen] |
mov esi, dhcpMsg |
int 0x40 |
eth.write_udp [socketNum],[dhcpMsgLen],dhcpMsg ; write to socket ( send broadcast request ) |
; Setup the DHCP buffer to receive response |
mov eax, dhcpMsg |
mov eax, dhcpMsg ; Setup the DHCP buffer to receive response |
mov [dhcpMsgLen], eax ; Used as a pointer to the data |
; now, we wait for data from remote |
wait_for_data: |
mov eax,23 ; wait here for event NOTE a TIME-OUT should be placed here |
mov ebx,TIMEOUT*100 |
mov eax,23 ; wait here for event (data from remote) |
mov ebx,TIMEOUT*10 |
int 0x40 |
; Any data in the UDP receive buffer? |
mov eax, 53 |
mov ebx, 2 |
mov ecx, [socketNum] |
int 0x40 |
eth.poll [socketNum] |
cmp eax, 0 |
jne ctr002 |
test eax,eax |
jnz ctr002 |
if DEBUG = 1 |
dps "DHCP: Timeout!" |
newline |
end if |
DEBUGF 2,"DHCP: Timeout!\n" |
eth.close_udp [socketNum] |
jmp apipa ; no server found, lets try zeroconf |
jmp close |
; we have data - this will be the response |
ctr002: |
ctr002: ; we have data - this will be the response |
eth.read_packet [socketNum], dhcpMsg, BUFFER |
mov [dhcpMsgLen], eax |
eth.close_udp [socketNum] |
mov eax, 53 |
mov ebx, 3 |
mov ecx, [socketNum] |
int 0x40 ; read byte - block (high byte) |
; Store the data in the response buffer |
mov eax, [dhcpMsgLen] |
mov [eax], bl |
inc dword [dhcpMsgLen] |
mov eax, 53 |
mov ebx, 2 |
mov ecx, [socketNum] |
int 0x40 ; any more data? |
cmp eax, 0 |
jne ctr002 ; yes, so get it |
; depending on which msg we sent, handle the response |
; accordingly. |
; If the response is to a dhcp discover, then: |
222,54 → 215,34 |
; 1) If response is DHCP OFFER then |
; 1.1) record server IP, lease time & IP address. |
; 1.2) send a request packet |
; 2) else exit ( display error ) |
; 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 |
; 2) else exit ( display error ) |
cmp [dhcpMsgType], byte 0x01 ; did we send a discover? |
je discover |
cmp [dhcpMsgType], byte 0x03 ; did we send a request? |
je request |
; should never get here - we only send discover or request |
jmp close |
jmp close ; really unknown, what we did |
discover: |
call parseResponse |
; Was the response an offer? It should be |
cmp [dhcpMsgType], byte 0x02 |
jne close ; NO - so quit |
; send request |
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 |
; Was the response an ACK? It should be |
cmp [dhcpMsgType], byte 0x05 |
jne close ; NO - so quit |
cmp [dhcpMsgType], byte 0x05 ; Was the response an ACK? It should be |
jne apipa ; NO - so we do zeroconf |
close: |
DEBUGF 1,"DHCP: Exiting\n" |
; close socket |
mov eax, 53 |
mov ebx, 1 |
mov ecx, [socketNum] |
int 0x40 |
if DEBUG = 1 |
dps "DHCP: Exiting" |
newline |
end if |
mov eax,-1 ; at last, exit |
int 0x40 |
288,47 → 261,19 |
; |
;*************************************************************************** |
parseResponse: |
if DEBUG = 1 |
dps "DHCP: Data received, parsing response" |
newline |
end if |
DEBUGF 1,"DHCP: Data received, parsing response\n" |
mov edx, dhcpMsg |
pusha |
mov eax,52 ; Set Client IP |
mov ebx,3 |
mov ecx, [edx+16] |
int 0x40 |
if DEBUG = 1 |
dps "DHCP: Client: " |
xor esi,esi |
.loop: |
pusha |
movzx eax,byte[edx+esi+16] |
call debug_outdec |
eth.set_IP [edx+16] |
mov eax,[edx] |
mov [dhcpClientIP],eax |
DEBUGF 1,"DHCP: Client: %u.%u.%u.%u\n",[edx+16]:1,[edx+17]:1,[edx+18]:1,[edx+19]:1 |
popa |
inc esi |
cmp esi,4 |
jne .loop |
newline |
end if |
popa |
; Scan options |
add edx, 240 ; Point to first option |
pr001: |
; Get option id |
mov al, [edx] |
cmp al, 0xff ; End of options? |
je pr_exit |
342,7 → 287,6 |
jmp pr001 ; Get next option |
pr002: |
; All other (accepted) options are 4 bytes in length |
inc edx |
movzx ecx, byte [edx] |
inc edx ; point to data |
351,6 → 295,7 |
jne pr0021 |
mov eax, [edx] ; All options are 4 bytes, so get it |
mov [dhcpServerIP], eax |
DEBUGF 1,"DHCP: Server: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 |
jmp pr003 |
pr0021: |
357,20 → 302,19 |
cmp al, 51 ; lease |
jne pr0022 |
if DEBUG = 1 |
pusha |
dps "DHCP: lease: " |
cmp dword[edx],-1 |
DEBUGF 1,"DHCP: lease: " |
mov eax,[edx] |
bswap eax |
mov [dhcpLease],eax |
cmp dword[edx],-1 ; i really don't know, how to test it |
jne no_lease_forever |
dps "forever" |
jmp lease_newline |
DEBUGF 1,"forever\n" |
jmp @f |
no_lease_forever: |
dpd [edx] |
lease_newline: |
newline |
DEBUGF 1,"%d\n",eax |
@@: |
popa |
end if |
jmp pr003 |
379,123 → 323,145 |
jne pr0023 |
pusha |
mov eax,52 |
mov ebx,12 |
mov ecx,[edx] |
int 0x40 |
eth.set_SUBNET [edx] |
DEBUGF 1,"DHCP: Subnet: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 |
popa |
jmp pr003 |
if DEBUG = 1 |
dps "DHCP: Subnet: " |
pr0023: |
cmp al, 3 ; gateway ip |
jne pr0024 |
xor esi,esi |
.loop: |
pusha |
movzx eax,byte[edx+esi] |
call debug_outdec |
eth.set_GATEWAY [edx] |
DEBUGF 1,"DHCP: Gateway: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 |
popa |
inc esi |
cmp esi,4 |
jne .loop |
newline |
end if |
pr0024: |
cmp al, 6 ; dns ip |
jne pr003 |
pusha |
eth.set_DNS [edx] |
DEBUGF 1,"DHCP: DNS: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1 |
popa |
jmp pr003 |
pr0023: |
cmp al, 6 ; dns ip |
jne pr0024 |
pr003: |
add edx, ecx |
jmp pr001 |
pusha |
pr_exit: |
mov eax,52 |
mov ebx,14 |
mov ecx,[edx] |
int 0x40 |
; DEBUGF 1,"DHCP: Sending ARP probe\n" |
; eth.ARP_ANNOUNCE [dhcpClientIP] ; send an ARP announc packet |
eth.get_GATEWAY eax ; if gateway was not set, set it to the DHCP SERVER IP |
test eax,eax |
jnz close |
eth.set_GATEWAY [dhcpServerIP] |
jmp close |
if DEBUG = 1 |
dps "DHCP: DNS IP: " |
apipa: |
call random |
mov ecx,0xfea9 ; IP 169.254.0.0 link local net, see RFC3927 |
mov cx,ax |
eth.set_IP ecx ; mask is 255.255.0.0 |
DEBUGF 1,"ZeroConf: Link Local IP assinged: 169.254.%u.%u\n",[generator+2]:1,[generator+3]:1 |
eth.set_SUBNET 0xffff |
eth.set_GATEWAY 0x0 |
eth.set_DNS 0x0 |
mov eax,5 |
mov ebx,PROBE_WAIT*100 |
int 0x40 |
xor esi,esi |
.loop: |
probe_loop: |
call random ; create a pseudo random number in eax (seeded by MAC) |
pusha |
movzx eax,byte[edx+esi] |
call debug_outdec |
popa |
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 |
@@: |
inc esi |
cmp esi,4 |
jne .loop |
cmp al,PROBE_MAX*100 |
jle @f |
sub al,(PROBE_MAX-PROBE_MIN)*100 |
@@: |
newline |
end if |
movzx ebx,al |
DEBUGF 1,"ZeroConf: Waiting %u0ms\n",ebx |
mov eax,5 |
int 0x40 |
popa |
DEBUGF 1,"ZeroConf: Sending Probe\n" |
; eth.ARP_PROBE MAC2 |
inc esi |
pr0024: |
cmp al, 3 ; gateway ip |
jne pr003 |
cmp esi,PROBE_NUM |
jl probe_loop |
pusha |
; now we wait further ANNOUNCE_WAIT seconds and send ANNOUNCE_NUM ARP announces. If any other host has assingnd |
; IP within this time, we should create another adress, that have to be done later |
mov eax,52 |
mov ebx,11 |
mov ecx,[edx] |
DEBUGF 1,"ZeroConf: Waiting %us\n",ANNOUNCE_WAIT |
mov eax,5 |
mov ebx,ANNOUNCE_WAIT*100 |
int 0x40 |
if DEBUG = 1 |
dps "DHCP: Gateway:" |
xor esi,esi |
.loop: |
announce_loop: |
pusha |
movzx eax,byte[edx+esi] |
call debug_outdec |
popa |
DEBUGF 1,"ZeroConf: Sending Announce\n" |
; eth.ARP_ANNOUNCE MAC2 |
inc esi |
cmp esi,4 |
jne .loop |
cmp esi,ANNOUNCE_NUM |
je @f |
newline |
end if |
DEBUGF 1,"ZeroConf: Waiting %us\n",ANNOUNCE_INTERVAL |
mov eax,5 |
mov ebx,ANNOUNCE_INTERVAL*100 |
int 0x40 |
popa |
jmp announce_loop |
@@: |
jmp close ; we should, instead of closing, detect ARP conflicts and detect if cable keeps connected ;) |
pr003: |
add edx, ecx |
jmp pr001 |
random: |
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 |
pr_exit: |
if DEBUG = 1 |
dps "DHCP: Done" |
newline |
end if |
jmp close |
; DATA AREA |
include_debug_strings ; ALWAYS present in data section |
; DATA AREA |
IM_END: |
dhcpMsgType: db 0 |
dhcpLease: dd 0 |
;dhcpClientIP: dd 0 |
dhcpServerIP: dd 0 |
dhcpClientIP dd 0 |
dhcpMsgType db 0 |
dhcpLease dd 0 |
dhcpServerIP dd 0 |
dhcpMsgLen: dd 0 |
socketNum: dd 0xFFFF |
dhcpMsg: rb 512 |
dhcpMsgLen dd 0 |
socketNum dd 0 |
MAC rb 6 |
currTime dd 0 |
renewTime dd 0 |
generator dd 0 |
dhcpMsg rb BUFFER |
I_END: |
/programs/network/autodhcp/trunk/debug-fdo.inc |
---|
0,0 → 1,422 |
; |
; Formatted Debug Output (FDO) |
; Copyright (c) 2005-2006, mike.dld |
; Created: 2005-01-29, Changed: 2006-11-10 |
; |
; For questions and bug reports, mail to mike.dld@gmail.com |
; |
; Available format specifiers are: %s, %d, %u, %x (with partial width support) |
; |
; to be defined: |
; __DEBUG__ equ 1 |
; __DEBUG_LEVEL__ equ 5 |
macro debug_func name { |
if used name |
name@of@func equ name |
} |
macro debug_beginf { |
align 4 |
name@of@func: |
} |
debug_endf fix end if |
macro DEBUGS _sign,[_str] { |
common |
local tp |
tp equ 0 |
match _arg:_num,_str \{ |
DEBUGS_N _sign,_num,_arg |
tp equ 1 |
\} |
match =0 _arg,tp _str \{ |
DEBUGS_N _sign,,_arg |
\} |
} |
macro DEBUGS_N _sign,_num,[_str] { |
common |
pushf |
pushad |
local ..str,..label,is_str |
is_str = 0 |
forward |
if _str eqtype '' |
is_str = 1 |
end if |
common |
if is_str = 1 |
jmp ..label |
..str db _str,0 |
..label: |
add esp,4*8+4 |
mov edx,..str |
sub esp,4*8+4 |
else |
mov edx,_str |
end if |
if ~_num eq |
if _num eqtype eax |
if _num in <eax,ebx,ecx,edx,edi,ebp,esp> |
mov esi,_num |
else if ~_num eq esi |
movzx esi,_num |
end if |
else if _num eqtype 0 |
mov esi,_num |
else |
local tp |
tp equ 0 |
match [_arg],_num \{ |
mov esi,dword[_arg] |
tp equ 1 |
\} |
match =0 =dword[_arg],tp _num \{ |
mov esi,dword[_arg] |
tp equ 1 |
\} |
match =0 =word[_arg],tp _num \{ |
movzx esi,word[_arg] |
tp equ 1 |
\} |
match =0 =byte[_arg],tp _num \{ |
movzx esi,byte[_arg] |
tp equ 1 |
\} |
match =0,tp \{ |
'Error: specified string width is incorrect' |
\} |
end if |
else |
mov esi,0x7FFFFFFF |
end if |
call fdo_debug_outstr |
popad |
popf |
} |
macro DEBUGD _sign,_dec { |
local tp |
tp equ 0 |
match _arg:_num,_dec \{ |
DEBUGD_N _sign,_num,_arg |
tp equ 1 |
\} |
match =0 _arg,tp _dec \{ |
DEBUGD_N _sign,,_arg |
\} |
} |
macro DEBUGD_N _sign,_num,_dec { |
pushf |
pushad |
if (~_num eq) |
if (_dec eqtype eax | _dec eqtype 0) |
'Error: precision allowed only for in-memory variables' |
end if |
if (~_num in <1,2,4>) |
if _sign |
'Error: 1, 2 and 4 are only allowed for precision in %d' |
else |
'Error: 1, 2 and 4 are only allowed for precision in %u' |
end if |
end if |
end if |
if _dec eqtype eax |
if _dec in <ebx,ecx,edx,esi,edi,ebp,esp> |
mov eax,_dec |
else if ~_dec eq eax |
if _sign = 1 |
movsx eax,_dec |
else |
movzx eax,_dec |
end if |
end if |
else if _dec eqtype 0 |
mov eax,_dec |
else |
add esp,4*8+4 |
if _num eq |
mov eax,dword _dec |
else if _num = 1 |
if _sign = 1 |
movsx eax,byte _dec |
else |
movzx eax,byte _dec |
end if |
else if _num = 2 |
if _sign = 1 |
movsx eax,word _dec |
else |
movzx eax,word _dec |
end if |
else |
mov eax,dword _dec |
end if |
sub esp,4*8+4 |
end if |
mov cl,_sign |
call fdo_debug_outdec |
popad |
popf |
} |
macro DEBUGH _sign,_hex { |
local tp |
tp equ 0 |
match _arg:_num,_hex \{ |
DEBUGH_N _sign,_num,_arg |
tp equ 1 |
\} |
match =0 _arg,tp _hex \{ |
DEBUGH_N _sign,,_arg |
\} |
} |
macro DEBUGH_N _sign,_num,_hex { |
pushf |
pushad |
if (~_num eq) & (~_num in <1,2,3,4,5,6,7,8>) |
'Error: 1..8 are only allowed for precision in %x' |
end if |
if _hex eqtype eax |
if _hex in <eax,ebx,ecx,edx,esi,edi,ebp,esp> |
if ~_hex eq eax |
mov eax,_hex |
end if |
else if _hex in <ax,bx,cx,dx,si,di,bp,sp> |
if ~_hex eq ax |
movzx eax,_hex |
end if |
shl eax,16 |
if (_num eq) |
mov edx,4 |
end if |
else if _hex in <al,ah,bl,bh,cl,ch,dl,dh> |
if ~_hex eq al |
movzx eax,_hex |
end if |
shl eax,24 |
if (_num eq) |
mov edx,2 |
end if |
end if |
else if _hex eqtype 0 |
mov eax,_hex |
else |
add esp,4*8+4 |
mov eax,dword _hex |
sub esp,4*8+4 |
end if |
if ~_num eq |
mov edx,_num |
else |
mov edx,8 |
end if |
call fdo_debug_outhex |
popad |
popf |
} |
;----------------------------------------------------------------------------- |
debug_func fdo_debug_outchar |
debug_beginf |
pushad |
mov cl,al |
mov ebx,1 |
mov eax,63 |
int 0x40 |
popad |
ret |
debug_endf |
debug_func fdo_debug_outstr |
debug_beginf |
mov eax,63 |
mov ebx,1 |
.l1: dec esi |
js .l2 |
mov cl,[edx] |
or cl,cl |
jz .l2 |
int 0x40 |
inc edx |
jmp .l1 |
.l2: ret |
debug_endf |
debug_func fdo_debug_outdec |
debug_beginf |
or cl,cl |
jz @f |
or eax,eax |
jns @f |
neg eax |
push eax |
mov al,'-' |
call fdo_debug_outchar |
pop eax |
@@: push 10 |
pop ecx |
push -'0' |
.l1: xor edx,edx |
div ecx |
push edx |
test eax,eax |
jnz .l1 |
.l2: pop eax |
add al,'0' |
jz .l3 |
call fdo_debug_outchar |
jmp .l2 |
.l3: ret |
debug_endf |
debug_func fdo_debug_outhex |
__fdo_hexdigits db '0123456789ABCDEF' |
debug_beginf |
mov cl,dl |
neg cl |
add cl,8 |
shl cl,2 |
rol eax,cl |
.l1: rol eax,4 |
push eax |
and eax,0x0000000F |
mov al,[__fdo_hexdigits+eax] |
call fdo_debug_outchar |
pop eax |
dec edx |
jnz .l1 |
ret |
debug_endf |
;----------------------------------------------------------------------------- |
macro DEBUGF _level,_format,[_arg] { |
common |
if __DEBUG__ = 1 & _level >= __DEBUG_LEVEL__ |
local ..f1,f2,a1,a2,c1,c2,c3,..lbl |
_debug_str_ equ __debug_str_ # a1 |
a1 = 0 |
c2 = 0 |
c3 = 0 |
f2 = 0 |
repeat ..lbl-..f1 |
virtual at 0 |
db _format,0,0 |
load c1 word from %-1 |
end virtual |
if c1 = '%s' |
virtual at 0 |
db _format,0,0 |
store word 0 at %-1 |
load c1 from f2-c2 |
end virtual |
if c1 <> 0 |
DEBUGS 0,_debug_str_+f2-c2 |
end if |
c2 = c2 + 1 |
f2 = %+1 |
DEBUGF_HELPER S,a1,0,_arg |
else if c1 = '%x' |
virtual at 0 |
db _format,0,0 |
store word 0 at %-1 |
load c1 from f2-c2 |
end virtual |
if c1 <> 0 |
DEBUGS 0,_debug_str_+f2-c2 |
end if |
c2 = c2 + 1 |
f2 = %+1 |
DEBUGF_HELPER H,a1,0,_arg |
else if c1 = '%d' | c1 = '%u' |
local c4 |
if c1 = '%d' |
c4 = 1 |
else |
c4 = 0 |
end if |
virtual at 0 |
db _format,0,0 |
store word 0 at %-1 |
load c1 from f2-c2 |
end virtual |
if c1 <> 0 |
DEBUGS 0,_debug_str_+f2-c2 |
end if |
c2 = c2 + 1 |
f2 = %+1 |
DEBUGF_HELPER D,a1,c4,_arg |
else if c1 = '\n' |
c3 = c3 + 1 |
end if |
end repeat |
virtual at 0 |
db _format,0,0 |
load c1 from f2-c2 |
end virtual |
if (c1<>0)&(f2<>..lbl-..f1-1) |
DEBUGS 0,_debug_str_+f2-c2 |
end if |
virtual at 0 |
..f1 db _format,0 |
..lbl: |
__debug_strings equ __debug_strings,_debug_str_,<_format>,..lbl-..f1-1-c2-c3 |
end virtual |
end if |
} |
macro __include_debug_strings dummy,[_id,_fmt,_len] { |
common |
local c1,a1,a2 |
forward |
if defined _len & ~_len eq |
_id: |
a1 = 0 |
a2 = 0 |
repeat _len |
virtual at 0 |
db _fmt,0,0 |
load c1 word from %+a2-1 |
end virtual |
if (c1='%s')|(c1='%x')|(c1='%d')|(c1='%u') |
db 0 |
a2 = a2 + 1 |
else if (c1='\n') |
dw $0A0D |
a1 = a1 + 1 |
a2 = a2 + 1 |
else |
db c1 and 0x0FF |
end if |
end repeat |
db 0 |
end if |
} |
macro DEBUGF_HELPER _letter,_num,_sign,[_arg] { |
common |
local num |
num = 0 |
forward |
if num = _num |
DEBUG#_letter _sign,_arg |
end if |
num = num+1 |
common |
_num = _num+1 |
} |
macro include_debug_strings { |
if __DEBUG__ = 1 |
match dbg_str,__debug_strings \{ |
__include_debug_strings dbg_str |
\} |
end if |
} |