Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
1164 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
 
45
 
46
 
47
AF_INET4	equ 1337  ;;;;;
48
 
49
 
50
 
51
 
1166 hidnplayr 52
include '../proc32.inc'
53
include '../macros.inc'
54
include '../debug-fdo.inc'
1164 hidnplayr 55
include 'dhcp.inc'
56
include 'dll.inc'
57
 
58
 
59
Ip2dword:
60
    push    edx
61
 
62
    ; This code validates if the query is an IP containing 4 numbers and 3 dots
63
 
64
    xor     al, al	      ; make al (dot count) zero
65
 
66
   @@:
67
    cmp     byte[edx],'0'     ; check if this byte is a number, if not jump to no_IP
68
    jl	    no_IP	      ;
69
    cmp     byte[edx],'9'     ;
70
    jg	    no_IP	      ;
71
 
72
    inc     edx 	      ; the byte was a number, so lets check the next byte
73
 
74
    cmp     byte[edx],0       ; is this byte zero? (have we reached end of query?)
75
    jz	    @f		      ; jump to next @@ then
76
    cmp     byte[edx],':'
77
    jz	    @f
78
 
79
    cmp     byte[edx],'.'     ; is this byte a dot?
80
    jne     @r		      ; if not, jump to previous @@
81
 
82
    inc     al		      ; the byte was a dot so increment al(dot count)
83
    inc     edx 	      ; next byte
84
    jmp     @r		      ; lets check for numbers again (jump to previous @@)
85
 
86
   @@:			      ; we reach this when end of query reached
87
    cmp     al,3	      ; check if there where 3 dots
88
    jnz     no_IP	      ; if not, jump to no_IP
89
 
90
    ; The following code will convert this IP into a dword and output it in eax
91
    ; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1
92
 
93
    pop     esi 	      ; edx (query address) was pushed onto stack and is now popped in esi
94
 
95
    xor     edx, edx	      ; result
96
    xor     eax, eax	      ; current character
97
    xor     ebx, ebx	      ; current byte
98
 
99
.outer_loop:
100
    shl     edx, 8
101
    add     edx, ebx
102
    xor     ebx, ebx
103
.inner_loop:
104
    lodsb
105
    test    eax, eax
106
    jz	    .finish
107
    cmp     al, '.'
108
    jz	    .outer_loop
109
    sub     eax, '0'
110
    imul    ebx, 10
111
    add     ebx, eax
112
    jmp     .inner_loop
113
.finish:
114
    shl     edx, 8
115
    add     edx, ebx
116
 
117
    bswap   edx 	      ; we want little endian order
118
 
119
    ret
120
 
121
no_IP:
122
    pop     edx
123
    xor     edx, edx
124
 
125
    ret
126
 
127
 
128
 
129
 
130
 
131
 
132
START:					    ; start of execution
133
 
134
    mcall 40, 1 shl 7 ; network event
135
 
136
;    eth.set_network_drv 0x00000383
137
 
138
    DEBUGF  1,"Zero-config service:\n"
139
 
140
;    eth.status eax                          ; Read the Stack status
141
;    test    eax,eax                         ; if eax is zero, no driver was found
142
;    jnz     @f
143
;    DEBUGF  1,"No Card found!\n"
144
;    jmp     close
145
 
146
;   @@:
147
;    DEBUGF  1,"Detected card: %x\n",eax
148
;   @@:
149
;    eth.check_cable eax
150
;    test    al,al
151
;    jnz     @f
152
;    DEBUGF  1,"Cable disconnected!\n"
153
;    mcall   5, 500                          ; loop until cable is connected (check every 5 sec)
154
;    jmp     @r
155
 
156
;   @@:
157
;    eth.read_mac MAC
158
 
159
    mcall 73, 10
160
    mov   word[MAC], bx
161
    mov   dword[MAC+2], eax
162
 
163
    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
164
 
165
    cld
166
    mov     edi, path	   ; Calculate the length of zero-terminated string
167
    xor     al , al
168
    mov     ecx, 1024
169
    repnz   scas byte[es:edi]
170
    dec     edi
171
 
172
    mov     esi, filename
173
    movsd
174
    movsb
175
 
176
    DEBUGF  1,"path to ini: %s\n", path
177
 
178
    mcall 68,11
179
 
180
    stdcall dll.Load,@IMPORT
181
    or	    eax,eax
182
    jnz     skip_ini
183
 
184
 
185
    invoke ini.get_str, path, str_ipconfig, str_type, inibuf, 16, 0
186
 
187
    mov  eax,dword[inibuf]
188
 
189
    cmp  eax,'stat'
190
    jne  skip_ini
191
 
192
    invoke ini.get_str, path, str_ipconfig, str_ip, inibuf, 16, 0
193
    mov    edx, inibuf
194
    call   Ip2dword
195
    mcall  73, 3, edx
196
 
197
    invoke ini.get_str, path, str_ipconfig, str_gateway, inibuf, 16, 0
198
    mov    edx, inibuf
199
    call   Ip2dword
200
    mcall  73, 9, edx
201
 
202
    invoke ini.get_str, path, str_ipconfig, str_dns, inibuf, 16, 0
203
    mov    edx, inibuf
204
    call   Ip2dword
205
    mcall  73, 7, edx
206
 
207
    invoke ini.get_str, path, str_ipconfig, str_subnet, inibuf, 16, 0
208
    mov    edx, inibuf
209
    call   Ip2dword
210
    mcall  73, 5, edx
211
 
212
 
213
    mcall  -1
214
 
215
 
216
skip_ini:
217
 
218
    DEBUGF  1,"Skip ini\n"
219
 
220
    mcall 74, 0, AF_INET4, 1, 0        ; open socket (parameters: domain, type, protocol)
221
    cmp   eax, -1
222
    je	  error
223
    mov   [socketNum], eax
224
 
225
    DEBUGF  1,"socket %x opened\n", eax
226
 
227
    mcall 74, 2, [socketNum], sockaddr1, 18	; bind socket to local port 68
228
    cmp   eax, -1
229
    je	  error
230
 
231
    DEBUGF  1,"Socket Bound to local port 68\n"
232
 
233
 
234
    mcall 74, 4, [socketNum], sockaddr2, 18	; connect to 255.255.255.255 on port 67
235
    cmp   eax, -1
236
    je	  error
237
 
238
    DEBUGF  1,"Connected to 255.255.255.255 on port 67\n"
239
 
240
    mov     byte [dhcpMsgType], 0x01	    ; DHCP discover
241
    mov     dword [dhcpLease], esi	    ; esi is still -1 (-1 = forever)
242
 
243
    mcall   26, 9
244
    imul    eax,100
245
    mov     [currTime],eax
246
 
247
buildRequest:				    ; Creates a DHCP request packet.
248
 
249
    DEBUGF  1,"Building request\n"
250
 
251
    stdcall mem.Alloc, BUFFER
252
    mov     [dhcpMsg], eax
253
    test    eax,eax
254
    jz	    apipa
255
 
256
 
257
    mov     edi, eax
258
    mov     ecx,BUFFER
259
    xor     eax,eax
260
    cld
261
    rep     stosb
262
 
263
    mov     edx,[dhcpMsg]
264
 
265
    mov     [edx], byte 0x01		    ; Boot request
266
    mov     [edx+1], byte 0x01		    ; Ethernet
267
    mov     [edx+2], byte 0x06		    ; Ethernet h/w len
268
    mov     [edx+4], dword 0x11223344	    ; xid
269
    mov     eax,[currTime]
270
    mov     [edx+8], eax		    ; secs, our uptime
271
    mov     [edx+10], byte 0x80 	    ; broadcast flag set
272
    mov     eax, dword [MAC]		    ; first 4 bytes of MAC
273
    mov     [edx+28],dword eax
