Subversion Repositories Kolibri OS

Rev

Rev 6123 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2010-2016. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;;  zeroconfig.asm - Zeroconfig service for KolibriOS              ;;
  7. ;;                                                                 ;;
  8. ;;  Written by hidnplayr@kolibrios.org                             ;;
  9. ;;    Some code contributed by Derpenguin                          ;;
  10. ;;                                                                 ;;
  11. ;;  DHCP code is based on that by Mike Hibbet                      ;;
  12. ;;      (DHCP client for menuetos)                                 ;;
  13. ;;                                                                 ;;
  14. ;;          GNU GENERAL PUBLIC LICENSE                             ;;
  15. ;;             Version 2, June 1991                                ;;
  16. ;;                                                                 ;;
  17. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  18.  
  19. format binary as ""
  20.  
  21. ; CONFIGURATION
  22.  
  23. TIMEOUT                 = 5             ; in seconds
  24. BUFFER                  = 1024          ; in bytes
  25. DHCP_TRIES              = 3             ; number of times to try contacting DHCP server
  26. __DEBUG__               = 1             ; enable/disable
  27. __DEBUG_LEVEL__         = 2             ; 1 = all, 2 = errors
  28.  
  29. ; CONFIGURATION FOR LINK-LOCAL
  30.  
  31. PROBE_WAIT              = 1             ; second  (initial random delay)
  32. PROBE_MIN               = 1             ; second  (minimum delay till repeated probe)
  33. PROBE_MAX               = 2             ; seconds (maximum delay till repeated probe)
  34. PROBE_NUM               = 3             ;         (number of probe packets)
  35.  
  36. ANNOUNCE_NUM            = 2             ;         (number of announcement packets)
  37. ANNOUNCE_INTERVAL       = 2             ; seconds (time between announcement packets)
  38. ANNOUNCE_WAIT           = 2             ; seconds (delay before announcing)
  39.  
  40. MAX_CONFLICTS           = 10            ;         (max conflicts before rate limiting)
  41.  
  42. RATE_LIMIT_INTERVAL     = 60            ; seconds (delay between successive attempts)
  43.  
  44. DEFEND_INTERVAL         = 10            ; seconds (min. wait between defensive ARPs)
  45.  
  46. MAX_INTERFACES          = 8
  47.  
  48. use32
  49.         org     0x0
  50.  
  51.         db      'MENUET01'              ; 8 byte id
  52.         dd      0x01                    ; header version
  53.         dd      START                   ; start of code
  54.         dd      IM_END                  ; size of image
  55.         dd      (I_END+0x100)           ; memory for app
  56.         dd      (I_END+0x100)           ; esp
  57.         dd      0, 0                    ; I_Param, I_Path
  58.  
  59.  
  60. include '../../proc32.inc'
  61. include '../../macros.inc'
  62. include '../../debug-fdo.inc'
  63. include '../../network.inc'
  64. include 'dhcp.inc'
  65. include '../../dll.inc'
  66.  
  67. struct  dhcp_msg
  68.         op              db ?    ; Operation Code
  69.         htype           db ?    ; Hardware type
  70.         hlen            db ?    ; Hardware address length
  71.         hops            db ?
  72.         xid             dd ?    ; Transaction Identifier
  73.         secs            dw ?    ; Seconds since boot
  74.         flags           dw ?
  75.         ciaddr          dd ?    ; Client IP address
  76.         yiaddr          dd ?    ; "Your" IP address
  77.         siaddr          dd ?    ; Server IP address
  78.         giaddr          dd ?    ; Gateway IP address
  79.         chaddr          rb 16   ; Client hardware address
  80.         sname           rb 64   ; Server name
  81.         file            rb 128  ; boot filename
  82.         cookie          dd ?    ; Magic cookie (0x63538263)
  83.         options         rb 512
  84. ends
  85.  
  86. struct  interface
  87.         number          dd ?
  88.         state           dd ?    ; 0 - disconnected, 1 - connected
  89.         mode            dd ?    ; 0 - disabled, 1 - static, 2 - dhcp, 3 - auto (zero config)
  90.         tries           dd ?
  91.         lease           dd ?
  92.         ServerIP        dd ?
  93.         ip              dd ?
  94.         subnet          dd ?
  95.         dns             dd ?
  96.         gateway         dd ?
  97.         socketNum       dd ?
  98.         timeout         dd ?
  99.         ip_conflicts    dd ?
  100. ends
  101.  
  102. START:
  103.         mcall   68, 11                  ; init heap
  104.  
  105.         stdcall dll.Load, @IMPORT       ; load libraries
  106.         or      eax, eax
  107.         jnz     exit_immediately
  108.  
  109.         DEBUGF  2, "Zero-config service loaded\n"
  110.  
  111.         mcall   40, EVM_STACK2          ; We only want low-level network events
  112.  
  113. ; Set up interface list
  114.         mov     edi, device_list
  115.         xor     ebx, ebx
  116.   @@:
  117.         inc     ebx
  118.         mov     eax, ebx
  119.         stosd
  120.         mov     ecx, sizeof.interface/4-1
  121.         xor     eax,eax
  122.         rep stosd
  123.         cmp     ebx, MAX_INTERFACES
  124.         jb      @b
  125.  
  126.         mov     ebp, device_list
  127. mainloop:
  128.         cmp     [ebp + interface.state], 0
  129.         je      .link_up?
  130.         jmp     .maintain_link
  131.  
  132.   .next:
  133.         cmp     [ebp + interface.number], MAX_INTERFACES
  134.         je      .wait
  135.         add     ebp, sizeof.interface
  136.         jmp     mainloop
  137.  
  138.   .wait:
  139.         mcall   10                      ; Wait for event
  140.         mov     ebp, device_list
  141.         jmp     mainloop
  142.  
  143.   .link_up?:
  144.         mov     bh, byte[ebp + interface.number]
  145.         mov     bl, 0                   ; Get device type
  146.         mcall   74
  147.         cmp     eax, 1                  ; Ethernet
  148.         jne     mainloop.next
  149.  
  150.         mov     bl, 10                  ; Get Link status
  151.         mcall   74
  152.         test    eax, eax
  153.         jz      mainloop.next
  154.  
  155.         mov     [ebp + interface.state], 1
  156.  
  157.         call    create_str_ini_int
  158.  
  159. ; Try to read settings from .ini file
  160.         invoke  ini.get_str, ini_path, str_ini_int, str_ip_type, inibuf, 16, str_null
  161.         test    eax, eax
  162.         jz      @f
  163. ; If settings not found, use default settings from 'ip?' section
  164.         mov     dword[str_ini_int], 'ip?'
  165.   @@:
  166.  
  167.         mov     ebx, API_ETH + 0
  168.         mov     bh, byte[ebp + interface.number]
  169.         mcall   76                      ; get MAC of the ethernet interface
  170.         mov     word[tx_msg.chaddr], bx
  171.         mov     dword[tx_msg.chaddr+2], eax
  172.         DEBUGF  1, "MAC: %x-%x-%x-%x-%x-%x\n", \
  173.         [tx_msg.chaddr+0]:2, [tx_msg.chaddr+1]:2, [tx_msg.chaddr+2]:2, \
  174.         [tx_msg.chaddr+3]:2, [tx_msg.chaddr+4]:2, [tx_msg.chaddr+5]:2
  175.  
  176.         invoke  ini.get_str, ini_path, str_ini_int, str_ip_type, inibuf, 16, str_null
  177.         test    eax, eax
  178.         jnz     .invalid
  179.         mov     eax, dword[inibuf]
  180.         or      eax, 0x20202020
  181.         mov     [ebp + interface.mode], 0
  182.         cmp     eax, 'disa'
  183.         je      .next
  184.         mov     [ebp + interface.mode], 1
  185.         cmp     eax, 'stat'
  186.         je      static
  187.         mov     [ebp + interface.mode], 2
  188.         cmp     eax, 'dhcp'
  189.         je      dhcp
  190.         mov     [ebp + interface.mode], 3
  191.         cmp     eax, 'auto'
  192.         je      dhcp
  193.  
  194.   .invalid:
  195.         DEBUGF  2, "Invalid settings for interface: %s.\n", str_ini_int
  196.         jmp     .next
  197.  
  198.   .maintain_link:
  199.  
  200. ; Check for IP conflicts
  201.         mov     ebx, API_ARP
  202.         mov     bh, byte[ebp + interface.number]
  203.         mov     bl, 7
  204.         mcall   76                      ; Number of IP conflicts
  205.         cmp     eax, [ebp + interface.ip_conflicts]
  206.         je      @f
  207.         mov     [ebp + interface.ip_conflicts], eax
  208.         DEBUGF  2, "IP address conflict on interface %u\n", [ebp + interface.number]
  209.         ; Notify user of the IP address conflict
  210.         mov     [notify_struct.msg], str_conflict
  211.         mcall   70, notify_struct
  212.   @@:
  213.  
  214. ; Check if device is still there
  215.         mov     bh, byte[ebp + interface.number]
  216.         mov     bl, 0                   ; Get device type
  217.         mcall   74
  218.         test    eax, eax                ; No device
  219.         jz      .link_down
  220.  
  221. ; Check if link is still there
  222.         mov     bl, 10                  ; Get Link status
  223.         mcall   74
  224.         test    eax, eax
  225.         jnz     .next
  226.  
  227.   .link_down:
  228.         mov     [ebp + interface.state], 0
  229.  
  230. ; Notify user that the link is down
  231.         mov     [notify_struct.msg], str_disconnected
  232.         mcall   70, notify_struct
  233.  
  234. ; CHECKME: should we do this in kernel instead? Should we even do this at all?
  235.         xor     ecx, ecx
  236.         mov     ebx, API_IPv4 + 3
  237.         mov     bh, byte[ebp + interface.number]
  238.         mcall   76                      ; ip
  239.         mov     bl, 5
  240.         mcall   76                      ; dns
  241.         mov     bl, 7
  242.         mcall   76                      ; subnet
  243.         mov     bl, 9
  244.         mcall   76                      ; gateway
  245.  
  246.         jmp     .next
  247.  
  248. link_up:
  249.  
  250. ; Read number of previous IP conflicts
  251.         mov     ebx, API_ARP
  252.         mov     bh, byte[ebp + interface.number]
  253.         mov     bl, 7
  254.         mcall   76
  255.         mov     [ebp + interface.ip_conflicts], eax
  256.  
  257. ; Notify user that the link is up and running
  258.         mov     [notify_struct.msg], str_connected
  259.         mcall   70, notify_struct
  260.  
  261.   .fail:
  262.         mcall   40, EVM_STACK2
  263.         jmp     mainloop.next
  264.  
  265. static:
  266.         DEBUGF  1, "Applying Static IP settings\n"
  267.  
  268.         invoke  ini.get_str, ini_path, str_ini_int, str_ip, inibuf, 16, str_null
  269.         mov     esi, inibuf
  270.         call    ip_str_to_dword
  271.         mov     ebx, API_IPv4 + 3       ; set IP
  272.         mov     bh, byte[ebp + interface.number]
  273.         mcall   76
  274.  
  275.         invoke  ini.get_str, ini_path, str_ini_int, str_subnet, inibuf, 16, str_null
  276.         mov     esi, inibuf
  277.         call    ip_str_to_dword
  278.         mov     ebx, API_IPv4 + 7       ; set subnet
  279.         mov     bh, byte[ebp + interface.number]
  280.         mcall   76
  281.  
  282.         invoke  ini.get_str, ini_path, str_ini_int, str_gateway, inibuf, 16, str_null
  283.         mov     esi, inibuf
  284.         call    ip_str_to_dword
  285.         mov     ebx, API_IPv4 + 9       ; set gateway
  286.         mov     bh, byte[ebp + interface.number]
  287.         mcall   76
  288.  
  289.   .dns:
  290.         invoke  ini.get_str, ini_path, str_ini_int, str_dns, inibuf, 16, str_null
  291.         mov     esi, inibuf
  292.         call    ip_str_to_dword
  293.         mov     ebx, API_IPv4 + 5       ; set DNS
  294.         mov     bh, byte[ebp + interface.number]
  295.         mcall   76
  296.  
  297.         jmp     link_up
  298.  
  299.  
  300. dhcp:
  301.  
  302.         DEBUGF  2, "Trying to contact DHCP server\n"
  303.  
  304.         mcall   40, EVM_STACK
  305.  
  306.         mcall   75, 0, AF_INET4, SOCK_DGRAM, 0                          ; open socket (parameters: domain, type, reserved)
  307.         cmp     eax, -1
  308.         je      dhcp_error
  309.         mov     [ebp + interface.socketNum], eax
  310.  
  311.         DEBUGF  1, "Socket %x opened\n", eax
  312.  
  313.         mcall   75, 2, [ebp + interface.socketNum], sock_local, 18      ; bind socket to local port 68
  314.         cmp     eax, -1
  315.         je      socket_error
  316.  
  317.         DEBUGF  1, "Socket Bound to local port 68\n"
  318.  
  319.         pushd   [ebp + interface.number]
  320.         pushd   4                       ; length of option
  321.         pushd   SO_BINDTODEVICE
  322.         pushd   SOL_SOCKET
  323.         mcall   75, 8, [ebp + interface.socketNum], esp
  324.         add     esp, 16
  325.         cmp     eax, -1
  326.         je      socket_error
  327.  
  328.         DEBUGF  1, "Socket Bound to local interface %u\n", [ebp + interface.number]
  329.  
  330.         mcall   75, 4, [ebp + interface.socketNum], sock_remote, 18     ; connect to 255.255.255.255 on port 67
  331.         cmp     eax, -1
  332.         je      socket_error
  333.  
  334.         DEBUGF  1, "Connected to 255.255.255.255 on port 67\n"
  335.  
  336.         ; Read preferred IP address from settings file
  337.         invoke  ini.get_str, ini_path, str_ini_int, str_ip, inibuf, 16, str_null
  338.         mov     esi, inibuf
  339.         call    ip_str_to_dword
  340.         mov     [ebp + interface.ip], ecx
  341.  
  342.         call    random
  343.         mov     [tx_msg.xid], eax                                       ; randomize session ID
  344.         mov     [tx_msg_type], 1                                        ; DHCP discover
  345.  
  346. build_dhcp_packet:
  347.  
  348.         DEBUGF  1, "Building DHCP packet\n"
  349.  
  350.         mov     [ebp + interface.tries], DHCP_TRIES
  351.  
  352.         ; Boot protocol legacy
  353.         mov     [tx_msg.op], 1                                          ; Boot request
  354.         mov     [tx_msg.htype], 1                                       ; Ethernet
  355.         mov     [tx_msg.hlen], 6                                        ; Ethernet address h/w len
  356.         mov     [tx_msg.hops], 0
  357.         mcall   26, 9                                                   ; Time since boot
  358.         xor     edx, edx
  359.         mov     ebx, 100
  360.         div     ebx                                                     ; Divide by 100 to get number of seconds
  361.         xchg    al, ah                                                  ; Convert to big endian
  362.         mov     [tx_msg.secs], ax
  363.         mov     [tx_msg.flags], 0
  364.  
  365.         ; DHCP extension
  366.         mov     [tx_msg.cookie], 0x63538263                             ; magic cookie
  367.  
  368.         mov     word[tx_msg+240], 0x0135                                ; option DHCP msg type
  369.         mov     al,[tx_msg_type]
  370.         mov     [tx_msg+240+2], al
  371.  
  372.         mov     word[tx_msg+240+3], 0x0433                              ; option Lease time
  373.         mov     dword[tx_msg+240+5], -1                                 ; infinite
  374.  
  375.         mov     word[tx_msg+240+9], 0x0432                              ; option requested IP address
  376.         mov     eax,[ebp + interface.ip]
  377.         mov     [tx_msg+240+11], eax
  378.  
  379.         mov     word[tx_msg+240+15], 0x0437                             ; option request list
  380.         mov     dword[tx_msg+240+17], 0x0f060301
  381.  
  382.         cmp     [tx_msg_type], 1                                        ; Check which msg we are sending
  383.         jne     .request
  384.  
  385.         mov     byte[tx_msg+240+21], 0xff                               ; end of options marker
  386.  
  387.         mov     [tx_msg_len], 262                                       ; length
  388.         jmp     send_dhcp_packet
  389.  
  390.   .request:
  391.         mov     word[tx_msg+240+21], 0x0436                             ; server IP
  392.         mov     eax,[ebp + interface.ServerIP]
  393.         mov     [tx_msg+240+23], eax
  394.  
  395.         mov     byte[tx_msg+240+27], 0xff                               ; end of options marker
  396.  
  397.         mov     [tx_msg_len], 268                                       ; length
  398.  
  399.  
  400. send_dhcp_packet:
  401.         DEBUGF  1, "Sending DHCP packet\n"
  402.         lea     edx, [tx_msg]
  403.         mcall   75, 6, [ebp + interface.socketNum], , [tx_msg_len]
  404.  
  405. ; Wait for reply
  406.         mcall   26, 9
  407.         add     eax, TIMEOUT*100
  408.         mov     [ebp + interface.timeout], eax
  409.         mov     ebx, TIMEOUT*100
  410.   .wait:
  411.         mcall   23                                                      ; Wait for event with timeout
  412. read_packet:                                                            ; we have data - this will be the response
  413.         lea     edx, [rx_msg]
  414.         mcall   75, 7, [ebp + interface.socketNum], , BUFFER, MSG_DONTWAIT    ; read data from socket
  415.         cmp     eax, -1
  416.         jne     .got_data
  417.  
  418.         mcall   26, 9
  419.         mov     ebx, eax
  420.         sub     ebx, [ebp + interface.timeout]
  421.         ja      send_dhcp_packet.wait
  422.  
  423.         DEBUGF  1, "No answer from DHCP server\n"
  424.         dec     [ebp + interface.tries]
  425.         jnz     send_dhcp_packet
  426.         jmp     dhcp_fail
  427.  
  428.   .got_data:
  429.         DEBUGF  1, "%d bytes received\n", eax
  430.         mov     [rx_msg_len], eax
  431.  
  432. ; depending on which msg we sent, handle the response
  433. ; accordingly.
  434. ; If the response is to a dhcp discover, then:
  435. ;  1) If response is DHCP OFFER then
  436. ;  1.1) record server IP, lease time & IP address.
  437. ;  1.2) send a request packet
  438. ; If the response is to a dhcp request, then:
  439. ;  1) If the response is DHCP ACK then
  440. ;  1.1) extract the DNS & subnet fields. Set them in the stack
  441.  
  442.         cmp     [tx_msg_type], 1                ; did we send a discover?
  443.         je      discover_sent
  444.         cmp     [tx_msg_type], 3                ; did we send a request?
  445.         je      request_sent
  446.         jmp     exit_immediately
  447.  
  448. discover_sent:
  449.         call    parse_dhcp_reply
  450.         cmp     [rx_msg_type], 2                ; Was the response an offer?
  451.         jne     read_packet
  452.  
  453.         DEBUGF  1, "Got offer, making request\n"
  454.         mov     [tx_msg_type], 3                ; make it a request
  455.         jmp     build_dhcp_packet
  456.  
  457. request_sent:
  458.         call    parse_dhcp_reply
  459.         cmp     [rx_msg_type], 5                ; Was the response an ACK? It should be
  460.         jne     read_packet                     ; NO - read next packets
  461.  
  462.         DEBUGF  2, "IP address %u.%u.%u.%u assigned to network interface %u by DHCP\n",\
  463.         [ebp+interface.ip+0]:1, [ebp+interface.ip+1]:1, [ebp+interface.ip+2]:1, [ebp+interface.ip+3]:1, [ebp + interface.number]:1
  464.  
  465.         mcall   close, [ebp + interface.socketNum]
  466.  
  467.         mov     ebx, API_IPv4 + 3
  468.         mov     bh, byte[ebp + interface.number]
  469.         mcall   76, , [ebp + interface.ip]            ; ip
  470.         mov     bl, 7
  471.         mcall   76, , [ebp + interface.subnet]        ; subnet
  472.         mov     bl, 9
  473.         mcall   76, , [ebp + interface.gateway]       ; gateway
  474.  
  475.         invoke  ini.get_str, ini_path, str_ini_int, str_dns_type, inibuf, 16, str_null
  476.         test    eax, eax
  477.         jnz     @f
  478.         mov     eax, dword[inibuf]
  479.         or      eax, 0x202020
  480.         cmp     eax, 'stat'
  481.         je      static.dns
  482.   @@:
  483.         mov     ebx, API_IPv4 + 5
  484.         mov     bh, byte[ebp + interface.number]
  485.         mcall   76, , [ebp + interface.dns]           ; dns
  486.  
  487.         jmp     link_up
  488.  
  489.  
  490. parse_dhcp_reply:
  491.  
  492.         DEBUGF  1, "Parsing response\n"
  493.         mov     [rx_msg_type], 0
  494.  
  495. ; Verify if session ID matches
  496.         mov     eax, [tx_msg.xid]
  497.         cmp     [rx_msg.xid], eax
  498.         jne     .done
  499.  
  500.         pushd   [rx_msg.yiaddr]
  501.         pop     [ebp + interface.ip]
  502.         DEBUGF  1, "Client: %u.%u.%u.%u\n", \
  503.         [rx_msg.yiaddr]:1, [rx_msg.yiaddr+1]:1, [rx_msg.yiaddr+2]:1, [rx_msg.yiaddr+3]:1
  504.  
  505. ; Verify magic cookie
  506.         cmp     [rx_msg.cookie], 0x63538263
  507.         jne     .done
  508.  
  509. ; Parse the DHCP options
  510.         lea     esi, [rx_msg]
  511.         mov     ecx, 240                        ; point to the first option
  512.   .next_option:
  513. ; TODO: check if we still are inside the buffer!
  514.         add     esi, ecx
  515.  
  516.         lodsb                                   ; get message identifier
  517.         mov     bl, al
  518.         cmp     bl, 0xff                        ; End of options?
  519.         je      .done
  520.         test    bl, bl
  521.         jz      .pad
  522.  
  523.         lodsb                                   ; load data length
  524.         movzx   ecx, al
  525.         cmp     bl, dhcp_msg_type               ; Msg type is a single byte option
  526.         je      .msgtype
  527.         cmp     bl, dhcp_dhcp_server_id
  528.         je      .server
  529.         cmp     bl, dhcp_address_time
  530.         je      .lease
  531.         cmp     bl, dhcp_subnet_mask
  532.         je      .subnet
  533.         cmp     bl, dhcp_router
  534.         je      .router
  535.         cmp     bl, dhcp_domain_server
  536.         je      .dns
  537.  
  538.         DEBUGF  1, "Unsupported DHCP option: %u\n", bl
  539.         jmp     .next_option
  540.  
  541.   .pad:
  542.         xor     ecx, ecx
  543.         inc     ecx
  544.         jmp     .next_option
  545.  
  546.   .msgtype:
  547.         mov     al, [esi]
  548.         mov     [rx_msg_type], al
  549.  
  550.         DEBUGF  1, "DHCP Msg type: %u\n", al
  551.         jmp     .next_option                    ; Get next option
  552.  
  553.   .server:
  554.         pushd   [esi]
  555.         pop     [ebp + interface.ServerIP]
  556.         DEBUGF  1, "Server: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
  557.         jmp     .next_option
  558.  
  559.   .lease:
  560.         pusha
  561.         mov     eax,[esi]
  562.         bswap   eax
  563.         mov     [ebp + interface.lease], eax
  564.         DEBUGF  1, "Lease: %d\n", eax
  565.         popa
  566.         jmp     .next_option
  567.  
  568.   .subnet:
  569.         pushd   [esi]
  570.         pop     [ebp + interface.subnet]
  571.         DEBUGF  1, "Subnet: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
  572.         jmp     .next_option
  573.  
  574.   .router:
  575.         pushd   [esi]
  576.         pop     [ebp + interface.gateway]
  577.         DEBUGF  1, "Gateway: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
  578.         jmp     .next_option
  579.  
  580.   .dns:
  581.         pushd   [esi]
  582.         pop     [ebp + interface.dns]
  583.         DEBUGF  1, "DNS: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
  584.         jmp     .next_option
  585.  
  586.   .done:
  587.         ret
  588.  
  589. exit_immediately:
  590.         DEBUGF  2, "Zeroconf failed!\n"
  591.         mcall   -1
  592.  
  593. socket_error:
  594.         DEBUGF  2, "Socket error!\n"
  595.  
  596. dhcp_fail:
  597.         mcall   close, [ebp + interface.socketNum]
  598.  
  599. dhcp_error:
  600.         DEBUGF  2, "DHCP failed\n"
  601.         cmp     [ebp + interface.mode], 3               ; zero config mode?
  602.         jne     link_up
  603.  
  604. link_local:
  605.  
  606. ; TODO: send ARP probes before setting the IP address in stack!
  607.  
  608.         call    random
  609.         mov     cx, ax
  610.         shl     ecx, 16
  611.         mov     cx, 0xfea9                              ; IP 169.254.0.0 link local net, see RFC3927
  612.         mov     ebx, API_IPv4 + 3
  613.         mov     bh, byte[ebp + interface.number]
  614.         mcall   76, , ecx                               ; mask is 255.255.0.0
  615.         DEBUGF  2, "IP address 169.254.%u.%u assigned to network interface %u through Link-Local\n",\
  616.         [generator+0]:1, [generator+1]:1, [ebp + interface.number]:1
  617.         mov     bl, 7
  618.         mcall   76, , 0xffff
  619.         mov     bl, 9
  620.         mcall   76, , 0x0
  621.         mov     bl, 5
  622.         mcall   76, , 0x0
  623.  
  624.         jmp     link_up
  625.  
  626.  
  627. random:  ; Pseudo random actually
  628.  
  629.         mov     eax,[generator]
  630.         add     eax, -43ab45b5h
  631.         ror     eax, 1
  632.         bswap   eax
  633.         xor     eax, dword[tx_msg.chaddr]
  634.         ror     eax, 1
  635.         xor     eax, dword[tx_msg.chaddr+2]
  636.         mov     [generator], eax
  637.  
  638.         ret
  639.  
  640.  
  641.  
  642. create_str_ini_int:
  643.         mov     eax, [ebp + interface.number]
  644.         mov     ebx, 10
  645.         xor     edx, edx
  646.         push    0
  647.   @@:
  648.         div     ebx
  649.         add     dl, '0'
  650.         push    edx
  651.         test    eax, eax
  652.         jnz     @r
  653.   @@:
  654.         mov     edi, str_ini_int+2
  655.   @@:
  656.         pop     eax
  657.         stosb
  658.         test    eax, eax
  659.         jnz     @r
  660.  
  661.         ret
  662.  
  663.  
  664.  
  665. ; In: esi = ptr to ASCIIZ IP address
  666. ; Out: ecx = IP (0 on error)
  667.  
  668. ip_str_to_dword:
  669.  
  670.         xor     ecx, ecx        ; end result
  671.   .charloop:
  672.         lodsb
  673.         test    al, al
  674.         jz      .finish
  675.         cmp     al, '.'
  676.         je      .dot
  677.         sub     al, '0'
  678.         jb      .fail
  679.         cmp     al, 9
  680.         ja      .fail
  681.         mov     dl, cl
  682.         shl     cl, 2
  683.         jc      .fail
  684.         add     cl, dl
  685.         jc      .fail
  686.         add     cl, cl
  687.         jc      .fail
  688.         add     cl, al
  689.         jc      .fail
  690.         jmp     .charloop
  691.   .dot:
  692.         shl     ecx, 8
  693.         jc      .fail
  694.         xor     cl, cl
  695.         jmp     .charloop
  696.   .finish:
  697.         bswap   ecx             ; we want little endian order
  698.         ret
  699.  
  700.   .fail:
  701.         xor     ecx, ecx
  702.         ret
  703.  
  704. ; DATA AREA
  705.  
  706. align 16
  707. @IMPORT:
  708.  
  709. library \
  710.         libini,         'libini.obj'
  711.  
  712. import  libini, \
  713.         ini.get_str,    'ini_get_str',\
  714.         ini.set_str,    'ini_set_str'
  715.  
  716. include_debug_strings
  717.  
  718. str_ip          db 'ip', 0
  719. str_subnet      db 'subnet', 0
  720. str_gateway     db 'gateway', 0
  721. str_dns         db 'dns', 0
  722.  
  723. str_ip_type     db 'ip_type', 0
  724. str_dns_type    db 'dns_type', 0
  725.  
  726. str_ini_int     db 'ip1', 0
  727.                 rb 10
  728.  
  729. str_null        db 0
  730.  
  731. sock_local:
  732.         dw AF_INET4
  733.         dw 68 shl 8     ; local port
  734.         dd 0            ; local IP
  735.         rb 10
  736.  
  737.  
  738. sock_remote:
  739.         dw AF_INET4
  740.         dw 67 shl 8     ; destination port
  741.         dd -1           ; destination IP
  742.         rb 10
  743.  
  744. notify_struct:
  745.         dd 7            ; run application
  746.         dd 0
  747.  .msg   dd 0
  748.         dd 0
  749.         dd 0
  750.         db '/sys/@notify', 0
  751.  
  752. str_connected           db '"You are now connected to the network." -N', 0
  753. str_disconnected        db '"You are now disconnected from the network." -N', 0
  754. str_conflict            db '"An IP address conflict has been detected on the network." -W', 0
  755.  
  756. ini_path                db '/sys/settings/network.ini',0
  757.  
  758. IM_END:
  759.  
  760. generator       dd ?
  761.  
  762. inibuf          rb 16
  763.  
  764. tx_msg_len      dd ?
  765. rx_msg_len      dd ?
  766. tx_msg_type     db ?
  767. rx_msg_type     db ?
  768. tx_msg          dhcp_msg
  769. rx_msg          dhcp_msg
  770.  
  771. device_list     rd MAX_INTERFACES*sizeof.interface
  772.  
  773. I_END: