Subversion Repositories Kolibri OS

Rev

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