From ef27b83e97fa20492d8b6a5d800236f30b7a7221 Mon Sep 17 00:00:00 2001 From: hidnplayr Date: Sat, 10 Feb 2007 14:01:21 +0000 Subject: [PATCH] DHCP client now sends MAC address to dhcp server. It also uses new system functions 53-10 and 53-11 Link-local ip support is under construction (problem with kernel ARP functions) git-svn-id: svn://kolibrios.org@336 a494cfbc-eb01-0410-851d-a64ba20cac60 --- programs/network/autodhcp/trunk/ETH.INC | 619 ++++++++++++++++++ programs/network/autodhcp/trunk/autodhcp.asm | 548 ++++++++-------- programs/network/autodhcp/trunk/debug-fdo.inc | 422 ++++++++++++ programs/network/autodhcp/trunk/debug.inc | 131 ---- 4 files changed, 1298 insertions(+), 422 deletions(-) create mode 100644 programs/network/autodhcp/trunk/ETH.INC create mode 100644 programs/network/autodhcp/trunk/debug-fdo.inc delete mode 100644 programs/network/autodhcp/trunk/debug.inc diff --git a/programs/network/autodhcp/trunk/ETH.INC b/programs/network/autodhcp/trunk/ETH.INC new file mode 100644 index 0000000000..ce8f905226 --- /dev/null +++ b/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 + + + + diff --git a/programs/network/autodhcp/trunk/autodhcp.asm b/programs/network/autodhcp/trunk/autodhcp.asm index 95826facc5..d50cbd6669 100644 --- a/programs/network/autodhcp/trunk/autodhcp.asm +++ b/programs/network/autodhcp/trunk/autodhcp.asm @@ -1,16 +1,17 @@ -; ; Automated dhcp client +; v 1.3 ; -; v 1.1 -; -; by the hidden player +; with thanks to authors of DHCP client for menuetos: Mike Hibbet ; +; 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,73 +22,101 @@ use32 dd I_END ; esp dd 0x0 , 0x0 ; I_Param , I_Icon -include 'macros.inc' - -if DEBUG = 1 -include 'debug.inc' -end if +;include 'macros.inc' +include 'eth.inc' +include 'debug-fdo.inc' -START: ; start of execution + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; 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) ; + ; ; + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - mov eax,40 ; Report events - mov ebx,10000000b ; Only Stack + +START: ; start of execution + + mov eax,40 ; Report events + 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 - - cmp eax,0 ; if eax is zero, no driver was found - jne @f - -if DEBUG = 1 - dps "DHCP: No Card detected" - newline -end if - - jmp close + 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 @@: -if DEBUG = 1 - dps "DHCP: Detected card: " - dph eax - newline -end if + 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" - ; now that the stack is running, lets start the dhcp request - - ; 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 + mov eax,5 + mov ebx,500 ; loop until cable is connected (check every 5 sec) int 0x40 - mov [socketNum], eax + jmp @r -if DEBUG = 1 - dps "DHCP: Socket opened: " - dpd eax - newline -end if + @@: + DEBUGF 1,"DHCP: Ethernet Cable status: %d\n",al - ; Setup the first msg we will send - mov byte [dhcpMsgType], 0x01 ; DHCP discover - mov dword [dhcpLease], esi ; esi is still -1 (-1 = forever) + 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 + +; jmp apipa ; comment this out if you want to skip DHCP and continue with link-local + +;*************************************************************************** +; +; DHCP rubish starts here +; +;*************************************************************************** + + + + 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 @@ -98,10 +127,9 @@ end if ; ;*************************************************************************** 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,110 +139,75 @@ buildRequest: 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 + eth.write_udp [socketNum],[dhcpMsgLen],dhcpMsg ; 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 + + mov eax,23 ; wait here for event (data from remote) + mov ebx,TIMEOUT*10 int 0x40 - ; Setup the DHCP buffer to receive response + eth.poll [socketNum] - mov eax, dhcpMsg - mov [dhcpMsgLen], eax ; Used as a pointer to the data + test eax,eax + jnz ctr002 - ; now, we wait for data from remote + DEBUGF 2,"DHCP: Timeout!\n" + eth.close_udp [socketNum] + jmp apipa ; no server found, lets try zeroconf -wait_for_data: - mov eax,23 ; wait here for event NOTE a TIME-OUT should be placed here - mov ebx,TIMEOUT*100 - int 0x40 - ; Any data in the UDP receive buffer? - mov eax, 53 - mov ebx, 2 - mov ecx, [socketNum] - int 0x40 - - cmp eax, 0 - jne ctr002 - -if DEBUG = 1 - dps "DHCP: Timeout!" - newline -end if - - jmp close - - ; we have data - this will be the response -ctr002: - - 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 +ctr002: ; we have data - this will be the response + eth.read_packet [socketNum], dhcpMsg, BUFFER + mov [dhcpMsgLen], eax + eth.close_udp [socketNum] ; depending on which msg we sent, handle the response ; accordingly. @@ -222,55 +215,35 @@ ctr002: ; 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? + cmp [dhcpMsgType], byte 0x01 ; did we send a discover? je discover - cmp [dhcpMsgType], byte 0x03 ; did we send a request? + 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 - mov [dhcpMsgType], byte 0x03 ; DHCP 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 - 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 + mov eax,-1 ; at last, exit int 0x40 @@ -288,47 +261,19 @@ end if ; ;*************************************************************************** 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 @@ pr001: 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,26 +295,26 @@ pr002: 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: 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,97 +323,31 @@ pr0022: jne pr0023 pusha - mov eax,52 - mov ebx,12 - mov ecx,[edx] - int 0x40 - - -if DEBUG = 1 - dps "DHCP: Subnet: " - - xor esi,esi - .loop: - - pusha - movzx eax,byte[edx+esi] - call debug_outdec - popa - - inc esi - cmp esi,4 - jne .loop - - newline -end if - + 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 pr0023: - cmp al, 6 ; dns ip + cmp al, 3 ; gateway ip jne pr0024 pusha - - mov eax,52 - mov ebx,14 - mov ecx,[edx] - int 0x40 - - -if DEBUG = 1 - dps "DHCP: DNS IP: " - - 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 - - popa pr0024: - cmp al, 3 ; gateway ip + cmp al, 6 ; dns ip jne pr003 pusha - - mov eax,52 - mov ebx,11 - mov ecx,[edx] - int 0x40 - - -if DEBUG = 1 - dps "DHCP: Gateway:" - - xor esi,esi - .loop: - - pusha - movzx eax,byte[edx+esi] - call debug_outdec + 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 - inc esi - cmp esi,4 - jne .loop - - newline -end if - - popa pr003: add edx, ecx @@ -477,25 +355,113 @@ pr003: pr_exit: -if DEBUG = 1 - dps "DHCP: Done" - newline -end if +; 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 +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 + 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,"ZeroConf: Waiting %u0ms\n",ebx + mov eax,5 + int 0x40 + + DEBUGF 1,"ZeroConf: Sending Probe\n" +; eth.ARP_PROBE MAC2 + 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 assingnd +; IP within this time, we should create another adress, that have to be done later + + DEBUGF 1,"ZeroConf: Waiting %us\n",ANNOUNCE_WAIT + mov eax,5 + mov ebx,ANNOUNCE_WAIT*100 + int 0x40 + + xor esi,esi + announce_loop: + + DEBUGF 1,"ZeroConf: Sending Announce\n" +; eth.ARP_ANNOUNCE MAC2 + + inc esi + cmp esi,ANNOUNCE_NUM + je @f + + DEBUGF 1,"ZeroConf: Waiting %us\n",ANNOUNCE_INTERVAL + mov eax,5 + mov ebx,ANNOUNCE_INTERVAL*100 + int 0x40 + + jmp announce_loop + @@: + jmp close ; we should, instead of closing, detect ARP conflicts and detect if cable keeps connected ;) + +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 + + ; DATA AREA +include_debug_strings ; ALWAYS present in data section + 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: \ No newline at end of file diff --git a/programs/network/autodhcp/trunk/debug-fdo.inc b/programs/network/autodhcp/trunk/debug-fdo.inc new file mode 100644 index 0000000000..ecfd0fcc84 --- /dev/null +++ b/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 + 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 + 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 + if ~_hex eq eax + mov eax,_hex + end if + else if _hex in + if ~_hex eq ax + movzx eax,_hex + end if + shl eax,16 + if (_num eq) + mov edx,4 + end if + else if _hex in + 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 +} diff --git a/programs/network/autodhcp/trunk/debug.inc b/programs/network/autodhcp/trunk/debug.inc deleted file mode 100644 index f58479019a..0000000000 --- a/programs/network/autodhcp/trunk/debug.inc +++ /dev/null @@ -1,131 +0,0 @@ -macro debug_print str -{ - local ..string, ..label - - jmp ..label - ..string db str,0 - ..label: - - pushf - pushad - mov edx,..string - call debug_outstr - popad - popf -} - -dps fix debug_print - -macro debug_print_dec arg -{ - pushf - pushad - if ~arg eq eax - mov eax,arg - end if - call debug_outdec - popad - popf -} - -dpd fix debug_print_dec - -;--------------------------------- -debug_outdec: ;(eax - num, edi-str) - push 10 ;2 - pop ecx ;1 - push -'0' ;2 - .l0: - xor edx,edx ;2 - div ecx ;2 - push edx ;1 - test eax,eax ;2 - jnz .l0 ;2 - .l1: - pop eax ;1 - add al,'0' ;2 - call debug_outchar ; stosb - jnz .l1 ;2 - ret ;1 -;--------------------------------- - -debug_outchar: ; al - char - pushf - pushad - mov cl,al - mov eax,63 - mov ebx,1 - int 0x40 - popad - popf -ret - -debug_outstr: - mov eax,63 - mov ebx,1 - @@: - mov cl,[edx] - test cl,cl - jz @f - int 40h - inc edx - jmp @b - @@: - ret - - -macro newline -{ - dps <13,10> -} - -macro print message -{ - dps message - newline -} - -macro pregs -{ - dps "EAX: " - dpd eax - dps " EBX: " - dpd ebx - newline - dps "ECX: " - dpd ecx - dps " EDX: " - dpd edx - newline -} - -macro debug_print_hex arg -{ - pushf - pushad - if ~arg eq eax - mov eax, arg - end if - call debug_outhex - popad - popf -} -dph fix debug_print_hex - -debug_outhex: - ; eax - number - mov edx, 8 - .new_char: - rol eax, 4 - movzx ecx, al - and cl, 0x0f - mov cl, [__hexdigits + ecx] - pushad - mcall 63, 1 - popad - dec edx - jnz .new_char -ret - -__hexdigits: - db '0123456789ABCDEF' \ No newline at end of file