Subversion Repositories Kolibri OS

Rev

Rev 5842 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
3545 hidnplayr 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
6123 hidnplayr 3
;; Copyright (C) KolibriOS team 2010-2016. All rights reserved.    ;;
3545 hidnplayr 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                      ;;
3618 hidnplayr 12
;;      (DHCP client for menuetos)                                 ;;
3545 hidnplayr 13
;;                                                                 ;;
14
;;          GNU GENERAL PUBLIC LICENSE                             ;;
15
;;             Version 2, June 1991                                ;;
16
;;                                                                 ;;
17
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
18
 
19
format binary as ""
20
 
21
; CONFIGURATION
22
 
5842 hidnplayr 23
TIMEOUT                 = 5             ; in seconds
3545 hidnplayr 24
BUFFER                  = 1024          ; in bytes
3632 hidnplayr 25
DHCP_TRIES              = 3             ; number of times to try contacting DHCP server
3545 hidnplayr 26
__DEBUG__               = 1             ; enable/disable
3682 hidnplayr 27
__DEBUG_LEVEL__         = 2             ; 1 = all, 2 = errors
3545 hidnplayr 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
 
5586 hidnplayr 46
MAX_INTERFACES          = 8
47
 
3618 hidnplayr 48
use32
49
        org     0x0
3545 hidnplayr 50
 
3618 hidnplayr 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'
3545 hidnplayr 64
include 'dhcp.inc'
3618 hidnplayr 65
include '../../dll.inc'
3545 hidnplayr 66
 
5586 hidnplayr 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
5610 hidnplayr 89
        mode            dd ?    ; 0 - disabled, 1 - static, 2 - dhcp, 3 - auto (zero config)
5586 hidnplayr 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
 
5391 hidnplayr 102
START:
5586 hidnplayr 103
        mcall   68, 11                  ; init heap
3545 hidnplayr 104
 
5586 hidnplayr 105
        stdcall dll.Load, @IMPORT       ; load libraries
5391 hidnplayr 106
        or      eax, eax
5586 hidnplayr 107
        jnz     exit_immediately
3545 hidnplayr 108
 
5586 hidnplayr 109
        DEBUGF  2, "Zero-config service loaded\n"
3545 hidnplayr 110
 
5586 hidnplayr 111
        mcall   40, EVM_STACK2          ; We only want low-level network events
3545 hidnplayr 112
 
5586 hidnplayr 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
5391 hidnplayr 146
        mcall   74
5586 hidnplayr 147
        cmp     eax, 1                  ; Ethernet
148
        jne     mainloop.next
3545 hidnplayr 149
 
5586 hidnplayr 150
        mov     bl, 10                  ; Get Link status
5391 hidnplayr 151
        mcall   74
152
        test    eax, eax
5586 hidnplayr 153
        jz      mainloop.next
3545 hidnplayr 154
 
5586 hidnplayr 155
        mov     [ebp + interface.state], 1
3545 hidnplayr 156
 
5586 hidnplayr 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
 
5391 hidnplayr 167
        mov     ebx, API_ETH + 0
5586 hidnplayr 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
3545 hidnplayr 175
 
5586 hidnplayr 176
        invoke  ini.get_str, ini_path, str_ini_int, str_ip_type, inibuf, 16, str_null
177
        test    eax, eax
5610 hidnplayr 178
        jnz     .invalid
5586 hidnplayr 179
        mov     eax, dword[inibuf]
180
        or      eax, 0x20202020
181
        mov     [ebp + interface.mode], 0
5610 hidnplayr 182
        cmp     eax, 'disa'
183
        je      .next
184
        mov     [ebp + interface.mode], 1
5586 hidnplayr 185
        cmp     eax, 'stat'
5391 hidnplayr 186
        je      static
5610 hidnplayr 187
        mov     [ebp + interface.mode], 2
5586 hidnplayr 188
        cmp     eax, 'dhcp'
189
        je      dhcp
5610 hidnplayr 190
        mov     [ebp + interface.mode], 3
5586 hidnplayr 191
        cmp     eax, 'auto'
192
        je      dhcp
3545 hidnplayr 193
 
5610 hidnplayr 194
  .invalid:
195
        DEBUGF  2, "Invalid settings for interface: %s.\n", str_ini_int
