Subversion Repositories Kolibri OS

Rev

Rev 1485 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2010. 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.  
  20. $Revision: 1514 $
  21.  
  22.  
  23. ARP_NO_ENTRY            equ  0
  24. ARP_VALID_MAPPING       equ  1
  25. ARP_AWAITING_RESPONSE   equ  2
  26. ARP_RESPONSE_TIMEOUT    equ  3
  27.  
  28. ARP_REQUEST_TTL         = 20 ; in seconds
  29. ARP_ENTRY_TTL           = 600 ; in seconds
  30.  
  31. ETHER_ARP               equ  0x0608
  32.  
  33. ARP_REQ_OPCODE          equ  0x0100  ; request
  34. ARP_REP_OPCODE          equ  0x0200  ; reply
  35.  
  36. ARP_TABLE_SIZE          equ  20      ; Size of table
  37.  
  38. struct ARP_ENTRY
  39.        .IP              dd  ?
  40.        .MAC             dp  ?
  41.        .Status          dw  ?
  42.        .TTL             dw  ?  ; in seconds
  43.        .size:
  44. ends
  45.  
  46. struct ARP_Packet
  47.        .HardwareType    dw  ?
  48.        .ProtocolType    dw  ?
  49.        .HardwareSize    db  ?
  50.        .ProtocolSize    db  ?
  51.        .Opcode          dw  ?
  52.        .SenderMAC       dp  ?
  53.        .SenderIP        dd  ?
  54.        .TargetMAC       dp  ?
  55.        .TargetIP        dd  ?
  56. ends
  57.  
  58.  
  59. ; The TTL field is decremented every second, and is deleted when it
  60. ; reaches 0. It is refreshed every time a packet is received
  61. ; If the TTL field is 0xFFFF it is a static entry and is never deleted
  62. ; The status field can be the following values:
  63. ; 0x0000  entry not used
  64. ; 0x0001  entry holds a valid mapping
  65. ; 0x0002  entry contains an IP address, awaiting ARP response
  66. ; 0x0003  No response received to ARP request.
  67. ; The last status value is provided to allow the network layer to delete
  68. ; a packet that is queued awaiting an ARP response
  69.  
  70. align 4
  71. uglobal
  72.  
  73.         NumARP          dd ?
  74.  
  75.         ARPTable        rb ARP_ENTRY.size * ARP_TABLE_SIZE
  76.  
  77.         ARP_PACKETS_TX  rd  MAX_NET_DEVICES
  78.         ARP_PACKETS_RX  rd  MAX_NET_DEVICES
  79.  
  80.  
  81. endg
  82.  
  83.  
  84.  
  85. ;-----------------------------------------------------------------
  86. ;
  87. ; ARP_init
  88. ;
  89. ;  This function resets all ARP variables
  90. ;
  91. ;  IN:  /
  92. ;  OUT: /
  93. ;
  94. ;-----------------------------------------------------------------
  95. align 4
  96. ARP_init:
  97.  
  98.         xor     eax, eax
  99.  
  100.         mov     [NumARP], eax
  101.  
  102.         mov     edi, ARP_PACKETS_TX
  103.         mov     ecx, 2*MAX_NET_DEVICES
  104.         rep     stosd
  105.  
  106.         ret
  107.  
  108.  
  109. ;-----------------------------------------------------------------
  110. ;
  111. ; ARP_IP_to_MAC
  112. ;
  113. ;  This function resets all ARP variables
  114. ;
  115. ;  IN: eax = IPv4 address
  116. ;  OUT: eax = -1 on error, else eax = first two bytes of mac
  117. ;                   ( high 16 bits are zero)
  118. ;       ebx = last four bytes of mac                                  ; TODO: special eax value for 'request send'
  119. ;
  120. ;-----------------------------------------------------------------
  121. align 4
  122. ARP_IP_to_MAC:
  123.  
  124.         DEBUGF 1,"ARP_IP_to_MAC\n"
  125.  
  126.     ; first, check destination IP to see if it is on 'this' network.
  127.     ; The test is:
  128.     ; if ( destIP & subnet_mask == stack_ip & subnet_mask )
  129.     ;   destination is local
  130.     ; else
  131.     ;  destination is remote, so pass to gateway
  132.  
  133.         xor     edx, edx ; TODO: find device num in edx
  134.  
  135.         mov     ebx, [IP_LIST+edx]
  136.         and     ebx, [SUBNET_LIST+edx]
  137.  
  138.         mov     ecx, eax
  139.         and     ecx, [SUBNET_LIST+edx]
  140.  
  141.         cmp     ecx, ebx
  142.         je      .local
  143.  
  144.         mov     eax, [GATEWAY_LIST+edx]
  145.         DEBUGF 1,"requested IP is not on subnet, using gateway\n"
  146.  
  147.   .local:
  148.    ; try to find it on the list
  149.         mov     ecx, [NumARP]
  150.         test    ecx, ecx
  151.         jz      .not_in_list
  152.         mov     esi, ARPTable + ARP_ENTRY.IP
  153.   .scan_loop:
  154.         cmp     [esi], eax
  155.         je      .found_it
  156.         add     esi, ARP_ENTRY.size
  157.         loop    .scan_loop
  158.   .not_in_list:
  159.  
  160.         DEBUGF 1,"IP not found on list, preparing for ARP request\n"
  161.  
  162.    ; if not, reserve an entry in list and send an ARP request packet
  163.  
  164.         push    eax
  165.  
  166.         pushw   ARP_REQUEST_TTL
  167.         pushw   ARP_AWAITING_RESPONSE
  168.         pushd   0
  169.         pushw   0
  170.         pushd   eax
  171.         call    ARP_add_entry
  172.         cmp     eax, -1
  173.         je      .full
  174.  
  175.         ; <Some dirty test code>
  176.  
  177.         ; This piece of code waits for an ARP reply
  178.  
  179.         mov     ebx, eax
  180.         pop     eax
  181.         push    ebx
  182.         call    ARP_create_request
  183.  
  184.         push    [timer_ticks]
  185.         add     dword[esp], 100*ARP_REQUEST_TTL
  186.         DEBUGF 1,"Waiting for ARP reply, time: %x, entry:%u\n",[timer_ticks], [esp + 4]
  187.    .dirty_loop:
  188.  
  189.         call    change_task     ; The ARP reply hasnt been received yet, tell the processor to do some other stuff first
  190.  
  191.         mov     eax, [esp + 4]
  192.         imul    eax, ARP_ENTRY.size
  193.         add     eax, ARPTable
  194.         cmp     [eax + ARP_ENTRY.Status], ARP_VALID_MAPPING
  195.         je      .gogogo
  196.  
  197.         mov     eax, [esp]      ; Check if the reply hasnt timed-out yet
  198.         cmp     [timer_ticks], eax
  199.         jl      .dirty_loop
  200.  
  201.         ; </Some dirty test code>
  202.         or      eax, -1
  203.         add     esp, 8
  204.         ret
  205.  
  206.   .found_it:
  207.         DEBUGF 1,"found MAC in ARPTable\n"
  208.         movzx  eax, word [esi+ARP_ENTRY.MAC]
  209.         mov    ebx, dword[esi+ARP_ENTRY.MAC+2]
  210.         ret
  211.  
  212.   .full:
  213.         add     esp, 4
  214.         mov     eax, -1
  215.         ret
  216.  
  217.   .gogogo:
  218.         DEBUGF 1,"got ARP reply, time: %x\n",[timer_ticks]
  219.         mov    ebx, dword[eax+ARP_ENTRY.MAC+2]
  220.         movzx  eax, word [eax+ARP_ENTRY.MAC]
  221.         add    esp, 8
  222.         ret
  223.  
  224.  
  225. ;---------------------------------------------------------------------------
  226. ;
  227. ; ARP_create_request
  228. ;
  229. ; IN:  ip in eax
  230. ;
  231. ; OUT: /
  232. ;
  233. ;---------------------------------------------------------------------------
  234. align 4
  235. ARP_create_request:
  236.  
  237.         DEBUGF 1,"Create ARP Packet\n"
  238.  
  239.         call    IPv4_dest_to_dev
  240.  
  241.         push    eax                                             ; DestIP
  242.         mov     eax, [IP_LIST+4*edi]                            ; senderIP
  243.         push    eax
  244.  
  245.         mov     edi, [NET_DRV_LIST + 4*edi]
  246.         lea     eax, [edi + ETH_DEVICE.mac]
  247.         mov     ebx, ETH_BROADCAST
  248.         mov     ecx, 60 ; minimum packet size
  249.         mov     edx, edi ;;;
  250.         mov     di , ETHER_ARP
  251.         call    ETH_create_packet
  252.         jz      .exit
  253.  
  254.         mov     ecx, eax
  255.  
  256.         mov     [edi + ARP_Packet.HardwareType], 0x0100 ;Ethernet
  257.         mov     [edi + ARP_Packet.ProtocolType], 0x0008 ;IP
  258.         mov     [edi + ARP_Packet.HardwareSize], 6   ;MAC-addr length
  259.         mov     [edi + ARP_Packet.ProtocolSize], 4   ;IP-addr length
  260.         mov     [edi + ARP_Packet.Opcode], ARP_REQ_OPCODE      ;Request
  261.  
  262.         add     edi, ARP_Packet.SenderMAC                       ; sendermac
  263.         lea     esi, [ebx + ETH_DEVICE.mac]                     ;
  264.         movsw                                                   ;
  265.         movsd                                                   ;
  266.         pop     eax                                             ;
  267.         stosd                                                   ;
  268.         mov     eax, -1                                         ; destmac
  269.         stosd                                                   ;
  270.         stosw                                                   ;
  271.         pop     eax
  272.         stosd                                                   ;
  273.  
  274.         DEBUGF 1,"ARP Packet for device %x created successfully\n", ebx
  275.  
  276.         push    edx ecx
  277.         jmp     NET_send
  278.  
  279.   .exit:
  280.         add     esp, 8
  281.         DEBUGF 1,"Create ARP Packet - failed\n"
  282.         mov     eax, -1
  283.         ret
  284.  
  285.  
  286.  
  287. ;---------------------------------------------------------------------------
  288. ;
  289. ; ARP_decrease_entry_ttls
  290. ;
  291. ; IN: /
  292. ; OUT: /
  293. ;
  294. ;---------------------------------------------------------------------------
  295. align 4
  296. ARP_decrease_entry_ttls:
  297.  
  298.         mov     ecx, [NumARP]
  299.         test    ecx, ecx
  300.         jz      .exit
  301.  
  302.         mov     ebx, ARPTable
  303.  
  304. .timer_loop:
  305.  
  306.         cmp     [ebx + ARP_ENTRY.TTL], 0xFFFF
  307.         je      .timer_loop_end  ;if TTL==0xFFFF then it's static entry
  308.  
  309.         cmp     [ebx + ARP_ENTRY.TTL], 0
  310.         jnz     .timer_loop_end_with_dec  ;if TTL!=0
  311.  
  312.         ; Ok, TTL is 0
  313.         ;if Status==AWAITING_RESPONSE and TTL==0
  314.         ;then we have to change it to ARP_RESPONSE_TIMEOUT
  315.         cmp     [ebx + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE
  316.         jne     @f
  317.  
  318.         mov     [ebx + ARP_ENTRY.Status], ARP_RESPONSE_TIMEOUT
  319.         mov     [ebx + ARP_ENTRY.TTL], word 0x000A   ;10 sec
  320.         jmp     .timer_loop_end
  321.  
  322.   @@:
  323.         ;if TTL==0 and Status==VALID_MAPPING, we have to delete it
  324.         ;if TTL==0 and Status==RESPONSE_TIMEOUT, delete too
  325.         mov     esi, [NumARP]
  326.         sub     esi, ecx          ;esi=index of entry, will be deleted
  327.  
  328.         push    ebx ecx
  329.         call    ARP_del_entry
  330.         pop     ecx ebx
  331.  
  332.         jmp     .timer_loop_end
  333.  
  334.  
  335. .timer_loop_end_with_dec:
  336.  
  337.         dec     [ebx + ARP_ENTRY.TTL]  ;decrease TTL
  338.  
  339. .timer_loop_end:
  340.  
  341.         add     ebx, ARP_ENTRY.size
  342.         loop    .timer_loop
  343.  
  344. .exit:
  345.  
  346.         ret
  347.  
  348. ;-----------------------------------------------------------------
  349. ;
  350. ; ARP_add_entry (or update)
  351. ;
  352. ; IN: arp entry in stack: esp     .IP
  353. ;                         esp+4   .MAC
  354. ;                         esp+10  .Status
  355. ;                         esp+12  .TTL
  356. ;                         esp+14
  357. ;
  358. ; OUT: eax = entry #, -1 on error
  359. ;
  360. ;-----------------------------------------------------------------   ; TODO: use a mutex
  361. align 4
  362. ARP_add_entry:
  363.  
  364.         DEBUGF 1,"ARP add entry: "
  365.  
  366.         mov     ecx, [NumARP]
  367.         test    ecx, ecx
  368.         jz      .add
  369.  
  370.         mov     eax, dword[esp + 4 + ARP_ENTRY.MAC]
  371.         mov     bx , word[esp + 4 + ARP_ENTRY.MAC + 4]
  372.         mov     esi, ARPTable
  373.  
  374. .loop:
  375.         cmp     dword [esi + ARP_ENTRY.MAC], eax
  376.         jne     .maybe_next
  377.         cmp     word [esi + ARP_ENTRY.MAC + 4], bx
  378.         jne     .maybe_next
  379.  
  380.         cmp     dword[esi + ARP_ENTRY.TTL], 0xFFFF ; static entry
  381.         jne     .notstatic
  382.         cmp     dword[esp + 4 + ARP_ENTRY.TTL], 0xFFFF
  383.         jne     .error
  384. .notstatic:
  385.  
  386.         mov     ebx, [NumARP]
  387.         xchg    ebx, ecx
  388.         sub     ecx, ebx
  389.         jmp     .add
  390.  
  391. .maybe_next:
  392.         add     esi, ARP_ENTRY.size
  393.         loop    .loop
  394.  
  395.         mov     ecx, [NumARP]
  396.         cmp     ecx, ARP_TABLE_SIZE
  397.         jge     .error
  398.  
  399. .add:
  400.         push    ecx
  401.         imul    ecx, ARP_ENTRY.size
  402.         lea     edi, [ecx + ARPTable]
  403.         lea     esi, [esp + 8]
  404.         mov     ecx, ARP_ENTRY.size/2
  405.         repz    movsw
  406.  
  407.         inc     [NumARP]
  408.         pop     eax
  409.         DEBUGF 1,"New entry created: %u\n", eax
  410. .exit:
  411.         DEBUGF 1,"Exiting\n"
  412.         ret     ARP_ENTRY.size
  413.  
  414. .error:
  415.  
  416.         DEBUGF 1,"error! \n"
  417.  
  418.         mov     eax, -1
  419.         jmp     .exit
  420.  
  421.  
  422. ;-----------------------------------------------------------------
  423. ;
  424. ; ARP_del_entry
  425. ;
  426. ; IN: entry # in esi
  427. ; OUT: /
  428. ;
  429. ;-----------------------------------------------------------------
  430. align 4
  431. ARP_del_entry:
  432.  
  433.         DEBUGF 1,"ARP del entry %u, total entrys: %u\n", esi, [NumARP]
  434.  
  435.         cmp     esi, [NumARP]
  436.         jge     .error
  437.  
  438.         imul    esi, ARP_ENTRY.size
  439.  
  440.         mov     ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY.size
  441.         sub     ecx, esi
  442.  
  443.         lea     edi, [ARPTable + esi]            ;edi=ptr to entry that should be deleted
  444.         lea     esi, [edi + ARP_ENTRY.size] ;esi=ptr to next entry
  445.  
  446.         shr     ecx,1      ;ecx/2 => ARP_ENTRY_SIZE MUST BE EVEN NUMBER!
  447.         rep     movsw
  448.  
  449.         dec     [NumARP] ;decrease arp-entries counter
  450.         DEBUGF 1,"ARP entry deleted\n"
  451. .error:
  452.         ret
  453.  
  454.  
  455.  
  456.  
  457. ;-----------------------------------------------------------------
  458. ;
  459. ; ARP_Handler:
  460. ;
  461. ;  This function handles ARP protocol over ethernet
  462. ;  (other protocols may follow in the future)
  463. ;
  464. ;  IN:  Pointer to buffer in [esp]
  465. ;       size of buffer in [esp+4]
  466. ;       packet size (without ethernet header) in ecx
  467. ;  OUT: /
  468. ;
  469. ;-----------------------------------------------------------------
  470. align 4
  471. ARP_handler:
  472.  
  473.         DEBUGF  1,"ARP_Handler - start\n"
  474.         cmp     ecx, 28
  475.         jl      .exit
  476.  
  477.         cmp     word [edx + ARP_Packet.Opcode], ARP_REP_OPCODE  ; Is this a reply packet?
  478.         jne     .maybe_request
  479.  
  480.         DEBUGF  1,"ARP_Handler - it's a reply packet from %u.%u.%u.%u\n",\
  481.         [edx + ARP_Packet.SenderIP]:1,[edx + ARP_Packet.SenderIP+1]:1,[edx + ARP_Packet.SenderIP+2]:1,[edx + ARP_Packet.SenderIP+3]:1,
  482.  
  483.         mov     ecx, [NumARP]
  484.         test    ecx, ecx
  485.         jz      .exit
  486.  
  487.         mov     eax, [edx + ARP_Packet.SenderIP]
  488.         mov     esi, ARPTable+ARP_ENTRY.IP
  489.  
  490.   .loop:
  491.         cmp     [esi], eax
  492.         je      .gotit
  493.         add     esi, ARP_ENTRY.size
  494.         loop    .loop
  495.  
  496.         jmp     .exit
  497.  
  498.   .gotit:
  499.  
  500.         DEBUGF  1,"ARP_Handler - found matching entry\n"
  501.  
  502.         cmp     [esi+ARP_ENTRY.Status], 0x0300   ;if it is a static entry, dont touch it
  503.         je      .exit
  504.  
  505.         DEBUGF  1,"ARP_Handler - updating entry\n"
  506.  
  507.         mov     [esi+ARP_ENTRY.Status], ARP_VALID_MAPPING
  508.         mov     [esi+ARP_ENTRY.TTL], ARP_ENTRY_TTL
  509.  
  510.         mov     eax, dword [edx + ARP_Packet.SenderMAC]
  511.         mov     dword [esi+ARP_ENTRY.MAC], eax
  512.         mov     ax , word [edx + ARP_Packet.SenderMAC + 4]
  513.         mov     word [esi+ARP_ENTRY.MAC+4], ax
  514.  
  515.         jmp     .exit
  516.  
  517.  
  518. ;------
  519.  
  520.  
  521.   .maybe_request:
  522.         cmp     word [edx + ARP_Packet.Opcode], ARP_REQ_OPCODE  ; Is this a request packet?
  523.         jne     .exit
  524.  
  525.         call    NET_ptr_to_num
  526.         DEBUGF  1,"ARP Request packet through device: %u\n", edi
  527.         inc     [ARP_PACKETS_RX+4*edi]
  528.         cmp     edi, -1
  529.         jz      .exit
  530.  
  531.         mov     eax, edi
  532.         shl     eax, 2
  533.         add     eax, IP_LIST
  534.         mov     eax, [eax]
  535.         cmp     eax, [edx + ARP_Packet.TargetIP]                ; Is it looking for my IP address?
  536.         jnz     .exit
  537.         push    eax
  538.         push    edi
  539.  
  540. ; OK, it is a request for one of our MAC addresses. Build the frame and send it
  541. ; We can reuse the buffer.  (faster then using ARP_create_packet)
  542.  
  543.         cld
  544.         lea     esi, [edx + ARP_Packet.SenderMAC]
  545.         lea     edi, [edx + ARP_Packet.TargetMAC]
  546.         movsd                                                   ; Move Sender Mac to Dest MAC
  547.         movsw                                                   ;
  548.         movsd                                                   ; Move sender IP to Dest IP
  549.  
  550.         pop     esi
  551.         mov     esi, [NET_DRV_LIST + 4*esi]
  552.         lea     esi, [esi + ETH_DEVICE.mac]
  553.         lea     edi, [edx + ARP_Packet.SenderMAC]
  554.         movsd                                                   ; Copy MAC address from in MAC_LIST
  555.         movsw                                                   ;
  556.         pop     eax
  557.         stosd                                                   ; Write our IP
  558.  
  559.         mov     word [edx + ARP_Packet.Opcode], ARP_REP_OPCODE
  560.  
  561. ; Now, Fill in ETHERNET header
  562.  
  563.         mov     edi, [esp]
  564.         lea     esi, [edx + ARP_Packet.TargetMAC]
  565.         movsd
  566.         movsw
  567.         lea     esi, [edx + ARP_Packet.SenderMAC]
  568.         movsd
  569.         movsw
  570. ;        mov     ax , ETHER_ARP
  571. ;        stosw
  572.  
  573.         DEBUGF  1,"ARP_Handler - Sending reply \n"
  574.  
  575.         jmp     NET_send                                      ; And send it!
  576.  
  577.      .exit:
  578.         call    kernel_free
  579.         add     esp, 4                                          ; pop (balance stack)
  580.  
  581.         DEBUGF 1,"ARP_Handler - exiting\n"
  582.         ret
  583.  
  584.  
  585.  
  586.  
  587. ;-----------------------------------------------------------------
  588. ;
  589. ; ARP_API
  590. ;
  591. ; This function is called by system function 75
  592. ;
  593. ; IN:  subfunction number in bl
  594. ;      device number in bh
  595. ;      ecx, edx, .. depends on subfunction
  596. ;
  597. ; OUT:  ?
  598. ;
  599. ;-----------------------------------------------------------------
  600. align 4
  601. ARP_API:
  602.  
  603.         movzx   eax, bh
  604.         shl     eax, 2
  605.  
  606.         test    bl, bl
  607.         jz      .packets_tx     ; 0
  608.         dec     bl
  609.         jz      .packets_rx     ; 1
  610.         dec     bl
  611.         jz      .entries        ; 2
  612.         dec     bl
  613.         jz      .read           ; 3
  614.         dec     bl
  615.         jz      .write          ; 4
  616.         dec     bl
  617.         jz      .remove         ; 5
  618.         dec     bl
  619.  
  620. .error:
  621.         mov     eax, -1
  622.         ret
  623.  
  624. .packets_tx:
  625.         add     eax, ARP_PACKETS_TX
  626.         mov     eax, [eax]
  627.         ret
  628.  
  629. .packets_rx:
  630.         add     eax, ARP_PACKETS_RX
  631.         mov     eax, [eax]
  632.         ret
  633.  
  634. .entries:
  635.         mov     eax, [NumARP]
  636.         ret
  637.  
  638. .read:
  639.         cmp     ecx, [NumARP]
  640.         jge     .error
  641.         ; edi = pointer to buffer
  642.         ; ecx = # entry
  643.         imul    ecx, ARP_ENTRY.size
  644.         add     ecx, ARPTable
  645.         mov     esi, ecx
  646.         mov     ecx, ARP_ENTRY.size/2
  647.         rep     movsw
  648.  
  649.         xor     eax, eax
  650.         ret
  651.  
  652. .write:
  653.         ; esi = pointer to buffer
  654.         sub     esp, ARP_ENTRY.size
  655.         mov     edi, esp
  656.         mov     ecx, ARP_ENTRY.size/2
  657.         rep     movsw
  658.         call    ARP_add_entry        ;out: eax = entry number, -1 on error
  659.         ret
  660.  
  661. .remove:
  662.         ; ecx = # entry
  663.         mov     esi, ecx
  664.         call    ARP_del_entry
  665.         ret
  666.  
  667.