Subversion Repositories Kolibri OS

Rev

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