Subversion Repositories Kolibri OS

Rev

Rev 3545 | Rev 3600 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  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.  
  180.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: got packet from %u.%u.%u.%u through device %u\n",\
  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.  
  197.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: It's a reply\n"
  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.  
  211.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: no matching entry found\n"
  212.         jmp     .exit
  213.  
  214.   .gotit:
  215.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: found matching entry\n"
  216.  
  217.         cmp     [esi + ARP_entry.TTL], ARP_STATIC_ENTRY         ; if it is a static entry, dont touch it
  218.         je      .exit
  219.  
  220.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: updating entry\n"
  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.  
  239.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: its a request\n"
  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.  
  280.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: Sending reply\n"
  281.  
  282.         call    [ebx + NET_DEVICE.transmit]
  283.         ret
  284.  
  285.   .collision:
  286.         inc     [ARP_CONFLICTS + 4*edi]
  287.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: IP address conflict detected!\n"
  288.  
  289.   .exit:
  290.         call    kernel_free
  291.         add     esp, 4                                          ; pop (balance stack)
  292.  
  293.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: exiting\n"
  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.  
  313.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_output_request: ip=%u.%u.%u.%u\n",\
  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.  
  347.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_output_request: device=%x\n", ebx
  348.  
  349.         push    edx ecx
  350.         call    [ebx + NET_DEVICE.transmit]
  351.         ret
  352.  
  353.   .exit:
  354.         add     esp, 4 + 4
  355.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_output_request: failed\n"
  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.  
  372.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_add_entry: "
  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
  403.         DEBUGF  DEBUG_NETWORK_VERBOSE, "entry=%u\n", eax
  404.  
  405.         ret
  406.  
  407.   .error:
  408.         DEBUGF  DEBUG_NETWORK_VERBOSE, "failed\n"
  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.  
  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", \
  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]
  441.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: success\n"
  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.  
  466.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: %u.%u", al, ah
  467.         rol     eax, 16
  468.         DEBUGF  DEBUG_NETWORK_VERBOSE, ".%u.%u\n", al, ah
  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:
  488.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: preparing for ARP request\n"
  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:
  538.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: found MAC\n"
  539.         movzx   eax, word[esi + ARP_entry.MAC]
  540.         mov     ebx, dword[esi + ARP_entry.MAC + 2]
  541.         ret
  542.  
  543.   .full:
  544.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: table is full!\n"
  545.         add     esp, 8
  546.   .give_up:
  547.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: entry has no valid mapping!\n"
  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.  
  646.