Subversion Repositories Kolibri OS

Rev

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

Rev Author Line No. Line
425 victor 1
$Revision: 425 $
261 hidnplayr 2
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3
;;
4
;;  ARP.INC
5
;;
6
;;  Address Resolution Protocol
7
;;
8
;;  Last revision: 10.11.2006
9
;;
10
;;  This file contains the following:
11
;;   arp_table_manager - Manages an ARPTable
12
;;   arp_request - Sends an ARP request on the ethernet
13
;;   arp_handler - Called when an ARP packet is received
14
;;
15
;;  Changes history:
16
;;   22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net
17
;;   11.11.2006 - [Johnny_B] and [smb]
18
;;
19
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
20
 
21
ARP_NO_ENTRY                equ  0
22
ARP_VALID_MAPPING           equ  1
23
ARP_AWAITING_RESPONSE       equ  2
24
ARP_RESPONSE_TIMEOUT        equ  3
25
 
26
struc ARP_ENTRY     ;=14 bytes
27
{  .IP       dd  ?  ;+00
28
   .MAC      dp  ?  ;+04
29
   .Status   dw  ?  ;+10
30
   .TTL      dw  ?  ;+12 : ( in seconds )
31
}
32
 
33
virtual at 0
34
  ARP_ENTRY ARP_ENTRY
35
end virtual
36
 
37
; The TTL field is decremented every second, and is deleted when it
38
; reaches 0. It is refreshed every time a packet is received
39
; If the TTL field is 0xFFFF it is a static entry and is never deleted
40
; The status field can be the following values:
41
; 0x0000  entry not used
42
; 0x0001  entry holds a valid mapping
43
; 0x0002  entry contains an IP address, awaiting ARP response
44
; 0x0003  No response received to ARP request.
45
; The last status value is provided to allow the network layer to delete
46
; a packet that is queued awaiting an ARP response
47
 
48
 
49
; The follow is the ARP Table.
50
; This table must be manually updated and the kernel recompilied if
51
; changes are made to it.
52
; Empty entries are filled with zeros
53
 
54
ARP_ENTRY_SIZE              equ     14          ; Number of bytes per entry
55
ARP_TABLE_SIZE              equ     20          ; Size of table
56
ARP_TABLE_ENTRIES           equ     0           ; Number of static entries in the table
57
 
58
;TO ADD A STATIC ENTRY, DONT FORGET, PUT "ARPTable" from "uglobal" to "iglobal"!!!
59
;AND ALSO - IP and MAC have net byte-order, BUT STATUS AND TTL HAVE A MIRROR BYTE-ORDER!!!
60
uglobal
61
  ARPTable:
62
;example, static entry ->  db  11,22,33,44, 0x11,0x22,0x33,0x44,0x55,0x66, 0x01,0x00, 0xFF,0xFF
63
  times ( ARP_TABLE_SIZE - ARP_TABLE_ENTRIES ) * ARP_ENTRY_SIZE  db 0
64
endg
65
 
66
iglobal
67
  NumARP:        dd    ARP_TABLE_ENTRIES
68
  ARPTable_ptr   dd    ARPTable   ;pointer to ARPTable
69
endg
70
 
71
ARP_REQ_OPCODE              equ     0x0100  ;request
72
ARP_REP_OPCODE              equ     0x0200  ;reply
73
 
74
struc ARP_PACKET
75
{  .HardwareType dw   ?  ;+00
76
   .ProtocolType dw   ?  ;+02
77
   .HardwareSize db   ?  ;+04
78
   .ProtocolSize db   ?  ;+05
79
   .Opcode       dw   ?  ;+06
80
   .SenderMAC    dp   ?  ;+08
81
   .SenderIP     dd   ?  ;+14
82
   .TargetMAC    dp   ?  ;+18
83
   .TargetIP     dd   ?  ;+24
84
}
85
 
86
virtual at 0
87
  ARP_PACKET ARP_PACKET
88
end virtual
89
 
90
 
91
 
92
;***************************************************************************
93
;   Function
94
;      arp_table_manager  [by Johnny_B]
95
;
96
;   Description
97
;     Does a most required operations with ARP-table
98
;  IN:
99
;   Operation: see Opcode's constants below
100
;       Index: Index of entry in the ARP-table
101
;       Extra: Extra parameter for some Opcodes
102
;  OUT:
103
;   EAX = Returned value depends on opcodes, more detailed see below
104
;
105
;***************************************************************************
106
;Opcode's constants
107
ARP_TABLE_ADD                 equ  1
108
ARP_TABLE_DEL                 equ  2
109
ARP_TABLE_GET                 equ  3
110
ARP_TABLE_GET_ENTRIES_NUMBER  equ  4
111
ARP_TABLE_IP_TO_MAC           equ  5
112
ARP_TABLE_TIMER               equ  6
113
 
114
;Index's constants
115
EXTRA_IS_ARP_PACKET_PTR  equ  0   ;if Extra contain pointer to ARP_PACKET
116
EXTRA_IS_ARP_ENTRY_PTR   equ  -1  ;if Extra contain pointer to ARP_ENTRY
117
 
118
align 4
119
proc arp_table_manager stdcall uses ebx esi edi ecx edx,\
120
    Opcode:DWORD,Index:DWORD,Extra:DWORD
121
 
122
    mov     ebx, dword[ARPTable_ptr]   ;ARPTable base
123
    mov     ecx, dword[NumARP]         ;ARP-entries counter
124
 
125
    mov     eax, dword[Opcode]
126
    cmp     eax, ARP_TABLE_TIMER
127
    je      .timer
128
    cmp     eax, ARP_TABLE_ADD
129
    je      .add
130
    cmp     eax, ARP_TABLE_DEL
131
    je      .del
132
    cmp     eax, ARP_TABLE_GET
133
    je      .get
134
    cmp     eax, ARP_TABLE_IP_TO_MAC
135
    je      .ip_to_mac
136
    cmp     eax, ARP_TABLE_GET_ENTRIES_NUMBER
137
    je      .get_entries_number
138
    jmp     .exit     ;if unknown opcode
139
 
140
 
141
;;BEGIN TIMER
142
;;Description: it must be callback every second. It is responsible for removing expired routes.
143
;;IN:   Operation: ARP_TABLE_TIMER
144
;;      Index: must be zero
145
;;      Extra: must be zero
146
;;OUT:
147
;;  EAX=not defined
148
;;
149
.timer:
150
    test    ecx, ecx
151
    jz      .exit    ;if NumARP=0 nothing to do
152
    sub     ecx, ARP_TABLE_ENTRIES  ;ecx=dynamic entries number
153
    jz      .exit    ;if NumARP=number of static entries then exit
154
 
155
    add     ebx, ARP_TABLE_ENTRIES*ARP_ENTRY_SIZE  ;ebx=dynamic entries base
156
 
157
  .timer_loop:
158
    movsx   esi, word [ebx + ARP_ENTRY.TTL]
159
    cmp     esi, 0xFFFFFFFF
160
    je      .timer_loop_end  ;if TTL==0xFFFF then it's static entry
161
 
162
    test    esi, esi
163
    jnz     .timer_loop_end_with_dec  ;if TTL!=0
164
 
165
    ; Ok, TTL is 0
166
    ;if Status==AWAITING_RESPONSE and TTL==0
167
    ;then we have to change it to ARP_RESPONSE_TIMEOUT
168
    cmp     word [ebx + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE
169
    jne     @f
170
 
171
    mov     word [ebx + ARP_ENTRY.Status], ARP_RESPONSE_TIMEOUT
172
    mov     word [ebx + ARP_ENTRY.TTL], word 0x000A   ;10 sec
173
    jmp     .timer_loop_end
174
 
175
  @@:
176
    ;if TTL==0 and Status==VALID_MAPPING, we have to delete it
177
    ;if TTL==0 and Status==RESPONSE_TIMEOUT, delete too
178
    mov     esi, dword[NumARP]
179
    sub     esi, ecx          ;esi=index of entry, will be deleted
180
    stdcall arp_table_manager,ARP_TABLE_DEL,esi,0 ;opcode,index,extra
181
    jmp     .timer_loop_end
182
 
183
 
184
  .timer_loop_end_with_dec:
185
    dec     word [ebx + ARP_ENTRY.TTL]  ;decrease TTL
186
  .timer_loop_end:
187
    add     ebx, ARP_ENTRY_SIZE
188
    loop    .timer_loop
189
 
190
    jmp     .exit
191
;;END TIMER
192
 
193
;;BEGIN ADD
194
;;Description: it adds an entry in the table. If ARP-table already
195
;;             contains same IP, it will be updated.
196
;;IN:   Operation: ARP_TABLE_ADD
197
;;      Index: specifies what contains Extra-parameter
198
;;      Extra: if Index==EXTRA_IS_ARP_PACKET_PTR,
199
;;             then Extra contains pointer to ARP_PACKET,
200
;;             otherwise Extra contains pointer to ARP_ENTRY
201
;;OUT:
202
;;  EAX=index of entry, that has been added
203
;;
204
.add:
205
 
206
    sub     esp, ARP_ENTRY_SIZE   ;Allocate ARP_ENTRY_SIZE byte in stack
207
 
208
    mov     esi, [Extra]   ;pointer
209
    mov     edi, [Index]   ;opcode
210
 
211
    cmp     edi, EXTRA_IS_ARP_PACKET_PTR
212
    je      .arp_packet_to_entry ;if Extra contain ptr to ARP_PACKET and we have to form arp-entry
213
                                 ;else it contain ptr to arp-entry
214
 
215
    cld
216
          ; esi already has been loaded
217
    mov     edi, esp      ;ebx + eax=ARPTable_base + ARP-entry_base(where we will add)
218
    mov     ecx,ARP_ENTRY_SIZE/2  ;ARP_ENTRY_SIZE must be even number!!!
219
    rep     movsw    ;copy
220
    jmp     .search
221
 
222
  .arp_packet_to_entry:
223
    mov     edx, dword[esi + ARP_PACKET.SenderIP] ;esi=base of ARP_PACKET
224
    mov     [esp + ARP_ENTRY.IP], edx
225
 
226
    cld
227
    lea     esi, [esi + ARP_PACKET.SenderMAC]
228
    lea     edi, [esp + ARP_ENTRY.MAC]
229
    movsd
230
    movsw
231
    mov     word[esp + ARP_ENTRY.Status], ARP_VALID_MAPPING  ; specify the type - a valid entry
232
    mov     word[esp + ARP_ENTRY.TTL], 0x0E10    ; = 1 hour
233
 
234
  .search:
235
    mov     edx, dword[esp + ARP_ENTRY.IP]  ;edx=IP-address, which we'll search
236
    mov     ecx, dword[NumARP]              ;ecx=ARP-entries counter
237
    jecxz   .add_to_end                     ;if ARP-entries number == 0
238
    imul    eax, ecx, ARP_ENTRY_SIZE        ;eax=current table size(in bytes)
239
  @@:
240
    sub     eax, ARP_ENTRY_SIZE
241
    cmp     dword[ebx + eax + ARP_ENTRY.IP], edx
242
    loopnz  @b
243
    jz      .replace       ; found, replace existing entry, ptr to it is in eax
244
 
245
  .add_to_end:
246
    ;else add to end
247
    or      eax,-1    ;set eax=0xFFFFFFFF if adding is impossible
248
    mov     ecx, dword[NumARP]
249
    cmp     ecx, ARP_TABLE_SIZE
250
    je      .add_exit   ;if arp-entries number is equal to arp-table maxsize
251
 
252
    imul    eax, dword[NumARP], ARP_ENTRY_SIZE ;eax=ptr to end of ARPTable
253
    inc     dword [NumARP]    ;increase ARP-entries counter
254
 
255
  .replace:
256
    cld
257
    mov     esi, esp              ;esp=base of ARP-entry, that will be added
258
    lea     edi, [ebx + eax]      ;ebx + eax=ARPTable_base + ARP-entry_base(where we will add)
259
    mov     ecx,ARP_ENTRY_SIZE/2  ;ARP_ENTRY_SIZE must be even number!!!
260
    rep     movsw
261
 
262
    mov     ecx, ARP_ENTRY_SIZE
263
    xor     edx, edx  ;"div" takes operand from EDX:EAX
264
    div     ecx       ;eax=index of entry, which has been added
265
 
266
.add_exit:
267
    add     esp, ARP_ENTRY_SIZE   ;free stack
268
    jmp     .exit
269
;;END ADD
270
 
271
;;BEGIN DEL
272
;;Description: it deletes an entry in the table.
273
;;IN:   Operation: ARP_TABLE_DEL
274
;;      Index: index of entry, that should be deleted
275
;;      Extra: must be zero
276
;;OUT:
277
;;  EAX=not defined
278
;;
279
.del:
280
    mov     esi, [Index]
281
    imul    esi, ARP_ENTRY_SIZE
282
 
283
    mov     ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY_SIZE
284
    sub     ecx, esi
285
 
286
    lea     edi, [ebx + esi]            ;edi=ptr to entry that should be deleted
287
    lea     esi, [edi + ARP_ENTRY_SIZE] ;esi=ptr to next entry
288
 
289
    shr     ecx,1      ;ecx/2 => ARP_ENTRY_SIZE MUST BE EVEN NUMBER!
290
    cld
291
    rep     movsw
292
 
293
    dec     dword[NumARP] ;decrease arp-entries counter
294
    jmp     .exit
295
;;END DEL
296
 
297
;;BEGIN GET
298
;;Description: it reads an entry of table into buffer.
299
;;IN:   Operation: ARP_TABLE_GET
300
;;      Index: index of entry, that should be read
301
;;      Extra: pointer to buffer for reading(size must be equal to ARP_ENTRY_SIZE)
302
;;OUT:
303
;;  EAX=not defined
304
;;
305
.get:
306
    mov     esi, [Index]
307
    imul    esi, ARP_ENTRY_SIZE   ;esi=ptr to required ARP_ENTRY
308
    mov     edi, [Extra]          ;edi=buffer for reading
309
    mov     ecx, ARP_ENTRY_SIZE/2 ; must be even number!!!
310
    cld
311
    rep     movsw
312
    jmp     .exit
313
;;END GET
314
 
315
;;BEGIN IP_TO_MAC
316
;;Description: it gets an IP from Index, scans each entry in the table and writes
317
;;             MAC, that relates to specified IP, into buffer specified in Extra.
318
;;             And if it cannot find an IP-address in the table, it does an ARP-request of that.
319
;;IN:   Operation: ARP_TABLE_IP_TO_MAC
320
;;      Index: IP that should be transformed into MAC
321
;;      Extra: pointer to buffer where will be written the MAC-address.
322
;;OUT:
323
;;  EAX=ARP table entry status code.
324
;;      If EAX==ARP_NO_ENTRY, IP isn't found in the table and we have sent the request.
325
;;      If EAX==ARP_AWAITING_RESPONSE, we wait the response from remote system.
326
;;      If EAX==ARP_RESPONSE_TIMEOUT, remote system not responds too long.
327
;;      If EAX==ARP_VALID_MAPPING, all is ok, we've got a true MAC.
328
;;
329
;;  If MAC will equal to a zero, in the buffer. It means, that IP-address was not yet
330
;;  resolved, or that doesn't exist. I recommend you, to do at most 3-5 calls of this
331
;;  function with 1sec delay. sure, only if it not return a valid MAC after a first call.
332
;;
333
.ip_to_mac:
334
 
335
    xor     eax, eax
336
    mov     edi, dword[Extra]
337
    cld
338
    stosd
339
    stosw
340
 
341
    cmp     dword[NumARP], 0
342
    je      .ip_to_mac_send_request ;if ARP-table not contain an entries, we have to request IP.
343
                                    ;EAX will be containing a zero, it's equal to ARP_NO_ENTRY
344
 
345
    ; first, check destination IP to see if it is on 'this' network.
346
    ; The test is:
347
    ; if ( destIP & subnet_mask == stack_ip & subnet_mask )
348
    ;   destination is local
349
    ; else
350
    ;  destination is remote, so pass to gateway
351
 
352
    mov     eax, [Index]       ;eax=required IP
353
    mov     esi, eax
354
    and     esi, [subnet_mask]
355
    mov     ecx, [stack_ip]
356
    and     ecx, [subnet_mask]
357
    cmp     esi, ecx
358
    je      @f        ;if we and target IP are located in the same network
359
    mov     eax, [gateway_ip]
360
  @@:
361
 
362
    mov     ecx, dword[NumARP]
363
    imul    esi, ecx, ARP_ENTRY_SIZE  ;esi=current ARP-table size
364
 
365
  @@:
366
    sub     esi, ARP_ENTRY_SIZE
367
    cmp     [ebx + esi], eax         ; ebx=ARPTable base
368
    loopnz  @b                       ; Return back if non match
369
    jnz     .ip_to_mac_send_request  ; and request IP->MAC if none found in the table
370
 
371
    ; Return the entry status in eax
372
    movzx   eax, word[ebx + esi + ARP_ENTRY.Status]
373
 
374
    ; esi holds index
375
    cld
376
    lea     esi, [ebx + esi + ARP_ENTRY.MAC]
377
    mov     edi, [Extra]   ;edi=ptr to buffer for write MAC
378
    movsd
379
    movsw
380
    jmp     .exit
381
 
382
  .ip_to_mac_send_request:
383
    stdcall arp_request,[Index],stack_ip,node_addr  ;TargetIP,SenderIP_ptr,SenderMAC_ptr
384
    mov     eax, ARP_NO_ENTRY
385
    jmp     .exit
386
 
387
;;END IP_TO_MAC
388
 
389
;;BEGIN GET_ENTRIES_NUMBER
390
;;Description: returns an ARP-entries number in the ARPTable
391
;;IN:   Operation: ARP_TABLE_GET_ENTRIES_NUMBER
392
;;      Index: must be zero
393
;;      Extra: must be zero
394
;;OUT:
395
;;  EAX=ARP-entries number in the ARPTable
396
  .get_entries_number:
397
    mov     eax, dword[NumARP]
398
    jmp     .exit
399
;;END GET_ENTRIES_NUMBER
400
 
401
.exit:
402
    ret
403
endp
404
 
405
 
406
;***************************************************************************
407
;   Function
408
;      arp_handler
409
;
410
;   Description
411
;      Called when an ARP packet is received on the ethernet
412
;      Header + Data is in Ether_buffer[]
413
;       It looks to see if the packet is a request to resolve this Hosts
414
;       IP address. If it is, send the ARP reply packet.
415
;      This Hosts IP address is in dword [stack_ip]  ( in network format )
416
;       This Hosts MAC address is in node_addr[6]
417
;      All registers may be destroyed
418
;
419
;***************************************************************************
420
arp_handler:
421
    ; Is this a REQUEST?
422
    ; Is this a request for My Host IP
423
    ; Yes - So construct a response message.
424
    ; Send this message to the ethernet card for transmission
425
 
426
    stdcall arp_table_manager,ARP_TABLE_ADD,EXTRA_IS_ARP_PACKET_PTR,ETH_FRAME.Data + ARP_PACKET
427
 
428
    inc     dword[arp_rx_count] ;increase ARP-packets counter
429
 
430
    cmp     word[ETH_FRAME.Data + ARP_PACKET.Opcode], ARP_REQ_OPCODE  ; Is this a request packet?
431
    jne     .exit            ; No - so exit
432
 
433
    mov     eax, [stack_ip]
434
    cmp     eax, dword[ETH_FRAME.Data + ARP_PACKET.TargetIP]         ; Is it looking for my IP address?
435
    jne     .exit            ; No - so quit now
436
 
437
    ; OK, it is a request for my MAC address. Build the frame and send it
438
    ; We can reuse the packet.
439
 
440
    mov     word[ETH_FRAME.Data + ARP_PACKET.Opcode], ARP_REP_OPCODE
441
 
442
    cld
443
    mov     esi, ETH_FRAME.Data + ARP_PACKET.SenderMAC
444
    mov     edi, ETH_FRAME.Data + ARP_PACKET.TargetMAC
445
    movsd
446
    movsw
447
 
448
    mov     esi, ETH_FRAME.Data + ARP_PACKET.SenderIP
449
    mov     edi, ETH_FRAME.Data + ARP_PACKET.TargetIP
450
    movsd
451
 
452
    mov     esi, node_addr
453
    mov     edi, ETH_FRAME.Data + ARP_PACKET.SenderMAC
454
    movsd
455
    movsw
456
 
457
    mov     esi, stack_ip
458
    mov     edi, ETH_FRAME.Data + ARP_PACKET.SenderIP
459
    movsd
460
 
461
    ; Now, send it!
462
    mov     edi, ETH_FRAME.Data + ARP_PACKET.TargetMAC   ;ptr to destination MAC address
463
    mov     bx, ETHER_ARP               ;type of protocol
464
    mov     ecx, 28                     ;data size
465
    mov     esi, ETH_FRAME.Data + ARP_PACKET             ;ptr to data
466
    call    dword [drvr_transmit]       ;transmit packet
467
 
468
  .exit:
469
    ret
470
 
471
 
472
;***************************************************************************
473
;   Function
474
;      arp_request  [by Johnny_B]
475
;
476
;   Description
477
;      Sends an ARP request on the ethernet
478
;   IN:
479
;     TargetIP      : requested IP address
480
;     SenderIP_ptr  : POINTER to sender's IP address(our system's address)
481
;     SenderMAC_ptr : POINTER to sender's MAC address(our system's address)
482
;   OUT:
483
;     EAX=0 (if all is ok), otherwise EAX is not defined
484
;
485
;      EBX,ESI,EDI will be saved
486
;
487
;***************************************************************************
488
proc arp_request stdcall uses ebx esi edi,\
489
    TargetIP:DWORD, SenderIP_ptr:DWORD, SenderMAC_ptr:DWORD
490
 
491
    inc     dword[arp_tx_count]  ; increase counter
492
 
493
    sub     esp, 28  ; allocate memory for ARP_PACKET
494
 
495
    mov     word[esp + ARP_PACKET.HardwareType],0x0100 ;Ethernet
496
    mov     word[esp + ARP_PACKET.ProtocolType],0x0008 ;IP
497
    mov     byte[esp + ARP_PACKET.HardwareSize],0x06   ;MAC-addr length
498
    mov     byte[esp + ARP_PACKET.ProtocolSize],0x04   ;IP-addr length
499
    mov     word[esp + ARP_PACKET.Opcode],0x0100       ;Request
500
 
501
    cld
502
    mov     esi,[SenderMAC_ptr]
503
    lea     edi,[esp + ARP_PACKET.SenderMAC]       ;Our MAC-addr
504
    movsd
505
    movsw
506
 
507
    mov     esi,[SenderIP_ptr]
508
    lea     edi,[esp + ARP_PACKET.SenderIP]        ;Our IP-addr
509
    movsd
510
 
511
    xor     eax, eax
512
    lea     edi, [esp + ARP_PACKET.TargetMAC]      ;Required MAC-addr(zeroed)
513
    stosd
514
    stosw
515
 
516
    mov     esi, dword[TargetIP]
517
    mov     dword[esp + ARP_PACKET.TargetIP],esi   ;Required IP-addr(we get it as function parameter)
518
 
519
    ; Now, send it!
520
    mov     edi, broadcast_add     ; Pointer to 48 bit destination address
521
    mov     bx, ETHER_ARP          ; Type of packet
522
    mov     ecx, 28                ; size of packet
523
    lea     esi, [esp + ARP_PACKET]; pointer to packet data
524
    call    dword [drvr_transmit]  ; Call the drivers transmit function
525
 
526
    add     esp, 28  ; free memory, allocated before for ARP_PACKET
527
 
528
    ; Add an entry in the ARP table, awaiting response
529
    sub     esp, ARP_ENTRY_SIZE    ;allocate memory for ARP-entry
530
 
531
    mov     esi, dword[TargetIP]
532
    mov     dword[esp + ARP_ENTRY.IP],esi
533
 
534
    lea     edi, [esp + ARP_ENTRY.MAC]
535
    xor     eax, eax
536
    stosd
537
    stosw
538
 
539
    mov     word[esp + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE
540
    mov     word[esp + ARP_ENTRY.TTL], 0x000A  ; 10 seconds
541
 
542
    stdcall arp_table_manager,ARP_TABLE_ADD,EXTRA_IS_ARP_ENTRY_PTR,esp
543
    add     esp, ARP_ENTRY_SIZE  ; free memory
544
 
545
.exit:
546
    ret
547
endp