Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
1010 hidnplayr 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: