Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
336 hidnplayr 1
;
2
; ETH.INC
3
;
4
; made by hidnplayr (hidnplayr@gmail.com) for KolibriOS
5
;
6
; The given code before every macro is only a simple example
7
;
8
;
9
; HISTORY
10
;
11
; v1.0: august 2006  original release
12
; v1.1: december 2006 bugfixes and improvements
13
; v1.2: februari 2007 more bugfixes and improvements
14
 
15
macro mov arg1,arg2 {
16
    if arg1 eq arg2
17
    else
18
    mov arg1,arg2
19
    end if
20
}
21
 
22
TCB_LISTEN = 1
23
TCB_SYN_SENT = 2
24
TCB_SYN_RECEIVED = 3
25
TCB_ESTABLISHED = 4
26
TCB_FIN_WAIT_1 = 5
27
TCB_FIN_WAIT_2 = 6
28
TCB_CLOSE_WAIT = 7
29
TCB_CLOSING = 8
30
TCB_LAST_ASK = 9
31
TCB_TIME_WAIT = 10
32
TCB_CLOSED = 11
33
 
34
PASSIVE = 0
35
ACTIVE = 1
36
 
37
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
38
 
39
macro eth.get_IP IP {
40
    mov  ebx,1
41
    mov  eax,52
485 heavyiron 42
    mcall
336 hidnplayr 43
 
44
    mov  IP ,eax
45
}
46
 
47
macro eth.get_GATEWAY GATEWAY {
48
    mov  ebx,9
49
    mov  eax,52
485 heavyiron 50
    mcall
336 hidnplayr 51
    mov GATEWAY ,eax
52
}
53
 
54
macro eth.get_SUBNET SUBNET {
55
    mov  ebx,10
56
    mov  eax,52
485 heavyiron 57
    mcall
336 hidnplayr 58
    mov SUBNET ,eax
59
}
60
 
61
macro eth.get_DNS DNS {
62
    mov  ebx,13
63
    mov  eax,52
485 heavyiron 64
    mcall
336 hidnplayr 65
    mov  DNS ,eax
66
}
67
 
68
macro eth.set_IP IP {
69
    mov  ecx,IP
70
    mov  ebx,3
71
    mov  eax,52
485 heavyiron 72
    mcall
336 hidnplayr 73
}
74
 
75
macro eth.set_GATEWAY GATEWAY {
76
    mov  ecx,GATEWAY
77
    mov  ebx,11
78
    mov  eax,52
485 heavyiron 79
    mcall
336 hidnplayr 80
}
81
 
82
macro eth.set_SUBNET SUBNET {
83
    mov  ecx,SUBNET
84
    mov  ebx,12
85
    mov  eax,52
485 heavyiron 86
    mcall
336 hidnplayr 87
}
88
 
89
macro eth.set_DNS DNS {
90
    mov  ecx,DNS
91
    mov  ebx,14
92
    mov  eax,52
485 heavyiron 93
    mcall
336 hidnplayr 94
}
95
 
339 hidnplayr 96
macro eth.set_network_drv conf {
97
    mov  ecx,conf
98
    mov  ebx,2
99
    mov  eax,52
485 heavyiron 100
    mcall
339 hidnplayr 101
}
102
 
336 hidnplayr 103
macro eth.open_udp local,remote,ip,socket {
104
    mov  ecx, local
105
    mov  edx, remote
106
    mov  esi, ip
107
    mov  ebx, 0
108
    mov  eax, 53
485 heavyiron 109
    mcall
336 hidnplayr 110
 
111
    mov  socket,eax
112
}
113
 
114
macro eth.close_udp socket {
115
    mov  ecx, socket
116
    mov  ebx, 1
117
    mov  eax, 53
485 heavyiron 118
    mcall
336 hidnplayr 119
}
120
 
121
macro eth.poll socket {
122
    mov  ecx, socket
123
    mov  ebx, 2
124
    mov  eax, 53
485 heavyiron 125
    mcall
336 hidnplayr 126
}
127
 
128
macro eth.read_byte socket, result {
129
    mov  ecx, socket
130
    mov  ebx, 3
131
    mov  eax, 53
485 heavyiron 132
    mcall
336 hidnplayr 133
 
134
    mov  result,bl
135
}
136
 
137
macro eth.read_packet socket, result, buffersize {
138
    mov  esi, buffersize
139
    mov  edx, result
140
    mov  ecx, socket
141
    mov  ebx, 11
142
    mov  eax, 53
485 heavyiron 143
    mcall
336 hidnplayr 144
}
145
 
146
macro eth.write_udp socket,length,msg,verify {
147
    mov  ecx, socket
148
    mov  edx, length
149
    mov  esi, msg
150
    mov  ebx, 4
151
    mov  eax, 53
485 heavyiron 152
    mcall
336 hidnplayr 153
 
154
    if verify eq 1
155
    call verifysend
156
    end if
157
 
158
}
159
 
160
verifysend:
161
    test eax,eax
162
    jnz  @f
163
    ret
164
@@:
165
    pusha
166
    mov  eax,5
167
    mov  ebx,100
485 heavyiron 168
    mcall
336 hidnplayr 169
    popa
485 heavyiron 170
    mcall
336 hidnplayr 171
ret
172
 
173
macro eth.open_tcp local,remote,ip,passive,socket {
174
 
175
    mov  ecx, local
176
    mov  edx, remote
177
    mov  esi, ip
178
    mov  edi, passive	   ; 0 = PASSIVE open
179
    mov  ebx, 5
180
    mov  eax, 53
485 heavyiron 181
    mcall
336 hidnplayr 182
 
183
    mov  socket,eax
184
}
185
 
186
macro eth.socket_status socket,result {
187
    mov  ecx, socket
188
    mov  ebx, 6
189
    mov  eax, 53
485 heavyiron 190
    mcall
336 hidnplayr 191
 
192
    mov  result,eax
193
}
194
 
195
macro eth.write_tcp socket,length,msg,verify {
196
    mov  ecx, socket
197
    mov  edx, length
198
    mov  esi, msg
199
    mov  ebx, 7
200
    mov  eax, 53
485 heavyiron 201
    mcall
336 hidnplayr 202
 
203
    if verify eq 1
204
    call verifysend
205
    end if
206
}
207
 
208
macro eth.read_mac mac {
209
    mov  eax, 52
210
    mov  ebx, 15
211
    xor  ecx, ecx
212
    pusha
485 heavyiron 213
    mcall
336 hidnplayr 214
    mov  dword[mac],eax
215
    popa
216
    add  cl, 4
485 heavyiron 217
    mcall
336 hidnplayr 218
    mov  word[mac+4],ax
219
 
220
}
221
 
222
macro eth.close_tcp socket {
223
    mov  ecx, socket
224
    mov  ebx, 8
225
    mov  eax, 53
485 heavyiron 226
    mcall
336 hidnplayr 227
}
228
 
229
macro eth.check_port port,result {
230
    mov  ecx, port
231
    mov  ebx, 9
232
    mov  eax, 53
485 heavyiron 233
    mcall
336 hidnplayr 234
 
235
    mov  result,eax
236
}
237
 
238
macro eth.check_cable result {
239
    mov  ebx, 10
240
    mov  eax, 53
485 heavyiron 241
    mcall
336 hidnplayr 242
 
243
    mov  result,eax
244
}
245
 
246
macro eth.status status {
247
    mov  ebx, 255
248
    mov  ecx, 6
249
    mov  eax, 53
485 heavyiron 250
    mcall
336 hidnplayr 251
 
252
    mov  status,eax
253
}
254
 
255
macro eth.search_port port,result {
256
    mov  edx,port
257
   @@:
258
    inc  edx
259
    eth.check_port edx,eax
260
    cmp  eax,0
261
    je	 @r
262
    mov  result,edx
263
}
264
 
265
macro eth.ARP_PROBE address{
266
 
267
    mov  edx,address
268
    mov  eax,52
269
    mov  ebx,16
270
    xor  ecx,ecx
485 heavyiron 271
    mcall
336 hidnplayr 272
 
273
}
274
 
275
 
276
macro eth.ARP_ANNOUNCE address{
277
 
278
    mov  edx,address
279
    mov  eax,52
280
    mov  ebx,16
281
    xor  ecx,ecx
282
    inc  ecx
485 heavyiron 283
    mcall
336 hidnplayr 284
 
285
}
286
 
287
macro eth.read_data socket,dest,endptr,bufferl {
288
local .getdata,.loop,.end
289
    mov     eax, dest
290
    mov     endptr, eax
291
 
292
.getdata:
293
    cmp     endptr, bufferl
294
    jg	    .end
295
 
337 hidnplayr 296
    eth.read_packet socket, endptr, 0
336 hidnplayr 297
    add     endptr,eax
298
 
299
    test    eax, eax
300
    jnz     .getdata
301
 
302
    xor     edx, edx
303
.loop:
304
    eth.poll socket
305
 
306
    test    eax, eax
307
    jnz     .getdata
308
 
309
    mov     eax,5
310
    mov     ebx,1
485 heavyiron 311
    mcall
336 hidnplayr 312
 
313
    inc     edx
314
    cmp     edx,30
315
    jl	    .loop
316
 
317
.end:
318
}
319
 
320
macro eth.wait_for_data socket,TIMEOUT,abort {
321
    mov   edx,TIMEOUT
322
 
323
   @@:
324
    eth.poll socket
325
 
326
    cmp   eax,0
327
    jne   @f
328
 
329
    dec   edx
330
    jz	  abort
331
 
332
    mov   eax,5 			      ; wait here for event
333
    mov   ebx,10
485 heavyiron 334
    mcall
336 hidnplayr 335
 
336
    jmp   @r
337
   @@:
338
 
339
}
340
 
341
 
342
; The function 'resolve' resolves the address in edx and puts the resulting IP in eax.
343
; When the input is an IP-adress, the function will output this IP in eax.
344
; If something goes wrong, the result in eax should be 0
345
;
346
; example:
347
;
348
; resolve query1,IP,PORT
349
; resolve '192.168.0.1',IP,PORT
350
; resolve query2,IP,PORT
351
;
352
; query1 db 'www.google.com',0
353
; query2 db '49.78.84.45',0
354
; IP     dd ?
355
; PORT   dd ?
356
 
357
macro resolve query,result {
358
 
359
if    query eqtype 0
360
 mov   edx,query
361
else
362
 local ..string, ..label
363
 jmp   ..label
364
 ..string db query,0
365
 ..label:
366
 mov   edx,..string
367
end   if
368
 
369
call  __resolve
370
 
371
mov   result,eax
372
 
373
}
374
 
375
if used __resolve
376
 
377
__resolve:
378
 
379
if __DEBUG__ eq 1
380
DEBUGF 1,'DNS: Resolving started\n'
381
end if
382
 
383
    ; This code validates if the query is an IP containing 4 numbers and 3 dots
384
 
385
 
386
    push    edx 	      ; push edx (query address) onto stack
387
    xor     al, al	      ; make al (dot count) zero
388
 
389
   @@:
390
    cmp     byte[edx],'0'     ; check if this byte is a number, if not jump to no_IP
391
    jl	    no_IP	      ;
392
    cmp     byte[edx],'9'     ;
393
    jg	    no_IP	      ;
394
 
395
    inc     edx 	      ; the byte was a number, so lets check the next byte
396
 
397
    cmp     byte[edx],0       ; is this byte zero? (have we reached end of query?)
398
    jz	    @f		      ; jump to next @@ then
399
    cmp     byte[edx],':'
400
    jz	    @f
401
 
402
    cmp     byte[edx],'.'     ; is this byte a dot?
403
    jne     @r		      ; if not, jump to previous @@
404
 
405
    inc     al		      ; the byte was a dot so increment al(dot count)
406
    inc     edx 	      ; next byte
407
    jmp     @r		      ; lets check for numbers again (jump to previous @@)
408
 
409
   @@:			      ; we reach this when end of query reached
410
    cmp     al,3	      ; check if there where 3 dots
411
    jnz     no_IP	      ; if not, jump to no_IP (this is where the DNS will take over)
412
 
413
    ; The following code will convert this IP into a dword and output it in eax
414
    ; If there is also a port number specified, this will be returned in ebx, otherwise ebx is -1
415
 
416
    pop     esi 	      ; edx (query address) was pushed onto stack and is now popped in esi
417
 
418
    xor     edx, edx	      ; result
419
    xor     eax, eax	      ; current character
420
    xor     ebx, ebx	      ; current byte
421
 
422
.outer_loop:
423
    shl     edx, 8
424
    add     edx, ebx
425
    xor     ebx, ebx
426
.inner_loop:
427
    lodsb
428
    test    eax, eax
429
    jz	    .finish
430
    cmp     al, '.'
431
    jz	    .outer_loop
432
    sub     eax, '0'
433
    imul    ebx, 10
434
    add     ebx, eax
435
    jmp     .inner_loop
436
.finish:
437
    shl     edx, 8
438
    add     edx, ebx
439
 
440
    bswap   edx 	      ; we want little endian order
441
    mov     eax, edx
442
 
443
    ret
444
 
445
 
446
no_IP:
447
 
448
    pop     edx
449
 
450
    ; The query is not an IP address, we will send the query to a DNS server and hope for answer ;)
451
if __DEBUG__ eq 1
452
    DEBUGF 1,'DNS: The query is no ip, Building request string from:%u\n',edx
453
end if
454
 
455
    ; Build the request string
456
    mov     eax, 0x00010100
457
    mov     [dnsMsg], eax
458
    mov     eax, 0x00000100
459
    mov     [dnsMsg+4], eax
460
    mov     eax, 0x00000000
461
    mov     [dnsMsg+8], eax
462
 
463
    ; domain name goes in at dnsMsg+12
464
    mov     esi, dnsMsg + 12			 ; location of label length
465
    mov     edi, dnsMsg + 13			 ; label start
466
    mov     ecx, 12				 ; total string length so far
467
 
468
td002:
469
    mov     [esi], byte 0
470
    inc     ecx
471
 
472
td0021:
473
    mov     al, [edx]
474
 
475
    cmp     al, 0
476
    je	    td001				 ; we have finished the string translation
477
 
478
    cmp     al, '.'
479
    je	    td004				 ; we have finished the label
480
 
481
    inc     byte [esi]
482
    inc     ecx
483
    mov     [edi], al
484
    inc     edi
485
    inc     edx
486
    jmp     td0021
487
 
488
td004:
489
    mov     esi, edi
490
    inc     edi
491
    inc     edx
492
    jmp     td002
493
 
494
    ; write label len + label text
495
td001:
496
    mov     [edi], byte 0
497
    inc     ecx
498
    inc     edi
499
    mov     [edi], dword 0x01000100
500
    add     ecx, 4
501
 
502
    mov     [dnsMsgLen], ecx			 ; We'll need the length of the message when we send it
503
    ; Now, lets send this and wait for an answer
504
 
505
    eth.search_port 1024,edx			 ; Find a free port starting from 1025 and store in edx
506
    eth.get_DNS esi				 ; Read DNS IP from stack into esi
507
    eth.open_udp edx,53,esi,[socketNum] 	     ; First, open socket
508
if __DEBUG__ eq 1
509
    DEBUGF 1,'DNS: Socket opened: %u (port %u)\n',[socketNum],ecx
510
end if
511
    eth.write_udp [socketNum],[dnsMsgLen],dnsMsg     ; Write to socket ( request DNS lookup )
512
if __DEBUG__ eq 1
513
    DEBUGF 1,'DNS: Data written, length:%u offset:%u\n',[dnsMsgLen],dnsMsg
514
    DEBUGF 1,'DNS: Waiting for data: (timeout is %us)\n',TIMEOUT
515
end if
516
    eth.wait_for_data [socketNum],TIMEOUT,abort  ; Now, we wait for data from remote
517
    eth.read_data dword[socketNum],dnsMsg,dword[dnsMsgLen],dnsMsg+BUFFER      ; Read the data into the buffer
518
if __DEBUG__ eq 1
519
    DEBUGF 1,'Data received, offset:%u buffer size:%u length:%u\n',dnsMsg,BUFFER,esi-dnsMsg
520
end if
521
    eth.close_udp [socketNum]			     ; We're done, close the socket
522
if __DEBUG__ eq 1
523
    DEBUGF 1,'Closed Socket\n'
524
end if
525
 
526
    ; Now parse the message to get the host IP. Man, this is complicated. It's described in RFC 1035
527
    ; 1) Validate that we have an answer with > 0 responses
528
    ; 2) Find the answer record with TYPE 0001 ( host IP )
529
    ; 3) Finally, copy the IP address to the display
530
    ; Note: The response is in dnsMsg, the end of the buffer is pointed to by [dnsMsgLen]
531
 
532
    mov     esi, dnsMsg
533
 
534
    mov     al, [esi+2] 			 ; Is this a response to my question?
535
    and     al, 0x80
536
    cmp     al, 0x80
537
    jne     abort
538
if __DEBUG__ eq 1
539
    DEBUGF 1,'DNS: It was a response to my question\n'
540
end if
541
 
542
    mov     al, [esi+3] 			 ; Were there any errors?
543
    and     al, 0x0F
544
    cmp     al, 0x00
545
    jne     abort
546
 
547
if __DEBUG__ eq 1
548
    DEBUGF 1,'DNS: There were no errors\n'
549
end if
550
 
551
    mov     ax, [esi+6] 			 ; Is there ( at least 1 ) answer?
552
    cmp     ax, 0x00
553
    je	    abort
554
 
555
    ; Header validated. Scan through and get my answer
556
    add     esi, 12				 ; Skip to the question field
557
    call    skipName				 ; Skip through the question field
558
    add     esi, 4				 ; skip past the questions qtype, qclass
559
 
560
ctr002z:
561
    ; Now at the answer. There may be several answers, find the right one ( TYPE = 0x0001 )
562
    call    skipName
563
    mov     ax, [esi]
564
    cmp     ax, 0x0100				 ; Is this the IP address answer?
565
    jne     ctr002c
566
    add     esi, 10				 ; Yes! Point eax to the first byte of the IP address
567
    mov     eax,[esi]
568
 
569
    ret
570
 
571
 
572
ctr002c:					 ; Skip through the answer, move to the next
573
    add     esi, 8
574
    movzx   eax, byte [esi+1]
575
    mov     ah, [esi]
576
    add     esi, eax
577
    add     esi, 2
578
 
579
    cmp     esi, [dnsMsgLen]			 ; Have we reached the end of the msg? This is an error condition, should not happen
580
    jl	    ctr002z				 ; Check next answer
581
 
582
abort:
583
if __DEBUG__ eq 1
584
    DEBUGF 1,'DNS: Something went wrong, aborting\n'
585
end if
586
    xor     eax,eax
587
 
588
    ret
589
 
590
 
591
skipName:
592
    ; Increment esi to the first byte past the name field
593
    ; Names may use compressed labels. Normally do.
594
    ; RFC 1035 page 30 gives details
595
    mov     al, [esi]
596
    cmp     al, 0
597
    je	    sn_exit
598
    and     al, 0xc0
599
    cmp     al, 0xc0
600
    je	    sn001
601
 
602
    movzx   eax, byte [esi]
603
    inc     eax
604
    add     esi, eax
605
    jmp     skipName
606
 
607
sn001:
608
    add     esi, 2				 ; A pointer is always at the end
609
    ret
610
 
611
sn_exit:
612
    inc     esi
613
    ret
614
 
615
dnsMsgLen:	dd 0
616
socketNum:	dd 0xFFFF
617
 
618
if ~defined dnsMsg
619
dnsMsg: 	rb BUFFER
620
end if
621
 
622
end if
623