196
        jmp     .next
3545 hidnplayr 197
 
5586 hidnplayr 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
5391 hidnplayr 217
        mcall   74
5586 hidnplayr 218
        test    eax, eax                ; No device
219
        jz      .link_down
3545 hidnplayr 220
 
5586 hidnplayr 221
; Check if link is still there
222
        mov     bl, 10                  ; Get Link status
5391 hidnplayr 223
        mcall   74
224
        test    eax, eax
5586 hidnplayr 225
        jnz     .next
3545 hidnplayr 226
 
5586 hidnplayr 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?
5391 hidnplayr 235
        xor     ecx, ecx
236
        mov     ebx, API_IPv4 + 3
5586 hidnplayr 237
        mov     bh, byte[ebp + interface.number]
238
        mcall   76                      ; ip
5391 hidnplayr 239
        mov     bl, 5
5586 hidnplayr 240
        mcall   76                      ; dns
5391 hidnplayr 241
        mov     bl, 7
5586 hidnplayr 242
        mcall   76                      ; subnet
5391 hidnplayr 243
        mov     bl, 9
5586 hidnplayr 244
        mcall   76                      ; gateway
3545 hidnplayr 245
 
5586 hidnplayr 246
        jmp     .next
3545 hidnplayr 247
 
5586 hidnplayr 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
 
5391 hidnplayr 265
static:
5586 hidnplayr 266
        DEBUGF  1, "Applying Static IP settings\n"
3545 hidnplayr 267
 
5586 hidnplayr 268
        invoke  ini.get_str, ini_path, str_ini_int, str_ip, inibuf, 16, str_null
269
        mov     esi, inibuf
5391 hidnplayr 270
        call    ip_str_to_dword
3844 hidnplayr 271
        mov     ebx, API_IPv4 + 3       ; set IP
5586 hidnplayr 272
        mov     bh, byte[ebp + interface.number]
3844 hidnplayr 273
        mcall   76
3545 hidnplayr 274
 
5586 hidnplayr 275
        invoke  ini.get_str, ini_path, str_ini_int, str_subnet, inibuf, 16, str_null
276
        mov     esi, inibuf
5391 hidnplayr 277
        call    ip_str_to_dword
5586 hidnplayr 278
        mov     ebx, API_IPv4 + 7       ; set subnet
279
        mov     bh, byte[ebp + interface.number]
3844 hidnplayr 280
        mcall   76
3545 hidnplayr 281
 
5586 hidnplayr 282
        invoke  ini.get_str, ini_path, str_ini_int, str_gateway, inibuf, 16, str_null
283
        mov     esi, inibuf
5391 hidnplayr 284
        call    ip_str_to_dword
5586 hidnplayr 285
        mov     ebx, API_IPv4 + 9       ; set gateway
286
        mov     bh, byte[ebp + interface.number]
3844 hidnplayr 287
        mcall   76
3545 hidnplayr 288
 
5586 hidnplayr 289
  .dns:
290
        invoke  ini.get_str, ini_path, str_ini_int, str_dns, inibuf, 16, str_null
291
        mov     esi, inibuf
5391 hidnplayr 292
        call    ip_str_to_dword
5586 hidnplayr 293
        mov     ebx, API_IPv4 + 5       ; set DNS
294
        mov     bh, byte[ebp + interface.number]
3844 hidnplayr 295
        mcall   76
3545 hidnplayr 296
 
5586 hidnplayr 297
        jmp     link_up
3545 hidnplayr 298
 
299
 
5586 hidnplayr 300
dhcp:
3545 hidnplayr 301
 
5586 hidnplayr 302
        DEBUGF  2, "Trying to contact DHCP server\n"
3545 hidnplayr 303
 
5391 hidnplayr 304
        mcall   40, EVM_STACK
305
 
5586 hidnplayr 306
        mcall   75, 0, AF_INET4, SOCK_DGRAM, 0                          ; open socket (parameters: domain, type, reserved)
3545 hidnplayr 307
        cmp     eax, -1
5586 hidnplayr 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
5391 hidnplayr 315
        je      socket_error
3545 hidnplayr 316
 
5586 hidnplayr 317
        DEBUGF  1, "Socket Bound to local port 68\n"
3545 hidnplayr 318
 
5586 hidnplayr 319
        pushd   [ebp + interface.number]
320
        pushd   4                       ; length of option
5842 hidnplayr 321
        pushd   SO_BINDTODEVICE
322
        pushd   SOL_SOCKET
5586 hidnplayr 323
        mcall   75, 8, [ebp + interface.socketNum], esp
324
        add     esp, 16
3545 hidnplayr 325
        cmp     eax, -1
5391 hidnplayr 326
        je      socket_error
3545 hidnplayr 327
 
5586 hidnplayr 328
        DEBUGF  1, "Socket Bound to local interface %u\n", [ebp + interface.number]
3545 hidnplayr 329
 
5586 hidnplayr 330
        mcall   75, 4, [ebp + interface.socketNum], sock_remote, 18     ; connect to 255.255.255.255 on port 67
3545 hidnplayr 331
        cmp     eax, -1
5391 hidnplayr 332
        je      socket_error
3545 hidnplayr 333
 
5586 hidnplayr 334
        DEBUGF  1, "Connected to 255.255.255.255 on port 67\n"
3545 hidnplayr 335
 
5586 hidnplayr 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
3545 hidnplayr 341
 
5419 hidnplayr 342
        call    random
5586 hidnplayr 343
        mov     [tx_msg.xid], eax                                       ; randomize session ID
344
        mov     [tx_msg_type], 1                                        ; DHCP discover
5419 hidnplayr 345
 
5586 hidnplayr 346
build_dhcp_packet:
5419 hidnplayr 347
 
5586 hidnplayr 348
        DEBUGF  1, "Building DHCP packet\n"
5419 hidnplayr 349
 
5586 hidnplayr 350
        mov     [ebp + interface.tries], DHCP_TRIES
3545 hidnplayr 351
 
5586 hidnplayr 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
        mov     [tx_msg.secs], ax
362
        mov     [tx_msg.flags], 0
3636 hidnplayr 363
 
5586 hidnplayr 364
        ; DHCP extension
365
        mov     [tx_msg.cookie], 0x63538263                             ; magic cookie
3545 hidnplayr 366
 
5586 hidnplayr 367
        mov     word[tx_msg+240], 0x0135                                ; option DHCP msg type
368
        mov     al,[tx_msg_type]
369
        mov     [tx_msg+240+2], al
3545 hidnplayr 370
 
5586 hidnplayr 371
        mov     word[tx_msg+240+3], 0x0433                              ; option Lease time
372
        mov     dword[tx_msg+240+5], -1                                 ; infinite
3545 hidnplayr 373
 
5586 hidnplayr 374
        mov     word[tx_msg+240+9], 0x0432                              ; option requested IP address
375
        mov     eax,[ebp + interface.ip]
376
        mov     [tx_msg+240+11], eax
3545 hidnplayr 377
 
5586 hidnplayr 378
        mov     word[tx_msg+240+15], 0x0437                             ; option request list
379
        mov     dword[tx_msg+240+17], 0x0f060301
3545 hidnplayr 380
 
5586 hidnplayr 381
        cmp     [tx_msg_type], 1                                        ; Check which msg we are sending
382
        jne     .request
3545 hidnplayr 383
 
5586 hidnplayr 384
        mov     byte[tx_msg+240+21], 0xff                               ; end of options marker
3545 hidnplayr 385
 
5586 hidnplayr 386
        mov     [tx_msg_len], 262                                       ; length
387
        jmp     send_dhcp_packet
3545 hidnplayr 388
 
5586 hidnplayr 389
  .request:
390
        mov     word[tx_msg+240+21], 0x0436                             ; server IP
391
        mov     eax,[ebp + interface.ServerIP]
392
        mov     [tx_msg+240+23], eax
3545 hidnplayr 393
 
5586 hidnplayr 394
        mov     byte[tx_msg+240+27], 0xff                               ; end of options marker
3545 hidnplayr 395
 
5586 hidnplayr 396
        mov     [tx_msg_len], 268                                       ; length
3545 hidnplayr 397
 
5419 hidnplayr 398
 
5586 hidnplayr 399
send_dhcp_packet:
400
        DEBUGF  1, "Sending DHCP packet\n"
401
        lea     edx, [tx_msg]
402
        mcall   75, 6, [ebp + interface.socketNum], , [tx_msg_len]
403
 
404
; Wait for reply
4805 hidnplayr 405
        mcall   26, 9
406
        add     eax, TIMEOUT*100
5586 hidnplayr 407
        mov     [ebp + interface.timeout], eax
408
        mov     ebx, TIMEOUT*100
3735 hidnplayr 409
  .wait:
5586 hidnplayr 410
        mcall   23                                                      ; Wait for event with timeout
411
read_packet:                                                            ; we have data - this will be the response
412
        lea     edx, [rx_msg]
413
        mcall   75, 7, [ebp + interface.socketNum], , BUFFER, MSG_DONTWAIT    ; read data from socket
3632 hidnplayr 414
        cmp     eax, -1
5419 hidnplayr 415
        jne     .got_data
4805 hidnplayr 416
 
417
        mcall   26, 9
5586 hidnplayr 418
        mov     ebx, eax
419
        sub     ebx, [ebp + interface.timeout]
420
        ja      send_dhcp_packet.wait
4805 hidnplayr 421
 
6123 hidnplayr 422
        DEBUGF  1, "No answer from DHCP server\n"
5586 hidnplayr 423
        dec     [ebp + interface.tries]
424
        jnz     send_dhcp_packet
5391 hidnplayr 425
        jmp     dhcp_fail
3545 hidnplayr 426
 
5419 hidnplayr 427
  .got_data:
5586 hidnplayr 428
        DEBUGF  1, "%d bytes received\n", eax
429
        mov     [rx_msg_len], eax
3545 hidnplayr 430
 
431
; depending on which msg we sent, handle the response
432
; accordingly.
433
; If the response is to a dhcp discover, then:
434
;  1) If response is DHCP OFFER then
435
;  1.1) record server IP, lease time & IP address.
436
;  1.2) send a request packet
437
; If the response is to a dhcp request, then:
438
;  1) If the response is DHCP ACK then
439
;  1.1) extract the DNS & subnet fields. Set them in the stack
440
 
5586 hidnplayr 441
        cmp     [tx_msg_type], 1                ; did we send a discover?
5419 hidnplayr 442
        je      discover_sent
5586 hidnplayr 443
        cmp     [tx_msg_type], 3                ; did we send a request?
5419 hidnplayr 444
        je      request_sent
5586 hidnplayr 445
        jmp     exit_immediately
3545 hidnplayr 446
 
5419 hidnplayr 447
discover_sent:
5586 hidnplayr 448
        call    parse_dhcp_reply
449
        cmp     [rx_msg_type], 2                ; Was the response an offer?
450
        jne     read_packet
3545 hidnplayr 451
 
3636 hidnplayr 452
        DEBUGF  1, "Got offer, making request\n"
5586 hidnplayr 453
        mov     [tx_msg_type], 3                ; make it a request
454
        jmp     build_dhcp_packet
3545 hidnplayr 455
 
5419 hidnplayr 456
request_sent:
5586 hidnplayr 457
        call    parse_dhcp_reply
458
        cmp     [rx_msg_type], 5                ; Was the response an ACK? It should be
459
        jne     read_packet                     ; NO - read next packets
3545 hidnplayr 460
 
6123 hidnplayr 461
        DEBUGF  2, "IP address %u.%u.%u.%u assigned to network interface %u by DHCP\n",\
462
        [ebp+interface.ip+0]:1, [ebp+interface.ip+1]:1, [ebp+interface.ip+2]:1, [ebp+interface.ip+3]:1, [ebp + interface.number]:1
3636 hidnplayr 463
 
5586 hidnplayr 464
        mcall   close, [ebp + interface.socketNum]
3545 hidnplayr 465
 
3601 hidnplayr 466
        mov     ebx, API_IPv4 + 3
5586 hidnplayr 467
        mov     bh, byte[ebp + interface.number]
468
        mcall   76, , [ebp + interface.ip]            ; ip
5587 hidnplayr 469
        mov     bl, 7
5586 hidnplayr 470
        mcall   76, , [ebp + interface.subnet]        ; subnet
3601 hidnplayr 471
        mov     bl, 9
5586 hidnplayr 472
        mcall   76, , [ebp + interface.gateway]       ; gateway
