Subversion Repositories Kolibri OS

Rev

Rev 1257 | Blame | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2009. 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: 1258 $
  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, [ETH_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.         cmp     edi, -1
  253.         je      .exit
  254.  
  255.         mov     ecx, eax
  256.  
  257.         mov     [edi + ARP_Packet.HardwareType], 0x0100 ;Ethernet
  258.         mov     [edi + ARP_Packet.ProtocolType], 0x0008 ;IP
  259.         mov     [edi + ARP_Packet.HardwareSize], 6   ;MAC-addr length
  260.         mov     [edi + ARP_Packet.ProtocolSize], 4   ;IP-addr length
  261.         mov     [edi + ARP_Packet.Opcode], ARP_REQ_OPCODE      ;Request
  262.  
  263.         add     edi, ARP_Packet.SenderMAC                       ; sendermac
  264.         lea     esi, [ebx + ETH_DEVICE.mac]                     ;
  265.         movsw                                                   ;
  266.         movsd                                                   ;
  267.         pop     eax                                             ;
  268.         stosd                                                   ;
  269.         mov     eax, -1                                         ; destmac
  270.         stosd                                                   ;
  271.         stosw                                                   ;
  272.         pop     eax
  273.         stosd                                                   ;
  274.  
  275.         DEBUGF 1,"ARP Packet for device %x created successfully\n", ebx
  276.  
  277.         push    edx ecx
  278.         jmp     ETH_sender
  279.  
  280.   .exit:
  281.         add     esp, 8
  282.         DEBUGF 1,"Create ARP Packet - failed\n"
  283.         mov     eax, -1
  284.         ret
  285.  
  286.  
  287.  
  288. ;---------------------------------------------------------------------------
  289. ;
  290. ; ARP_decrease_entry_ttls
  291. ;
  292. ; IN: /
  293. ; OUT: /
  294. ;
  295. ;---------------------------------------------------------------------------
  296. align 4
  297. ARP_decrease_entry_ttls:
  298.  
  299.         mov     ecx, [NumARP]
  300.         test    ecx, ecx
  301.         jz      .exit
  302.  
  303.         mov     ebx, ARPTable
  304.  
  305. .timer_loop:
  306.  
  307.         cmp     [ebx + ARP_ENTRY.TTL], 0xFFFF
  308.         je      .timer_loop_end  ;if TTL==0xFFFF then it's static entry
  309.  
  310.         cmp     [ebx + ARP_ENTRY.TTL], 0
  311.         jnz     .timer_loop_end_with_dec  ;if TTL!=0
  312.  
  313.         ; Ok, TTL is 0
  314.         ;if Status==AWAITING_RESPONSE and TTL==0
  315.         ;then we have to change it to ARP_RESPONSE_TIMEOUT
  316.         cmp     [ebx + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE
  317.         jne     @f
  318.  
  319.         mov     [ebx + ARP_ENTRY.Status], ARP_RESPONSE_TIMEOUT
  320.         mov     [ebx + ARP_ENTRY.TTL], word 0x000A   ;10 sec
  321.         jmp     .timer_loop_end
  322.  
  323.   @@:
  324.         ;if TTL==0 and Status==VALID_MAPPING, we have to delete it
  325.         ;if TTL==0 and Status==RESPONSE_TIMEOUT, delete too
  326.         mov     esi, [NumARP]
  327.         sub     esi, ecx          ;esi=index of entry, will be deleted
  328.  
  329.         push    ebx ecx
  330.         call    ARP_del_entry
  331.         pop     ecx ebx
  332.  
  333.         jmp     .timer_loop_end
  334.  
  335.  
  336. .timer_loop_end_with_dec:
  337.  
  338.         dec     [ebx + ARP_ENTRY.TTL]  ;decrease TTL
  339.  
  340. .timer_loop_end:
  341.  
  342.         add     ebx, ARP_ENTRY.size
  343.         loop    .timer_loop
  344.  
  345. .exit:
  346.  
  347.         ret
  348.  
  349. ;-----------------------------------------------------------------
  350. ;
  351. ; ARP_add_entry (or update)
  352. ;
  353. ; IN: arp entry in stack: esp     .IP
  354. ;                         esp+4   .MAC
  355. ;                         esp+10  .Status
  356. ;                         esp+12  .TTL
  357. ;                         esp+14
  358. ;
  359. ; OUT: eax = entry #, -1 on error
  360. ;
  361. ;-----------------------------------------------------------------   ; TODO: use a mutex
  362. align 4
  363. ARP_add_entry:
  364.  
  365.         DEBUGF 1,"ARP add entry: "
  366.  
  367.         mov     ecx, [NumARP]
  368.         test    ecx, ecx
  369.         jz      .add
  370.  
  371.         mov     eax, dword[esp + 4 + ARP_ENTRY.MAC]
  372.         mov     bx , word[esp + 4 + ARP_ENTRY.MAC + 4]
  373.         mov     esi, ARPTable
  374.  
  375. .loop:
  376.         cmp     dword [esi + ARP_ENTRY.MAC], eax
  377.         jne     .maybe_next
  378.         cmp     word [esi + ARP_ENTRY.MAC + 4], bx
  379.         jne     .maybe_next
  380.  
  381.         cmp     dword[esi + ARP_ENTRY.TTL], 0xFFFF ; static entry
  382.         jne     .notstatic
  383.         cmp     dword[esp + 4 + ARP_ENTRY.TTL], 0xFFFF
  384.         jne     .error
  385. .notstatic:
  386.  
  387.         mov     ebx, [NumARP]
  388.         xchg    ebx, ecx
  389.         sub     ecx, ebx
  390.         jmp     .add
  391.  
  392. .maybe_next:
  393.         add     esi, ARP_ENTRY.size
  394.         loop    .loop
  395.  
  396.         mov     ecx, [NumARP]
  397.         cmp     ecx, ARP_TABLE_SIZE
  398.         jge     .error
  399.  
  400. .add:
  401.         push    ecx
  402.         imul    ecx, ARP_ENTRY.size
  403.         lea     edi, [ecx + ARPTable]
  404.         lea     esi, [esp + 8]
  405.         mov     ecx, ARP_ENTRY.size/2
  406.         repz    movsw
  407.  
  408.         inc     [NumARP]
  409.         pop     eax
  410.         DEBUGF 1,"New entry created: %u\n", eax
  411. .exit:
  412.         DEBUGF 1,"Exiting\n"
  413.         ret     ARP_ENTRY.size
  414.  
  415. .error:
  416.  
  417.         DEBUGF 1,"error! \n"
  418.  
  419.         mov     eax, -1
  420.         jmp     .exit
  421.  
  422.  
  423. ;-----------------------------------------------------------------
  424. ;
  425. ; ARP_del_entry
  426. ;
  427. ; IN: entry # in esi
  428. ; OUT: /
  429. ;
  430. ;-----------------------------------------------------------------
  431. align 4
  432. ARP_del_entry:
  433.  
  434.         DEBUGF 1,"ARP del entry %u, total entrys: %u\n", esi, [NumARP]
  435.  
  436.         cmp     esi, [NumARP]
  437.         jge     .error
  438.  
  439.         DEBUGF 1,"deleting the entry..\n"
  440.  
  441.         imul    esi, ARP_ENTRY.size
  442.  
  443.         mov     ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY.size
  444.         sub     ecx, esi
  445.  
  446.         lea     edi, [ebx + esi]            ;edi=ptr to entry that should be deleted
  447.         lea     esi, [edi + ARP_ENTRY.size] ;esi=ptr to next entry
  448.  
  449.         shr     ecx,1      ;ecx/2 => ARP_ENTRY_SIZE MUST BE EVEN NUMBER!
  450.         rep     movsw
  451.  
  452.         dec     [NumARP] ;decrease arp-entries counter
  453. .error:
  454.         ret
  455.  
  456.  
  457.  
  458.  
  459. ;-----------------------------------------------------------------
  460. ;
  461. ; ARP_Handler:
  462. ;
  463. ;  This function handles ARP protocol over ethernet
  464. ;  (other protocols may follow in the future)
  465. ;
  466. ;  IN:  Pointer to buffer in [esp]
  467. ;       size of buffer in [esp+4]
  468. ;       packet size (without ethernet header) in ecx
  469. ;  OUT: /
  470. ;
  471. ;-----------------------------------------------------------------
  472. align 4
  473. ARP_handler:
  474.  
  475.         DEBUGF  1,"ARP_Handler - start\n"
  476.         cmp     ecx, 28
  477.         jl      .exit
  478.  
  479.         cmp     word [edx + ARP_Packet.Opcode], ARP_REP_OPCODE  ; Is this a reply packet?
  480.         jne     .maybe_request
  481.  
  482.         DEBUGF  1,"ARP_Handler - it's a reply packet from %u.%u.%u.%u\n",\
  483.         [edx + ARP_Packet.SenderIP]:1,[edx + ARP_Packet.SenderIP+1]:1,[edx + ARP_Packet.SenderIP+2]:1,[edx + ARP_Packet.SenderIP+3]:1,
  484.  
  485.         mov     ecx, [NumARP]
  486.         test    ecx, ecx
  487.         jz      .exit
  488.  
  489.         mov     eax, [edx + ARP_Packet.SenderIP]
  490.         mov     esi, ARPTable+ARP_ENTRY.IP
  491.  
  492.   .loop:
  493.         cmp     [esi], eax
  494.         je      .gotit
  495.         add     esi, ARP_ENTRY.size
  496.         loop    .loop
  497.  
  498.         jmp     .exit
  499.  
  500.   .gotit:
  501.  
  502.         DEBUGF  1,"ARP_Handler - found matching entry\n"
  503.  
  504.         cmp     [esi+ARP_ENTRY.Status], 0x0300   ;if it is a static entry, dont touch it
  505.         je      .exit
  506.  
  507.         DEBUGF  1,"ARP_Handler - updating entry\n"
  508.  
  509.         mov     [esi+ARP_ENTRY.Status], ARP_VALID_MAPPING
  510.         mov     [esi+ARP_ENTRY.TTL], ARP_ENTRY_TTL
  511.  
  512.         mov     eax, dword [edx + ARP_Packet.SenderMAC]
  513.         mov     dword [esi+ARP_ENTRY.MAC], eax
  514.         mov     ax , word [edx + ARP_Packet.SenderMAC + 4]
  515.         mov     word [esi+ARP_ENTRY.MAC+4], ax
  516.  
  517.         jmp     .exit
  518.  
  519.  
  520. ;------
  521.  
  522.  
  523.   .maybe_request:
  524.         cmp     word [edx + ARP_Packet.Opcode], ARP_REQ_OPCODE  ; Is this a request packet?
  525.         jne     .exit
  526.  
  527.         call    ETH_struc2dev
  528.         DEBUGF  1,"ARP Request packet through device: %u\n", edi
  529.         inc     [ARP_PACKETS_RX+4*edi]
  530.         cmp     edi, -1
  531.         jz      .exit
  532.  
  533.         mov     eax, edi
  534.         shl     eax, 2
  535.         add     eax, IP_LIST
  536.         mov     eax, [eax]
  537.         cmp     eax, [edx + ARP_Packet.TargetIP]                ; Is it looking for my IP address?
  538.         jnz     .exit
  539.         push    eax
  540.         push    edi
  541.  
  542. ; OK, it is a request for one of our MAC addresses. Build the frame and send it
  543. ; We can reuse the buffer.  (faster then using ARP_create_packet)
  544.  
  545.         cld
  546.         lea     esi, [edx + ARP_Packet.SenderMAC]
  547.         lea     edi, [edx + ARP_Packet.TargetMAC]
  548.         movsd                                                   ; Move Sender Mac to Dest MAC
  549.         movsw                                                   ;
  550.         movsd                                                   ; Move sender IP to Dest IP
  551.  
  552.         pop     esi
  553.         mov     esi, [ETH_DRV_LIST + 4*esi]
  554.         lea     esi, [esi + ETH_DEVICE.mac]
  555.         lea     edi, [edx + ARP_Packet.SenderMAC]
  556.         movsd                                                   ; Copy MAC address from in MAC_LIST
  557.         movsw                                                   ;
  558.         pop     eax
  559.         stosd                                                   ; Write our IP
  560.  
  561.         mov     word [edx + ARP_Packet.Opcode], ARP_REP_OPCODE
  562.  
  563. ; Now, Fill in ETHERNET header
  564.  
  565.         mov     edi, [esp]
  566.         lea     esi, [edx + ARP_Packet.TargetMAC]
  567.         movsd
  568.         movsw
  569.         lea     esi, [edx + ARP_Packet.SenderMAC]
  570.         movsd
  571.         movsw
  572. ;        mov     ax , ETHER_ARP
  573. ;        stosw
  574.  
  575.         DEBUGF  1,"ARP_Handler - Sending reply \n"
  576.  
  577.         jmp     ETH_sender                                      ; And send it!
  578.  
  579.      .exit:
  580.         call    kernel_free
  581.         add     esp, 4                                          ; pop (balance stack)
  582.  
  583.         DEBUGF 1,"ARP_Handler - exiting\n"
  584.         ret
  585.  
  586.  
  587.  
  588.  
  589. ;-----------------------------------------------------------------
  590. ;
  591. ; ARP_API
  592. ;
  593. ; This function is called by system function 75
  594. ;
  595. ; IN:  subfunction number in bl
  596. ;      device number in bh
  597. ;      ecx, edx, .. depends on subfunction
  598. ;
  599. ; OUT:  ?
  600. ;
  601. ;-----------------------------------------------------------------
  602. align 4
  603. ARP_API:
  604.  
  605.         movzx   eax, bh
  606.         shl     eax, 2
  607.  
  608.         test    bl, bl
  609.         jz      .packets_tx     ; 0
  610.         dec     bl
  611.         jz      .packets_rx     ; 1
  612.         dec     bl
  613.         jz      .entries        ; 2
  614.         dec     bl
  615.         jz      .read           ; 3
  616.         dec     bl
  617.         jz      .write          ; 4
  618.         dec     bl
  619.         jz      .remove         ; 5
  620.         dec     bl
  621.  
  622. .error:
  623.         mov     eax, -1
  624.         ret
  625.  
  626. .packets_tx:
  627.         add     eax, ARP_PACKETS_TX
  628.         mov     eax, [eax]
  629.         ret
  630.  
  631. .packets_rx:
  632.         add     eax, ARP_PACKETS_RX
  633.         mov     eax, [eax]
  634.         ret
  635.  
  636. .entries:
  637.         mov     eax, [NumARP]
  638.         ret
  639.  
  640. .read:
  641.         cmp     ecx, [NumARP]
  642.         jge     .error
  643.         ; edi = pointer to buffer
  644.         ; ecx = # entry
  645.         imul    ecx, ARP_ENTRY.size
  646.         add     ecx, ARPTable
  647.         mov     esi, ecx
  648.         mov     ecx, ARP_ENTRY.size/2
  649.         rep     movsw
  650.  
  651.         xor     eax, eax
  652.         ret
  653.  
  654. .write:
  655.         ; esi = pointer to buffer
  656.         sub     esp, ARP_ENTRY.size
  657.         mov     edi, esp
  658.         mov     ecx, ARP_ENTRY.size/2
  659.         rep     movsw
  660.         call    ARP_add_entry        ;out: eax = entry number, -1 on error
  661.         ret
  662.  
  663. .remove:
  664.         ; ecx = # entry
  665.         mov     esi, ecx
  666.         call    ARP_del_entry
  667.         ret
  668.  
  669.