274
    mov     ax, word [MAC+4]		    ; last 2 bytes of MAC
275
    mov     [edx+32],word ax
276
    mov     [edx+236], dword 0x63538263     ; magic number
277
    mov     [edx+240], word 0x0135	    ; option DHCP msg type
278
    mov     al, [dhcpMsgType]
279
    mov     [edx+240+2], al
280
    mov     [edx+240+3], word 0x0433	    ; option Lease time = infinity
281
    mov     eax, [dhcpLease]
282
    mov     [edx+240+5], eax
283
    mov     [edx+240+9], word 0x0432	    ; option requested IP address
284
    mov     eax, [dhcpClientIP]
285
    mov     [edx+240+11], eax
286
    mov     [edx+240+15], word 0x0437	    ; option request list
287
    mov     [edx+240+17], dword 0x0f060301
288
 
289
    cmp     [dhcpMsgType], byte 0x01	    ; Check which msg we are sending
290
    jne     request_options
291
 
292
    mov     [edx+240+21], byte 0xff	    ; "Discover" options
293
 
294
    mov     [dhcpMsgLen], dword 262	    ; end of options marker
295
    jmp     send_request
296
 
297
request_options:
298
    mov     [edx+240+21], word 0x0436	    ; server IP
299
    mov     eax, [dhcpServerIP]
300
    mov     [edx+240+23], eax
301
 
302
    mov     [edx+240+27], byte 0xff	    ; end of options marker
303
 
304
    mov     [dhcpMsgLen], dword 268
305
 
306
send_request:
307
    mcall 74, 6, [socketNum], [dhcpMsg], [dhcpMsgLen] ; write to socket ( send broadcast request )
308
 
309
    mov     eax, [dhcpMsg]		      ; Setup the DHCP buffer to receive response
310
    mov     [dhcpMsgLen], eax		    ; Used as a pointer to the data
311
 
312
    mcall 23, TIMEOUT*10		    ; wait for data
313
 
314
read_data:				    ; we have data - this will be the response
315
 
316
    mcall 74, 7, [socketNum], [dhcpMsg], BUFFER   ; read data from socket
317
 
318
    DEBUGF  1,"%u bytes received\n", eax
319
 
320
    push eax
321
    mcall 74, 10, [socketNum]			  ; close the socket
322
    pop  eax
323
 
324
    cmp eax, -1
325
    je	error
326
 
327
    mov [dhcpMsgLen], eax
328
 
329
    ; depending on which msg we sent, handle the response
330
    ; accordingly.
331
    ; If the response is to a dhcp discover, then:
332
    ;  1) If response is DHCP OFFER then
333
    ;  1.1) record server IP, lease time & IP address.
334
    ;  1.2) send a request packet
335
    ; If the response is to a dhcp request, then:
336
    ;  1) If the response is DHCP ACK then
337
    ;  1.1) extract the DNS & subnet fields. Set them in the stack
338
 
339
    cmp     [dhcpMsgType], byte 0x01	    ; did we send a discover?
340
    je	    discover
341
    cmp     [dhcpMsgType], byte 0x03	    ; did we send a request?
342
    je	    request
343
 
344
    jmp     close			    ; really unknown, what we did
345
 
346
discover:
347
    call    parseResponse
348
 
349
    cmp     [dhcpMsgType], byte 0x02	    ; Was the response an offer?
350
    jne     apipa			    ; NO - so we do zeroconf
351
    mov     [dhcpMsgType], byte 0x03	    ; DHCP request
352
    jmp     buildRequest
353
 
354
request:
355
    call    parseResponse
356
 
357
    cmp     [dhcpMsgType], byte 0x05	    ; Was the response an ACK? It should be
358
    jne     apipa			    ; NO - so we do zeroconf
359
 
360
    jmp     close
361
 