3545 hidnplayr 473
 
5586 hidnplayr 474
        invoke  ini.get_str, ini_path, str_ini_int, str_dns_type, inibuf, 16, str_null
475
        test    eax, eax
476
        jnz     @f
477
        mov     eax, dword[inibuf]
478
        or      eax, 0x202020
479
        cmp     eax, 'stat'
480
        je      static.dns
481
  @@:
5587 hidnplayr 482
        mov     ebx, API_IPv4 + 5
483
        mov     bh, byte[ebp + interface.number]
5586 hidnplayr 484
        mcall   76, , [ebp + interface.dns]           ; dns
3545 hidnplayr 485
 
5586 hidnplayr 486
        jmp     link_up
3545 hidnplayr 487
 
488
 
5586 hidnplayr 489
parse_dhcp_reply:
3545 hidnplayr 490
 
5586 hidnplayr 491
        DEBUGF  1, "Parsing response\n"
492
        mov     [rx_msg_type], 0
493
 
5419 hidnplayr 494
; Verify if session ID matches
5586 hidnplayr 495
        mov     eax, [tx_msg.xid]
496
        cmp     [rx_msg.xid], eax
5419 hidnplayr 497
        jne     .done
498
 
5586 hidnplayr 499
        pushd   [rx_msg.yiaddr]
500
        pop     [ebp + interface.ip]
501
        DEBUGF  1, "Client: %u.%u.%u.%u\n", \
502
        [rx_msg.yiaddr]:1, [rx_msg.yiaddr+1]:1, [rx_msg.yiaddr+2]:1, [rx_msg.yiaddr+3]:1
3545 hidnplayr 503
 
5586 hidnplayr 504
; Verify magic cookie
505
        cmp     [rx_msg.cookie], 0x63538263
506
        jne     .done
3545 hidnplayr 507
 
5586 hidnplayr 508
; Parse the DHCP options
509
        lea     esi, [rx_msg]
510
        mov     ecx, 240                        ; point to the first option
3545 hidnplayr 511
  .next_option:
5586 hidnplayr 512
; TODO: check if we still are inside the buffer!
513
        add     esi, ecx
3545 hidnplayr 514
 
5586 hidnplayr 515
        lodsb                                   ; get message identifier
516
        mov     bl, al
517
        cmp     bl, 0xff                        ; End of options?
3545 hidnplayr 518
        je      .done
5586 hidnplayr 519
        test    bl, bl
520
        jz      .pad
3545 hidnplayr 521
 
5586 hidnplayr 522
        lodsb                                   ; load data length
523
        movzx   ecx, al
524
        cmp     bl, dhcp_msg_type               ; Msg type is a single byte option
3545 hidnplayr 525
        je      .msgtype
5586 hidnplayr 526
        cmp     bl, dhcp_dhcp_server_id
3545 hidnplayr 527
        je      .server
5586 hidnplayr 528
        cmp     bl, dhcp_address_time
3545 hidnplayr 529
        je      .lease
5586 hidnplayr 530
        cmp     bl, dhcp_subnet_mask
3545 hidnplayr 531
        je      .subnet
5586 hidnplayr 532
        cmp     bl, dhcp_router
3545 hidnplayr 533
        je      .router
5586 hidnplayr 534
        cmp     bl, dhcp_domain_server
3545 hidnplayr 535
        je      .dns
536
 
5586 hidnplayr 537
        DEBUGF  1, "Unsupported DHCP option: %u\n", bl
3545 hidnplayr 538
        jmp     .next_option
539
 
540
  .pad:
541
        xor     ecx, ecx
542
        inc     ecx
543
        jmp     .next_option
544
 
545
  .msgtype:
5586 hidnplayr 546
        mov     al, [esi]
547
        mov     [rx_msg_type], al
3545 hidnplayr 548
 
5586 hidnplayr 549
        DEBUGF  1, "DHCP Msg type: %u\n", al
3545 hidnplayr 550
        jmp     .next_option                    ; Get next option
551
 
552
  .server:
5586 hidnplayr 553
        pushd   [esi]
554
        pop     [ebp + interface.ServerIP]
555
        DEBUGF  1, "Server: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
3545 hidnplayr 556
        jmp     .next_option
557
 
558
  .lease:
559
        pusha
5586 hidnplayr 560
        mov     eax,[esi]
3545 hidnplayr 561
        bswap   eax
5586 hidnplayr 562
        mov     [ebp + interface.lease], eax
563
        DEBUGF  1, "Lease: %d\n", eax
3545 hidnplayr 564
        popa
565
        jmp     .next_option
566
 
567
  .subnet:
5586 hidnplayr 568
        pushd   [esi]
569
        pop     [ebp + interface.subnet]
570
        DEBUGF  1, "Subnet: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
3545 hidnplayr 571
        jmp     .next_option
572
 
573
  .router:
5586 hidnplayr 574
        pushd   [esi]
575
        pop     [ebp + interface.gateway]
576
        DEBUGF  1, "Gateway: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
3545 hidnplayr 577
        jmp     .next_option
578
 
579
  .dns:
5586 hidnplayr 580
        pushd   [esi]
581
        pop     [ebp + interface.dns]
582
        DEBUGF  1, "DNS: %u.%u.%u.%u\n", [esi]:1, [esi+1]:1, [esi+2]:1, [esi+3]:1
3545 hidnplayr 583
        jmp     .next_option
584
 
585
  .done:
586
        ret
587
 
5586 hidnplayr 588
exit_immediately:
589
        DEBUGF  2, "Zeroconf failed!\n"
590
        mcall   -1
5419 hidnplayr 591
 
5586 hidnplayr 592
socket_error:
593
        DEBUGF  2, "Socket error!\n"
594
 
5391 hidnplayr 595
dhcp_fail:
5586 hidnplayr 596
        mcall   close, [ebp + interface.socketNum]
3545 hidnplayr 597
 
5586 hidnplayr 598
dhcp_error:
6123 hidnplayr 599
        DEBUGF  2, "DHCP failed\n"
5610 hidnplayr 600
        cmp     [ebp + interface.mode], 3               ; zero config mode?
5586 hidnplayr 601
        jne     link_up
3545 hidnplayr 602
 
5586 hidnplayr 603
link_local:
3545 hidnplayr 604
 
5586 hidnplayr 605
; TODO: send ARP probes before setting the IP address in stack!
5419 hidnplayr 606
 
3545 hidnplayr 607
        call    random
608
        mov     cx, ax
609
        shl     ecx, 16
610
        mov     cx, 0xfea9                              ; IP 169.254.0.0 link local net, see RFC3927
3601 hidnplayr 611
        mov     ebx, API_IPv4 + 3
5586 hidnplayr 612
        mov     bh, byte[ebp + interface.number]
5419 hidnplayr 613
        mcall   76, , ecx                               ; mask is 255.255.0.0
6123 hidnplayr 614
        DEBUGF  2, "IP address 169.254.%u.%u assigned to network interface %u through Link-Local\n",\
615
        [generator+0]:1, [generator+1]:1, [ebp + interface.number]:1
3601 hidnplayr 616
        mov     bl, 7
617
        mcall   76, , 0xffff
618
        mov     bl, 9
619
        mcall   76, , 0x0
620
        mov     bl, 5
621
        mcall   76, , 0x0
3545 hidnplayr 622
 
5586 hidnplayr 623
        jmp     link_up
3545 hidnplayr 624
 
625
 
626
random:  ; Pseudo random actually
627
 
5586 hidnplayr 628
        mov     eax,[generator]
3545 hidnplayr 629
        add     eax, -43ab45b5h
630
        ror     eax, 1
631
        bswap   eax
5586 hidnplayr 632
        xor     eax, dword[tx_msg.chaddr]
3545 hidnplayr 633
        ror     eax, 1
5586 hidnplayr 634
        xor     eax, dword[tx_msg.chaddr+2]
3545 hidnplayr 635
        mov     [generator], eax
636
 
637
        ret
638
 
5391 hidnplayr 639
 
640
 
5586 hidnplayr 641
create_str_ini_int:
642
        mov     eax, [ebp + interface.number]
643
        mov     ebx, 10
644
        xor     edx, edx
645
        push    0
646
  @@:
647
        div     ebx
648
        add     dl, '0'
649
        push    edx
650
        test    eax, eax
651
        jnz     @r
652
  @@:
653
        mov     edi, str_ini_int+2
654
  @@:
655
        pop     eax
656
        stosb
657
        test    eax, eax
658
        jnz     @r
5391 hidnplayr 659
 
5586 hidnplayr 660
        ret
5391 hidnplayr 661
 
662
 
663
 
5586 hidnplayr 664
; In: esi = ptr to ASCIIZ IP address
665
; Out: ecx = IP (0 on error)
5391 hidnplayr 666
 
5586 hidnplayr 667
ip_str_to_dword:
5391 hidnplayr 668
 
5586 hidnplayr 669
        xor     ecx, ecx        ; end result
670
  .charloop:
671
        lodsb
672
        test    al, al
673
        jz      .finish
674
        cmp     al, '.'
675
        je      .dot
676
        sub     al, '0'
677
        jb      .fail
678
        cmp     al, 9
679
        ja      .fail
680
        mov     dl, cl
681
        shl     cl, 2
682
        jc      .fail
683
        add     cl, dl
684
        jc      .fail
685
        add     cl, cl
686
        jc      .fail
687
        add     cl, al
688
        jc      .fail
689
        jmp     .charloop
690
  .dot:
691
        shl     ecx, 8
692
        jc      .fail
693
        xor     cl, cl
694
        jmp     .charloop
5391 hidnplayr 695
  .finish:
5586 hidnplayr 696
        bswap   ecx             ; we want little endian order
697
        ret
5391 hidnplayr 698
 
5586 hidnplayr 699
  .fail:
700
        xor     ecx, ecx
701
        ret
5391 hidnplayr 702
 
3545 hidnplayr 703
; DATA AREA
704
 
705
align 16
706
@IMPORT:
707
 
708
library \
5586 hidnplayr 709
        libini,         'libini.obj'
3545 hidnplayr 710
 
711
import  libini, \
5586 hidnplayr 712
        ini.get_str,    'ini_get_str',\
713
        ini.set_str,    'ini_set_str'
3545 hidnplayr 714
 
715
include_debug_strings
716
 
717
str_ip          db 'ip', 0
718
str_subnet      db 'subnet', 0
719
str_gateway     db 'gateway', 0
720
str_dns         db 'dns', 0
721
 
5586 hidnplayr 722
str_ip_type     db 'ip_type', 0
723
str_dns_type    db 'dns_type', 0
3545 hidnplayr 724
 
5586 hidnplayr 725
str_ini_int     db 'ip1', 0
726
                rb 10
3545 hidnplayr 727
 
5586 hidnplayr 728
str_null        db 0
729
 
730
sock_local:
3545 hidnplayr 731
        dw AF_INET4
732
        dw 68 shl 8     ; local port
733
        dd 0            ; local IP
734
        rb 10
735
 
736
 
5586 hidnplayr 737
sock_remote:
3545 hidnplayr 738
        dw AF_INET4
739
        dw 67 shl 8     ; destination port
740
        dd -1           ; destination IP
741
        rb 10
742
 
4013 hidnplayr 743
notify_struct:
744
        dd 7            ; run application
745
        dd 0
746
 .msg   dd 0
747
        dd 0
748
        dd 0
749
        db '/sys/@notify', 0
3545 hidnplayr 750
 
5586 hidnplayr 751
str_connected           db '"You are now connected to the network." -N', 0
752
str_disconnected        db '"You are now disconnected from the network." -N', 0
753
str_conflict            db '"An IP address conflict has been detected on the network." -W', 0
5419 hidnplayr 754
 
5586 hidnplayr 755
ini_path                db '/sys/settings/network.ini',0
4013 hidnplayr 756
 
3545 hidnplayr 757
IM_END:
758
 
5586 hidnplayr 759
generator       dd ?
760
 
3545 hidnplayr 761
inibuf          rb 16
762
 
5586 hidnplayr 763
tx_msg_len      dd ?
764
rx_msg_len      dd ?
765
tx_msg_type     db ?
766
rx_msg_type     db ?
767
tx_msg          dhcp_msg
768
rx_msg          dhcp_msg
3545 hidnplayr 769
 
5586 hidnplayr 770
device_list     rd MAX_INTERFACES*sizeof.interface
3545 hidnplayr 771
 
772
I_END: