Subversion Repositories Kolibri OS

Rev

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