362
;***************************************************************************
363
;   Function
364
;      parseResponse
365
;
366
;   Description
367
;      extracts the fields ( client IP address and options ) from
368
;      a DHCP response
369
;      The values go into
370
;       dhcpMsgType,dhcpLease,dhcpClientIP,dhcpServerIP,
371
;       dhcpDNSIP, dhcpSubnet
372
;      The message is stored in dhcpMsg
373
;
374
;***************************************************************************
375
parseResponse:
376
    DEBUGF  1,"Data received, parsing response\n"
377
    mov     edx, [dhcpMsg]
378
 
379
    pusha
380
    mcall 73, 3, [edx+16]
381
    mov     eax,[edx]
382
    mov     [dhcpClientIP],eax
383
    DEBUGF  1,"Client: %u.%u.%u.%u\n",[edx+16]:1,[edx+17]:1,[edx+18]:1,[edx+19]:1
384
    popa
385
 
386
    add     edx, 240			    ; Point to first option
387
    xor     ecx, ecx
388
 
389
next_option:
390
    add     edx, ecx
391
pr001:
392
    mov     al, [edx]
393
    cmp     al, 0xff			    ; End of options?
394
    je	    pr_exit
395
 
396
    cmp     al, dhcp_msg_type		    ; Msg type is a single byte option
397
    jne     @f
398
 
399
    mov     al, [edx+2]
400
    mov     [dhcpMsgType], al
401
    add     edx, 3
402
    jmp     pr001			    ; Get next option
403
 
404
@@:
405
    inc     edx
406
    movzx   ecx, byte [edx]
407
    inc     edx 			    ; point to data
408
 
409
    cmp     al, dhcp_dhcp_server_id	    ; server ip
410
    jne     @f
411
    mov     eax, [edx]
412
    mov     [dhcpServerIP], eax
413
    DEBUGF  1,"Server: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
414
    jmp     next_option
415
 
416
@@:
417
    cmp     al, dhcp_address_time
418
    jne     @f
419
 
420
    pusha
421
    mov     eax,[edx]
422
    bswap   eax
423
    mov     [dhcpLease],eax
424
    DEBUGF  1,"lease: %d\n",eax
425
    popa
426
 
427
    jmp     next_option
428
 
429
@@:
430
    cmp     al, dhcp_subnet_mask
431
    jne     @f
432
 
433
    pusha
434
    mcall 73, 5, [edx]
435
    DEBUGF  1,"Subnet: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
436
    popa
437
 
438
    jmp     next_option
439
 
440
@@:
441
    cmp     al, dhcp_router
442
    jne     @f
443
 
444
    pusha
445
    mcall 73, 9, [edx]
446
    DEBUGF  1,"Gateway: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
447
    popa
448
 
449
    jmp     next_option
450
 
451
 
452
@@:
453
    cmp     al, dhcp_domain_server
454
    jne     next_option
455
 
456
    pusha
457
    mcall 73, 7, [edx]
458
    DEBUGF  1,"DNS: %u.%u.%u.%u\n",[edx]:1,[edx+1]:1,[edx+2]:1,[edx+3]:1
459
    popa
460
 
461
    jmp     next_option
462
 
463
pr_exit:
464
 
465
;    DEBUGF  1,"Sending ARP announce\n"
466
;    eth.ARP_ANNOUNCE [dhcpClientIP]         ; send an ARP announce packet
467
 
468
    jmp close
469
 
470
apipa:
471
    stdcall mem.Free, [dhcpMsg]
472
 
473
link_local:
474
    call random
475
    mov  ecx,0xfea9			    ; IP 169.254.0.0 link local net, see RFC3927
476
    mov  cx,ax
477
    mcall 73, 3, ecx			      ; mask is 255.255.0.0
478
    DEBUGF 1,"Link Local IP assinged: 169.254.%u.%u\n",[generator+2]:1,[generator+3]:1
479
    mcall 73, 5, 0xffff
480
    mcall 73, 9, 0x0
481
    mcall 73, 7, 0x0
482
 
483
    mcall 5, PROBE_WAIT*100
484
 
485
    xor esi,esi
486
   probe_loop:
487
    call  random			    ; create a pseudo random number in eax (seeded by MAC)
488
 
489
    cmp   al,PROBE_MIN*100		    ; check if al is bigger then PROBE_MIN
490
    jge   @f				    ; all ok
491
    add   al,(PROBE_MAX-PROBE_MIN)*100	    ; al is too small
492
   @@:
493
 
494
    cmp   al,PROBE_MAX*100
495
    jle   @f
496
    sub   al,(PROBE_MAX-PROBE_MIN)*100
497
   @@:
498
 
499
    movzx ebx,al
500
    DEBUGF  1,"Waiting %u0ms\n",ebx
501
    mcall 5
502
 
503
    DEBUGF  1,"Sending Probe\n"
504
;    eth.ARP_PROBE MAC
505
    inc   esi
506
 
507
    cmp   esi,PROBE_NUM
508
    jl	  probe_loop
509
 
510
; now we wait further ANNOUNCE_WAIT seconds and send ANNOUNCE_NUM ARP announces. If any other host has assingned
511
; IP within this time, we should create another adress, that have to be done later
512
 
513
    DEBUGF  1,"Waiting %us\n",ANNOUNCE_WAIT
514
    mcall 5, ANNOUNCE_WAIT*100
515
    xor   esi,esi
516
   announce_loop:
517
 
518
    DEBUGF  1,"Sending Announce\n"
519
;    eth.ARP_ANNOUNCE MAC
520
 
521
    inc   esi
522
    cmp   esi,ANNOUNCE_NUM
523
    je	  @f
524
 
525
    DEBUGF  1,"Waiting %us\n",ANNOUNCE_INTERVAL
526
    mcall 5, ANNOUNCE_INTERVAL*100
527
    jmp   announce_loop
528
   @@:
529
    ; we should, instead of closing, detect ARP conflicts and detect if cable keeps connected ;)
530
 
531
error:
532
close:
533
    mcall -1
534
 
535
 
536
random:  ; Pseudo random actually
537
 
538
    mov   eax,[generator]
539
    add   eax,-43ab45b5h
540
    ror   eax,1
541
    bswap eax
542
    xor   eax,dword[MAC]
543
    ror   eax,1
544
    xor   eax,dword[MAC+2]
545
    mov   [generator],eax
546
 
547
ret
548
 
549
; DATA AREA
550
 
551
align 16
552
@IMPORT:
553
 
554
library \
555
	libini,'libini.obj'
556
 
557
import	libini, \
558
	ini.get_str,'ini.get_str'
559
 
560
include_debug_strings
561
 
562
filename db '.ini',0
563
str_ip db 'ip',0
564
str_subnet db 'subnet',0
565
str_gateway db 'gateway',0
566
str_dns db 'dns',0
567
str_ipconfig db 'ipconfig',0
568
str_type db 'type',0
569
 
570
 
571
sockaddr1:
572
 
573
	dw AF_INET4
574
	dw 68		; local port
575
	dd 0		; local IP
576
 
577
	rb 10
578
 
579
 
580
sockaddr2:
581
 
582
	dw AF_INET4
583
	dw 67		; destination port
584
	dd -1		; destination IP
585
 
586
	rb 10
587
 
588
 
589
IM_END:
590
 
591
inibuf		rb 16
592
 
593
dhcpClientIP	dd  ?
594
dhcpMsgType	db  ?
595
dhcpLease	dd  ?
596
dhcpServerIP	dd  ?
597
 
598
dhcpMsgLen	dd  ?
599
socketNum	dd  ?
600
 
601
MAC		dp  ?
602
 
603
currTime	dd  ?
604
renewTime	dd  ?
605
generator	dd  ?
606
 
607
dhcpMsg 	dd  ?
608
 
609
I_END_2:
610
 
611
path		rb  1024+5
612
 
613
I_END: