Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
3555 Serge 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                                 ;;
3
;; Copyright (C) KolibriOS team 2004-2013. All rights reserved.    ;;
4
;; Distributed under terms of the GNU General Public License       ;;
5
;;                                                                 ;;
6
;;  ARP.INC                                                        ;;
7
;;                                                                 ;;
8
;;  Part of the tcp/ip network stack for KolibriOS                 ;;
9
;;                                                                 ;;
10
;;  Based on the work of [Johnny_B] and [smb]                      ;;
11
;;                                                                 ;;
12
;;    Written by hidnplayr@kolibrios.org                           ;;
13
;;                                                                 ;;
14
;;          GNU GENERAL PUBLIC LICENSE                             ;;
15
;;             Version 2, June- 1991                               ;;
16
;;                                                                 ;;
17
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
18
 
19
$Revision: 3386 $
20
 
21
ARP_NO_ENTRY            = 0
22
ARP_VALID_MAPPING       = 1
23
ARP_AWAITING_RESPONSE   = 2
24
ARP_RESPONSE_TIMEOUT    = 3
25
 
26
ARP_REQUEST_TTL         = 31          ; 20 s
27
ARP_ENTRY_TTL           = 937         ; 600 s
28
ARP_STATIC_ENTRY        = -1
29
 
30
ARP_REQ_OPCODE          = 0x0100      ; request
31
ARP_REP_OPCODE          = 0x0200      ; reply
32
 
33
ARP_TABLE_SIZE          = 20          ; Size of table
34
 
35
struct ARP_entry
36
 
37
       IP               dd ?
38
       MAC              dp ?
39
       Status           dw ?
40
       TTL              dw ?
41
 
42
ends
43
 
44
struct ARP_header
45
 
46
       HardwareType     dw ?
47
       ProtocolType     dw ?
48
       HardwareSize     db ?
49
       ProtocolSize     db ?
50
       Opcode           dw ?
51
       SenderMAC        dp ?
52
       SenderIP         dd ?
53
       TargetMAC        dp ?
54
       TargetIP         dd ?
55
 
56
ends
57
 
58
align 4
59
uglobal
60
 
61
        NumARP          dd ?
62
 
63
        ARP_table       rb ARP_TABLE_SIZE * sizeof.ARP_entry    ; TODO: separate ARP table and stats per interface
64
 
65
        ARP_PACKETS_TX  rd MAX_NET_DEVICES
66
        ARP_PACKETS_RX  rd MAX_NET_DEVICES
67
        ARP_CONFLICTS   rd MAX_NET_DEVICES
68
 
69
 
70
endg
71
 
72
 
73
 
74
;-----------------------------------------------------------------
75
;
76
; ARP_init
77
;
78
;  This function resets all ARP variables
79
;
80
;-----------------------------------------------------------------
81
macro ARP_init {
82
 
83
        xor     eax, eax
84
        mov     [NumARP], eax
85
 
86
        mov     edi, ARP_PACKETS_TX
87
        mov     ecx, 3*MAX_NET_DEVICES
88
        rep     stosd
89
 
90
}
91
 
92
;---------------------------------------------------------------------------
93
;
94
; ARP_decrease_entry_ttls
95
;
96
;---------------------------------------------------------------------------
97
 
98
macro ARP_decrease_entry_ttls {
99
 
100
local   .loop
101
local   .exit
102
 
103
; The TTL field is decremented every second, and is deleted when it reaches 0.
104
; It is refreshed every time a packet is received.
105
; If the TTL field is 0xFFFF it is a static entry and is never deleted.
106
; The status field can be the following values:
107
; 0x0000  entry not used
108
; 0x0001  entry holds a valid mapping
109
; 0x0002  entry contains an IP address, awaiting ARP response
110
; 0x0003  No response received to ARP request.
111
; The last status value is provided to allow the network layer to delete
112
; a packet that is queued awaiting an ARP response
113
 
114
        mov     ecx, [NumARP]
115
        test    ecx, ecx
116
        jz      .exit
117
 
118
        mov     esi, ARP_table
119
  .loop:
120
        cmp     [esi + ARP_entry.TTL], ARP_STATIC_ENTRY
121
        je      .next
122
 
123
        dec     [esi + ARP_entry.TTL]
124
        jz      .time_out
125
 
126
  .next:
127
        add     esi, sizeof.ARP_entry
128
        dec     ecx
129
        jnz     .loop
130
        jmp     .exit
131
 
132
  .time_out:
133
        cmp     [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE
134
        je      .response_timeout
135
 
136
        push    esi ecx
137
        call    ARP_del_entry
138
        pop     ecx esi
139
 
140
        jmp     .next
141
 
142
  .response_timeout:
143
        mov     [esi + ARP_entry.Status], ARP_RESPONSE_TIMEOUT
144
        mov     [esi + ARP_entry.TTL], 10
145
 
146
        jmp     .next
147
 
148
  .exit:
149
 
150
}
151
 
152
 
153
;-----------------------------------------------------------------
154
;
155
; ARP_input
156
;
157
;  IN:  Pointer to buffer in [esp]
158
;       size of buffer in [esp+4]
159
;       packet size (without ethernet header) in ecx
160
;       packet ptr in edx
161
;       device ptr in ebx
162
;  OUT: /
163
;
164
;-----------------------------------------------------------------
165
align 4
166
ARP_input:
167
 
168
;-----------------------------------------
169
; Check validity and print some debug info
170
 
171
        cmp     ecx, sizeof.ARP_header
172
        jb      .exit
173
 
174
        call    NET_ptr_to_num
175
        cmp     edi, -1
176
        jz      .exit
177
 
178
        inc     [ARP_PACKETS_RX + 4*edi]        ; update stats
179
 
3589 Serge 180
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: got packet from %u.%u.%u.%u through device %u\n",\
3555 Serge 181
        [edx + ARP_header.SenderIP]:1, [edx + ARP_header.SenderIP + 1]:1,\
182
        [edx + ARP_header.SenderIP + 2]:1, [edx + ARP_header.SenderIP + 3]:1, edi
183
 
184
;------------------------------
185
; First, check for IP collision
186
 
187
        mov     eax, [edx + ARP_header.SenderIP]
188
        cmp     eax, [IP_LIST + 4*edi]
189
        je      .collision
190
 
191
;---------------------
192
; Handle reply packets
193
 
194
        cmp     [edx + ARP_header.Opcode], ARP_REP_OPCODE
195
        jne     .maybe_request
196
 
3589 Serge 197
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: It's a reply\n"
3555 Serge 198
 
199
        mov     ecx, [NumARP]
200
        test    ecx, ecx
201
        jz      .exit
202
 
203
        mov     esi, ARP_table
204
  .loop:
205
        cmp     [esi + ARP_entry.IP], eax
206
        je      .gotit
207
        add     esi, sizeof.ARP_entry
208
        dec     ecx
209
        jnz     .loop
210
 
3589 Serge 211
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: no matching entry found\n"
3555 Serge 212
        jmp     .exit
213
 
214
  .gotit:
3589 Serge 215
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: found matching entry\n"
3555 Serge 216
 
217
        cmp     [esi + ARP_entry.TTL], ARP_STATIC_ENTRY         ; if it is a static entry, dont touch it
218
        je      .exit
219
 
3589 Serge 220
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: updating entry\n"
3555 Serge 221
 
222
        mov     [esi + ARP_entry.Status], ARP_VALID_MAPPING
223
        mov     [esi + ARP_entry.TTL], ARP_ENTRY_TTL
224
 
225
        mov     eax, dword [edx + ARP_header.SenderMAC]
226
        mov     dword [esi + ARP_entry.MAC], eax
227
        mov     cx, word [edx + ARP_header.SenderMAC + 4]
228
        mov     word [esi + ARP_entry.MAC + 4], cx
229
 
230
        jmp     .exit
231
 
232
;-----------------------
233
; Handle request packets
234
 
235
  .maybe_request:
236
        cmp     [edx + ARP_header.Opcode], ARP_REQ_OPCODE
237
        jne     .exit
238
 
3589 Serge 239
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: its a request\n"
3555 Serge 240
 
241
        mov     eax, [IP_LIST + 4*edi]
242
        cmp     eax, [edx + ARP_header.TargetIP]                ; Is it looking for my IP address?
243
        jne     .exit
244
 
245
        push    eax
246
        push    edi
247
 
248
; OK, it is a request for one of our MAC addresses.
249
; Build the frame and send it. We can reuse the buffer.  (faster then using ARP_create_packet)
250
 
251
        lea     esi, [edx + ARP_header.SenderMAC]
252
        lea     edi, [edx + ARP_header.TargetMAC]
253
        movsd                                                   ; Move Sender Mac to Dest MAC
254
        movsw                                                   ;
255
        movsd                                                   ; Move sender IP to Dest IP
256
 
257
        pop     esi
258
        mov     esi, [NET_DRV_LIST + 4*esi]
259
        lea     esi, [esi + ETH_DEVICE.mac]
260
        lea     edi, [edx + ARP_header.SenderMAC]
261
        movsd                                                   ; Copy MAC address from in MAC_LIST
262
        movsw                                                   ;
263
        pop     eax
264
        stosd                                                   ; Write our IP
265
 
266
        mov     [edx + ARP_header.Opcode], ARP_REP_OPCODE
267
 
268
; Now, Fill in ETHERNET header
269
 
270
        mov     edi, [esp]
271
        lea     esi, [edx + ARP_header.TargetMAC]
272
        movsd
273
        movsw
274
        lea     esi, [edx + ARP_header.SenderMAC]
275
        movsd
276
        movsw
277
;        mov     ax , ETHER_ARP                                 ; It's already there, I'm sure of it!
278
;        stosw
279
 
3589 Serge 280
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: Sending reply\n"
3555 Serge 281
 
282
        call    [ebx + NET_DEVICE.transmit]
283
        ret
284
 
285
  .collision:
286
        inc     [ARP_CONFLICTS + 4*edi]
3589 Serge 287
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: IP address conflict detected!\n"
3555 Serge 288
 
289
  .exit:
290
        call    kernel_free
291
        add     esp, 4                                          ; pop (balance stack)
292
 
3589 Serge 293
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: exiting\n"
3555 Serge 294
        ret
295
 
296
 
297
;---------------------------------------------------------------------------
298
;
299
; ARP_output_request
300
;
301
; IN:  ip in eax
302
;      device in edi
303
; OUT: /
304
;
305
;---------------------------------------------------------------------------
306
align 4
307
ARP_output_request:
308
 
309
        push    eax                             ; DestIP
310
        pushd   [IP_LIST + edi]                 ; SenderIP
311
        inc     [ARP_PACKETS_TX + edi]          ; assume we will succeed
312
 
3589 Serge 313
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_output_request: ip=%u.%u.%u.%u\n",\
3555 Serge 314
        [esp + 4]:1, [esp + 5]:1, [esp + 6]:1, [esp + 7]:1
315
 
316
        mov     ebx, [NET_DRV_LIST + edi]       ; device ptr
317
 
318
        lea     eax, [ebx + ETH_DEVICE.mac]     ; local device mac
319
        mov     edx, ETH_BROADCAST              ; broadcast mac
320
        mov     ecx, sizeof.ARP_header
321
        mov     di, ETHER_ARP
322
        call    ETH_output
323
        jz      .exit
324
 
325
        mov     ecx, eax
326
 
327
        mov     [edi + ARP_header.HardwareType], 0x0100         ; Ethernet
328
        mov     [edi + ARP_header.ProtocolType], 0x0008         ; IP
329
        mov     [edi + ARP_header.HardwareSize], 6              ; MAC-addr length
330
        mov     [edi + ARP_header.ProtocolSize], 4              ; IP-addr length
331
        mov     [edi + ARP_header.Opcode], ARP_REQ_OPCODE       ; Request
332
 
333
        add     edi, ARP_header.SenderMAC
334
 
335
        lea     esi, [ebx + ETH_DEVICE.mac]     ; SenderMac
336
        movsw                                   ;
337
        movsd                                   ;
338
        pop     eax                             ; SenderIP
339
        stosd                                   ;
340
 
341
        mov     eax, -1                         ; DestMac
342
        stosd                                   ;
343
        stosw                                   ;
344
        pop     eax                             ; DestIP
345
        stosd                                   ;
346
 
3589 Serge 347
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_output_request: device=%x\n", ebx
3555 Serge 348
 
349
        push    edx ecx
350
        call    [ebx + NET_DEVICE.transmit]
351
        ret
352
 
353
  .exit:
354
        add     esp, 4 + 4
3589 Serge 355
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_output_request: failed\n"
3555 Serge 356
        sub     eax, eax
357
        ret
358
 
359
 
360
;-----------------------------------------------------------------
361
;
362
; ARP_add_entry (or update)
363
;
364
; IN:  esi = ptr to entry (can easily be made on the stack)
365
; OUT: eax = entry #, -1 on error
366
;      edi = ptr to newly created entry
367
;
368
;-----------------------------------------------------------------      ; TODO: use a mutex
369
align 4
370
ARP_add_entry:
371
 
3589 Serge 372
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_add_entry: "
3555 Serge 373
 
374
        mov     ecx, [NumARP]
375
        cmp     ecx, ARP_TABLE_SIZE                                     ; list full ?
376
        jae     .error
377
 
378
        xor     eax, eax
379
        mov     edi, ARP_table
380
        mov     ecx, [esi + ARP_entry.IP]
381
  .loop:
382
        cmp     [edi + ARP_entry.Status], ARP_NO_ENTRY                  ; is this slot empty?
383
        je      .add
384
 
385
        cmp     [edi + ARP_entry.IP], ecx                               ; if not, check if it doesnt collide
386
        jne     .maybe_next
387
 
388
        cmp     [edi + ARP_entry.TTL], ARP_STATIC_ENTRY                 ; ok, its the same IP, update it if not static
389
        jne     .add
390
 
391
  .maybe_next:                                                          ; try the next slot
392
        add     edi, sizeof.ARP_entry
393
        inc     eax
394
        cmp     eax, ARP_TABLE_SIZE
395
        jae     .error
396
        jmp     .loop
397
 
398
  .add:
399
        mov     ecx, sizeof.ARP_entry/2
400
        rep     movsw
401
        inc     [NumARP]
402
        sub     edi, sizeof.ARP_entry
3589 Serge 403
        DEBUGF  DEBUG_NETWORK_VERBOSE, "entry=%u\n", eax
3555 Serge 404
 
405
        ret
406
 
407
  .error:
3589 Serge 408
        DEBUGF  DEBUG_NETWORK_VERBOSE, "failed\n"
3555 Serge 409
        mov     eax, -1
410
        ret
411
 
412
 
413
;-----------------------------------------------------------------
414
;
415
; ARP_del_entry
416
;
417
; IN:  esi = ptr to arp entry
418
; OUT: /
419
;
420
;-----------------------------------------------------------------
421
align 4
422
ARP_del_entry:
423
 
3589 Serge 424
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: entry=%x entrys=%u\n", esi, [NumARP]
425
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: IP=%u.%u.%u.%u\n", \
3555 Serge 426
        [esi + ARP_entry.IP]:1, [esi + ARP_entry.IP + 1]:1, [esi + ARP_entry.IP + 2]:1, [esi + ARP_entry.IP + 3]:1
427
 
428
        mov     ecx, ARP_table + (ARP_TABLE_SIZE - 1) * sizeof.ARP_entry
429
        sub     ecx, esi
430
        shr     ecx, 1
431
 
432
        mov     edi, esi
433
        add     esi, sizeof.ARP_entry
434
        rep     movsw
435
 
436
        xor     eax, eax
437
        mov     ecx, sizeof.ARP_entry/2
438
        rep     stosw
439
 
440
        dec     [NumARP]
3589 Serge 441
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: success\n"
3555 Serge 442
 
443
        ret
444
 
445
 
446
 
447
 
448
 
449
;-----------------------------------------------------------------
450
;
451
; ARP_IP_to_MAC
452
;
453
;  This function translates an IP address to a MAC address
454
;
455
;  IN:  eax = IPv4 address
456
;       edi = device number
457
;  OUT: eax = -1 on error, -2 means request send
458
;      else, ax = first two bytes of mac (high 16 bits of eax will be 0)
459
;       ebx = last four bytes of mac
460
;       edi = unchanged
461
;
462
;-----------------------------------------------------------------
463
align 4
464
ARP_IP_to_MAC:
465
 
3589 Serge 466
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: %u.%u", al, ah
3555 Serge 467
        rol     eax, 16
3589 Serge 468
        DEBUGF  DEBUG_NETWORK_VERBOSE, ".%u.%u\n", al, ah
3555 Serge 469
        rol     eax, 16
470
 
471
        cmp     eax, 0xffffffff
472
        je      .broadcast
473
 
474
;--------------------------------
475
; Try to find the IP in ARP_table
476
 
477
        mov     ecx, [NumARP]
478
        test    ecx, ecx
479
        jz      .not_in_list
480
        mov     esi, ARP_table + ARP_entry.IP
481
  .scan_loop:
482
        cmp     [esi], eax
483
        je      .found_it
484
        add     esi, sizeof.ARP_entry
485
        loop    .scan_loop
486
 
487
  .not_in_list:
3589 Serge 488
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: preparing for ARP request\n"
3555 Serge 489
 
490
;--------------------
491
; Send an ARP request
492
 
493
        push    eax edi                 ; save IP for ARP_output_request
494
 
495
; Now create the ARP entry
496
        pushw   ARP_REQUEST_TTL         ; TTL
497
        pushw   ARP_AWAITING_RESPONSE   ; status
498
        pushd   0                       ; mac
499
        pushw   0
500
        pushd   eax                     ; ip
501
        mov     esi, esp
502
        call    ARP_add_entry
503
        add     esp, sizeof.ARP_entry   ; clear the entry from stack
504
 
505
        cmp     eax, -1                 ; did ARP_add_entry fail?
506
        je      .full
507
 
508
        mov     esi, edi
509
        pop     edi eax                 ; IP in eax, device number in edi, for ARP_output_request
510
 
511
        push    esi edi
512
        call    ARP_output_request      ; And send a request
513
        pop     edi esi
514
 
515
;-----------------------------------------------
516
; At this point, we got an ARP entry in the list
517
  .found_it:
518
        cmp     [esi + ARP_entry.Status], ARP_VALID_MAPPING             ; Does it have a MAC assigned?
519
        je      .valid
520
 
521
if ARP_BLOCK
522
 
523
        cmp     [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE         ; Are we waiting for reply from remote end?
524
        jne     .give_up
525
        push    esi
526
        mov     esi, 10                 ; wait 10 ms
527
        call    delay_ms
528
        pop     esi
529
        jmp     .found_it               ; now check again
530
 
531
else
532
 
533
        jmp     .give_up
534
 
535
end if
536
 
537
  .valid:
3589 Serge 538
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: found MAC\n"
3555 Serge 539
        movzx   eax, word[esi + ARP_entry.MAC]
540
        mov     ebx, dword[esi + ARP_entry.MAC + 2]
541
        ret
542
 
543
  .full:
3589 Serge 544
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: table is full!\n"
3555 Serge 545
        add     esp, 8
546
  .give_up:
3589 Serge 547
        DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: entry has no valid mapping!\n"
3555 Serge 548
        mov     eax, -1
549
        ret
550
 
551
  .broadcast:
552
        mov     eax, 0x0000ffff
553
        mov     ebx, 0xffffffff
554
        ret
555
 
556
 
557
;-----------------------------------------------------------------
558
;
559
; ARP_API
560
;
561
; This function is called by system function 75
562
;
563
; IN:  subfunction number in bl
564
;      device number in bh
565
;      ecx, edx, .. depends on subfunction
566
;
567
; OUT:  ?
568
;
569
;-----------------------------------------------------------------
570
align 4
571
ARP_api:
572
 
573
        movzx   eax, bh
574
        shl     eax, 2
575
 
576
        and     ebx, 0xff
577
        cmp     ebx, .number
578
        ja      .error
579
        jmp     dword [.table + 4*ebx]
580
 
581
  .table:
582
        dd      .packets_tx     ; 0
583
        dd      .packets_rx     ; 1
584
        dd      .entries        ; 2
585
        dd      .read           ; 3
586
        dd      .write          ; 4
587
        dd      .remove         ; 5
588
        dd      .send_announce  ; 6
589
        dd      .conflicts      ; 7
590
  .number = ($ - .table) / 4 - 1
591
 
592
  .error:
593
        mov     eax, -1
594
        ret
595
 
596
  .packets_tx:
597
        mov     eax, [ARP_PACKETS_TX + eax]
598
        ret
599
 
600
  .packets_rx:
601
        mov     eax, [ARP_PACKETS_RX + eax]
602
        ret
603
 
604
  .conflicts:
605
        mov     eax, [ARP_CONFLICTS + eax]
606
        ret
607
 
608
  .entries:
609
        mov     eax, [NumARP]
610
        ret
611
 
612
  .read:
613
        cmp     ecx, [NumARP]
614
        jae     .error
615
        ; edi = pointer to buffer
616
        ; ecx = # entry
617
        imul    ecx, sizeof.ARP_entry
618
        add     ecx, ARP_table
619
        mov     esi, ecx
620
        mov     ecx, sizeof.ARP_entry/2
621
        rep     movsw
622
 
623
        xor     eax, eax
624
        ret
625
 
626
  .write:
627
        ; esi = pointer to buffer
628
        call    ARP_add_entry           ; out: eax = entry number, -1 on error
629
        ret
630
 
631
  .remove:
632
        ; ecx = # entry
633
        cmp     ecx, [NumARP]
634
        jae     .error
635
        imul    ecx, sizeof.ARP_entry
636
        lea     esi, [ARP_table + ecx]
637
        call    ARP_del_entry
638
        ret
639
 
640
  .send_announce:
641
        mov     edi, eax
642
        mov     eax, [IP_LIST + eax]
643
        call    ARP_output_request      ; now send a gratuitous ARP
644
        ret
645