Subversion Repositories Kolibri OS

Rev

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