Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. ; Zero-config
  2. ; v 1.4
  3. ;
  4. ; DHCP code is based on that by Mike Hibbet (DHCP client for menuetos)
  5. ;
  6. ; Written by HidnPlayr & Derpenguin
  7.  
  8. use32
  9.                org    0x0
  10.  
  11.                db     'MENUET01'            ; 8 byte id
  12.                dd     0x01                  ; header version
  13.                dd     START                 ; start of code
  14.                dd     IM_END                ; size of image
  15.                dd     I_END                 ; memory for app
  16.                dd     I_END                 ; esp
  17.                dd     0x0 , path             ; I_Param , I_Icon
  18.  
  19. ; CONFIGURATION
  20.  
  21.  
  22. TIMEOUT             equ 60                  ; in seconds
  23. BUFFER              equ 1024                ; in bytes
  24. __DEBUG__           equ 1                   ; enable/disable
  25. __DEBUG_LEVEL__     equ 1                   ; 1 = all, 2 = errors
  26.  
  27. ; CONFIGURATION FOR LINK-LOCAL
  28.  
  29. PROBE_WAIT          equ 1                   ; second  (initial random delay)
  30. PROBE_MIN           equ 1                   ; second  (minimum delay till repeated probe)
  31. PROBE_MAX           equ 2                   ; seconds (maximum delay till repeated probe)
  32. PROBE_NUM           equ 3                   ;         (number of probe packets)
  33.  
  34. ANNOUNCE_NUM        equ 2                   ;         (number of announcement packets)
  35. ANNOUNCE_INTERVAL   equ 2                   ; seconds (time between announcement packets)
  36. ANNOUNCE_WAIT       equ 2                   ; seconds (delay before announcing)
  37.  
  38. MAX_CONFLICTS       equ 10                  ;         (max conflicts before rate limiting)
  39.  
  40. RATE_LIMIT_INTERVAL equ 60                  ; seconds (delay between successive attempts)
  41.  
  42. DEFEND_INTERVAL     equ 10                  ; seconds (min. wait between defensive ARPs)
  43.  
  44. include '../../../proc32.inc'
  45. include '../../../macros.inc'
  46. include 'eth.inc'
  47. include 'debug-fdo.inc'
  48. include 'dhcp.inc'
  49. include 'dll.inc'
  50.  
  51. START:                                      ; start of execution
  52.  
  53.     mcall 40, 0
  54.  
  55.     eth.set_network_drv 0x00000383
  56.  
  57.     DEBUGF  1,"Zero-config service:\n"
  58.  
  59.     eth.status eax                          ; Read the Stack status
  60.     test    eax,eax                         ; if eax is zero, no driver was found
  61.     jnz     @f
  62.     DEBUGF  1,"No Card found!\n"
  63.     jmp     close
  64.  
  65.    @@:
  66.     DEBUGF  1,"Detected card: %x\n",eax
  67.    @@:
  68.     eth.check_cable eax
  69.     test    al,al
  70.     jnz     @f
  71.     DEBUGF  1,"Cable disconnected!\n"
  72.     mcall   5, 500                          ; loop until cable is connected (check every 5 sec)
  73.     jmp     @r
  74.  
  75.    @@:
  76.     eth.read_mac MAC
  77.     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
  78.  
  79.     cld
  80.     mov     edi, path      ; Calculate the length of zero-terminated string
  81.     xor     al , al
  82.     mov     ecx, 1024
  83.     repnz   scas byte[es:edi]
  84.     dec     edi
  85.  
  86.     mov     esi, filename
  87.     mov     ecx, 5
  88.     rep     movsb
  89.  
  90.     mcall 64,1,I_END_2
  91.     mcall 68,11
  92.  
  93.     stdcall dll.Load,@IMPORT
  94.     or      eax,eax
  95.     jnz     skip_ini
  96.  
  97.  
  98.     invoke ini.get_str, path, str_ipconfig, str_type, inibuf, 16, 0
  99.  
  100.     mov  eax,dword[inibuf]
  101.  
  102.     cmp  eax,'stat'
  103.     jne  skip_ini
  104.  
  105.     invoke ini.get_str, path, str_ipconfig, str_ip, inibuf, 16, 0
  106.     mov    edx, inibuf
  107.     call   Ip2dword
  108.     eth.set_IP edx
  109.  
  110.     invoke ini.get_str, path, str_ipconfig, str_gateway, inibuf, 16, 0
  111.     mov    edx, inibuf
  112.     call   Ip2dword
  113.     eth.set_GATEWAY edx
  114.  
  115.     invoke ini.get_str, path, str_ipconfig, str_dns, inibuf, 16, 0
  116.     mov    edx, inibuf
  117.     call   Ip2dword
  118.     eth.set_DNS edx
  119.  
  120.     invoke ini.get_str, path, str_ipconfig, str_subnet, inibuf, 16, 0
  121.     mov    edx, inibuf
  122.     call   Ip2dword
  123.     eth.set_SUBNET edx
  124.  
  125.  
  126.     mcall  -1
  127.  
  128.  
  129. skip_ini:
  130.  
  131.     eth.check_port 68,eax                   ; Check if port 68 is available
  132.     cmp     eax,1
  133.     je      @f
  134.  
  135.     DEBUGF  1,"Port 68 is already in use!\n"
  136.     jmp     close
  137.  
  138.    @@:
  139.     eth.open_udp 68,67,-1,[socketNum]       ; open socket (local,remote,ip,socket)
  140.                                             ; Setup the first msg we will send
  141.     mov     byte [dhcpMsgType], 0x01        ; DHCP discover
  142.     mov     dword [dhcpLease], esi          ; esi is still -1 (-1 = forever)
  143.  
  144.     mcall   26, 9
  145.     imul    eax,100
  146.     mov     [currTime],eax
  147.  
  148. buildRequest:                               ; Creates a DHCP request packet.
  149.     stdcall mem.Alloc, BUFFER
  150.     mov     [dhcpMsg], eax
  151.     test    eax,eax
  152.     jz      apipa
  153.  
  154.  
  155.     mov     edi, eax
  156.     mov     ecx,BUFFER
  157.     xor     eax,eax
  158.     cld
  159.     rep     stosb
  160.  
  161.     mov     edx,[dhcpMsg]
  162.  
  163.     mov     [edx], byte 0x01                ; Boot request
  164.     mov     [edx+1], byte 0x01              ; Ethernet
  165.     mov     [edx+2], byte 0x06              ; Ethernet h/w len
  166.     mov     [edx+4], dword 0x11223344       ; xid
  167.     mov     eax,[currTime]
  168.     mov     [edx+8], eax                    ; secs, our uptime
  169.     mov     [edx+10], byte 0x80             ; broadcast flag set
  170.     mov     eax, dword [MAC]                ; first 4 bytes of MAC
  171.     mov     [edx+28],dword eax
  172.     mov     ax, word [MAC+4]                ; last 2 bytes of MAC
  173.     mov     [edx+32],word ax
  174.     mov     [edx+236], dword 0x63538263     ; magic number
  175.     mov     [edx+240], word 0x0135          ; option DHCP msg type
  176.     mov     al, [dhcpMsgType]
  177.     mov     [edx+240+2], al
  178.     mov     [edx+240+3], word 0x0433        ; option Lease time = infinity
  179.     mov     eax, [dhcpLease]
  180.     mov     [edx+240+5], eax
  181.     mov     [edx+240+9], word 0x0432        ; option requested IP address
  182.     mov     eax, [dhcpClientIP]
  183.     mov     [edx+240+11], eax
  184.     mov     [edx+240+15], word 0x0437       ; option request list
  185.     mov     [edx+240+17], dword 0x0f060301
  186.  
  187.     cmp     [dhcpMsgType], byte 0x01        ; Check which msg we are sending
  188.     jne     request_options
  189.  
  190.     mov     [edx+240+21], byte 0xff         ; "Discover" options
  191.  
  192.     mov     [dhcpMsgLen], dword 262         ; end of options marker
  193.     jmp     send_request
  194.  
  195. request_options:
  196.     mov     [edx+240+21], word 0x0436       ; server IP
  197.     mov     eax, [dhcpServerIP]
  198.     mov     [edx+240+23], eax
  199.  
  200.     mov     [edx+240+27], byte 0xff         ; end of options marker
  201.  
  202.     mov     [dhcpMsgLen], dword 268
  203.  
  204. send_request:
  205.     eth.write_udp [socketNum],[dhcpMsgLen],[dhcpMsg] ; write to socket ( send broadcast request )
  206.  
  207.     mov     eax, [dhcpMsg]                    ; Setup the DHCP buffer to receive response
  208.     mov     [dhcpMsgLen], eax               ; Used as a pointer to the data
  209.  
  210.     mov     eax,23                          ; wait here for event (data from remote)
  211.     mov     ebx,TIMEOUT*10
  212.     mcall
  213.  
  214.     eth.poll [socketNum]
  215.  
  216.     test    eax,eax
  217.     jnz     read_data
  218.  
  219.     DEBUGF  2,"Timeout!\n"
  220.     eth.close_udp [socketNum]
  221.     jmp    apipa                            ; no server found, lets try zeroconf
  222.  
  223.  
  224. read_data:                                  ; we have data - this will be the response
  225.     eth.read_packet [socketNum], [dhcpMsg], BUFFER
  226.     mov     [dhcpMsgLen], eax
  227.     eth.close_udp [socketNum]
  228.  
  229.     ; depending on which msg we sent, handle the response
  230.     ; accordingly.
  231.     ; If the response is to a dhcp discover, then:
  232.     ;  1) If response is DHCP OFFER then
  233.     ;  1.1) record server IP, lease time & IP address.
  234.     ;  1.2) send a request packet
  235.     ; If the response is to a dhcp request, then:
  236.     ;  1) If the response is DHCP ACK then
  237.     ;  1.1) extract the DNS & subnet fields. Set them in the stack
  238.  
  239.     cmp     [dhcpMsgType], byte 0x01        ; did we send a discover?
  240.     je      discover
  241.     cmp     [dhcpMsgType], byte 0x03        ; did we send a request?
  242.     je      request
  243.  
  244.     jmp     close                           ; really unknown, what we did
  245.  
  246. discover:
  247.     call    parseResponse
  248.  
  249.     cmp     [dhcpMsgType], byte 0x02        ; Was the response an offer?
  250.     jne     apipa                           ; NO - so we do zeroconf
  251.     mov     [dhcpMsgType], byte 0x03        ; DHCP request
  252.     jmp     buildRequest
  253.  
  254. request:
  255.     call    parseResponse
  256.  
  257.     cmp     [dhcpMsgType], byte 0x05        ; Was the response an ACK? It should be
  258.     jne     apipa                           ; NO - so we do zeroconf
  259.  
  260.     jmp     close
  261.  
  262. ;***************************************************************************
  263. ;   Function
  264. ;      parseResponse
  265. ;
  266. ;   Description
  267. ;      extracts the fields ( client IP address and options ) from
  268. ;      a DHCP response
  269. ;      The values go into
  270. ;       dhcpMsgType,dhcpLease,dhcpClientIP,dhcpServerIP,
  271. ;       dhcpDNSIP, dhcpSubnet
  272. ;      The message is stored in dhcpMsg
  273. ;
  274. ;***************************************************************************
  275. parseResponse:
  276.     DEBUGF  1,"Data received, parsing response\n"
  277.     mov     edx, [dhcpMsg]
  278.  
  279.     pusha
  280.     eth.set_IP [edx+16]
  281.     mov     eax,[edx]
  282.     mov     [dhcpClientIP],eax
  283.     DEBUGF  1,"Client: %u.%u.%u.%u\n",[edx+16]:1,[edx+17]:1,[edx+18]:1,[edx+19]:1
  284.     popa
  285.  
  286.     add     edx, 240                        ; Point to first option
  287.     xor     ecx, ecx
  288.  
  289. next_option:
  290.     add     edx, ecx
  291. pr001:
  292.     mov     al, [edx]
  293.     cmp     al, 0xff                        ; End of options?
  294.     je      pr_exit
  295.  
  296.     cmp     al, dhcp_msg_type               ; Msg type is a single byte option
  297.     jne     @f
  298.  
  299.     mov     al, [edx+2]
  300.     mov     [dhcpMsgType], al
  301.     add     edx, 3
  302.     jmp     pr001                           ; Get next option
  303.  
  304. @@:
  305.     inc     edx
  306.     movzx   ecx, byte [edx]
  307.     inc     edx                             ; point to data
  308.  
  309.     cmp     al, dhcp_dhcp_server_id         ; server ip
  310.     jne     @f
  311.     mov     eax, [edx]
  312.     mov     [dhcpServerIP], eax
  313.     DEBUGF  1,"Server: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
  314.     jmp     next_option
  315.  
  316. @@:
  317.     cmp     al, dhcp_address_time
  318.     jne     @f
  319.  
  320.     pusha
  321.     mov     eax,[edx]
  322.     bswap   eax
  323.     mov     [dhcpLease],eax
  324.     DEBUGF  1,"lease: %d\n",eax
  325.     popa
  326.  
  327.     jmp     next_option
  328.  
  329. @@:
  330.     cmp     al, dhcp_subnet_mask
  331.     jne     @f
  332.  
  333.     pusha
  334.     eth.set_SUBNET [edx]
  335.     DEBUGF  1,"Subnet: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
  336.     popa
  337.  
  338.     jmp     next_option
  339.  
  340. @@:
  341.     cmp     al, dhcp_router
  342.     jne     @f
  343.  
  344.     pusha
  345.     eth.set_GATEWAY [edx]
  346.     DEBUGF  1,"Gateway: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
  347.     popa
  348.  
  349.     jmp     next_option
  350.  
  351.  
  352. @@:
  353.     cmp     al, dhcp_domain_server
  354.     jne     next_option
  355.  
  356.     pusha
  357.     eth.set_DNS [edx]
  358.     DEBUGF  1,"DNS: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
  359.     popa
  360.  
  361.     jmp     next_option
  362.  
  363. pr_exit:
  364.  
  365. ;    DEBUGF  1,"Sending ARP announce\n"
  366. ;    eth.ARP_ANNOUNCE [dhcpClientIP]         ; send an ARP announce packet
  367.  
  368.     jmp close
  369.  
  370. apipa:
  371.     stdcall mem.Free, [dhcpMsg]
  372.  
  373. link_local:
  374.     call random
  375.     mov  ecx,0xfea9                         ; IP 169.254.0.0 link local net, see RFC3927
  376.     mov  cx,ax
  377.     eth.set_IP ecx                          ; mask is 255.255.0.0
  378.     DEBUGF 1,"Link Local IP assinged: 169.254.%u.%u\n",[generator+2]:1,[generator+3]:1
  379.     eth.set_SUBNET 0xffff
  380.     eth.set_GATEWAY 0x0
  381.     eth.set_DNS 0x0
  382.  
  383.     mcall 5, PROBE_WAIT*100
  384.  
  385.     xor esi,esi
  386.    probe_loop:
  387.     call  random                            ; create a pseudo random number in eax (seeded by MAC)
  388.  
  389.     cmp   al,PROBE_MIN*100                  ; check if al is bigger then PROBE_MIN
  390.     jge   @f                                ; all ok
  391.     add   al,(PROBE_MAX-PROBE_MIN)*100      ; al is too small
  392.    @@:
  393.  
  394.     cmp   al,PROBE_MAX*100
  395.     jle   @f
  396.     sub   al,(PROBE_MAX-PROBE_MIN)*100
  397.    @@:
  398.  
  399.     movzx ebx,al
  400.     DEBUGF  1,"Waiting %u0ms\n",ebx
  401.     mcall 5
  402.  
  403.     DEBUGF  1,"Sending Probe\n"
  404. ;    eth.ARP_PROBE MAC
  405.     inc   esi
  406.  
  407.     cmp   esi,PROBE_NUM
  408.     jl    probe_loop
  409.  
  410. ; now we wait further ANNOUNCE_WAIT seconds and send ANNOUNCE_NUM ARP announces. If any other host has assingned
  411. ; IP within this time, we should create another adress, that have to be done later
  412.  
  413.     DEBUGF  1,"Waiting %us\n",ANNOUNCE_WAIT
  414.     mcall 5, ANNOUNCE_WAIT*100
  415.     xor   esi,esi
  416.    announce_loop:
  417.  
  418.     DEBUGF  1,"Sending Announce\n"
  419. ;    eth.ARP_ANNOUNCE MAC
  420.  
  421.     inc   esi
  422.     cmp   esi,ANNOUNCE_NUM
  423.     je    @f
  424.  
  425.     DEBUGF  1,"Waiting %us\n",ANNOUNCE_INTERVAL
  426.     mcall 5, ANNOUNCE_INTERVAL*100
  427.     jmp   announce_loop
  428.    @@:
  429.     ; we should, instead of closing, detect ARP conflicts and detect if cable keeps connected ;)
  430.  
  431. close:
  432.     mcall -1
  433.  
  434.  
  435. random:  ; Pseudo random actually
  436.  
  437.     mov   eax,[generator]
  438.     add   eax,-43ab45b5h
  439.     ror   eax,1
  440.     bswap eax
  441.     xor   eax,dword[MAC]
  442.     ror   eax,1
  443.     xor   eax,dword[MAC+2]
  444.     mov   [generator],eax
  445.  
  446. ret
  447.  
  448. ; DATA AREA
  449.  
  450. align 16
  451. @IMPORT:
  452.  
  453. library \
  454.         libini,'libini.obj'
  455.  
  456. import  libini, \
  457.         ini.get_str,'ini.get_str',\
  458.         ini.set_str,'ini.set_str',\
  459.         ini.get_int,'ini.get_int',\
  460.         ini.set_int,'ini.set_int',\
  461.         ini.enum_sections,'ini.enum_sections',\
  462.         ini.enum_keys,'ini.enum_keys'
  463.  
  464. include_debug_strings
  465.  
  466. filename db '.ini',0
  467. str_ip db 'ip',0
  468. str_subnet db 'subnet',0
  469. str_gateway db 'gateway',0
  470. str_dns db 'dns',0
  471. str_ipconfig db 'ipconfig',0
  472. str_type db 'type',0
  473.  
  474.  
  475. IM_END:
  476.  
  477. inibuf          rb 16
  478.  
  479. dhcpClientIP    dd  ?
  480. dhcpMsgType     db  ?
  481. dhcpLease       dd  ?
  482. dhcpServerIP    dd  ?
  483.  
  484. dhcpMsgLen      dd  ?
  485. socketNum       dd  ?
  486.  
  487. MAC             dp  ?
  488. currTime        dd  ?
  489. renewTime       dd  ?
  490. generator       dd  ?
  491.  
  492. dhcpMsg         dd  ?
  493.  
  494. I_END_2:
  495.  
  496. path            rb  1024+5
  497.  
  498. I_END: