Subversion Repositories Kolibri OS

Rev

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

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