Subversion Repositories Kolibri OS

Rev

Rev 3589 | Rev 3725 | 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.  
  62.         ARP_table       rb NET_DEVICES_MAX*(ARP_TABLE_SIZE * sizeof.ARP_entry)
  63.  
  64.         ARP_entries_num rd NET_DEVICES_MAX
  65.         ARP_PACKETS_TX  rd NET_DEVICES_MAX
  66.         ARP_PACKETS_RX  rd NET_DEVICES_MAX
  67.         ARP_CONFLICTS   rd NET_DEVICES_MAX
  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     edi, ARP_entries_num
  85.         mov     ecx, 4*NET_DEVICES_MAX
  86.         rep     stosd
  87.  
  88. }
  89.  
  90. ;---------------------------------------------------------------------------
  91. ;
  92. ; ARP_decrease_entry_ttls
  93. ;
  94. ;---------------------------------------------------------------------------
  95.  
  96. macro ARP_decrease_entry_ttls {
  97.  
  98. local   .loop
  99. local   .exit
  100.  
  101. ; The TTL field is decremented every second, and is deleted when it reaches 0.
  102. ; It is refreshed every time a packet is received.
  103. ; If the TTL field is 0xFFFF it is a static entry and is never deleted.
  104. ; The status field can be the following values:
  105. ; 0x0000  entry not used
  106. ; 0x0001  entry holds a valid mapping
  107. ; 0x0002  entry contains an IP address, awaiting ARP response
  108. ; 0x0003  No response received to ARP request.
  109. ; The last status value is provided to allow the network layer to delete
  110. ; a packet that is queued awaiting an ARP response
  111.  
  112.         xor     edi, edi
  113.   .loop_outer:
  114.         mov     ecx, [ARP_entries_num + 4*edi]
  115.         test    ecx, ecx
  116.         jz      .exit
  117.  
  118.         mov     esi, (ARP_TABLE_SIZE * sizeof.ARP_entry)
  119.         imul    esi, edi
  120.         add     esi, ARP_table
  121.   .loop:
  122.         cmp     [esi + ARP_entry.TTL], ARP_STATIC_ENTRY
  123.         je      .next
  124.  
  125.         dec     [esi + ARP_entry.TTL]
  126.         jz      .time_out
  127.  
  128.   .next:
  129.         add     esi, sizeof.ARP_entry
  130.         dec     ecx
  131.         jnz     .loop
  132.         jmp     .exit
  133.  
  134.   .time_out:
  135.         cmp     [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE
  136.         je      .response_timeout
  137.  
  138.         push    esi edi ecx
  139.         call    ARP_del_entry
  140.         pop     ecx edi esi
  141.  
  142.         jmp     .next
  143.  
  144.   .response_timeout:
  145.         mov     [esi + ARP_entry.Status], ARP_RESPONSE_TIMEOUT
  146.         mov     [esi + ARP_entry.TTL], 10
  147.  
  148.         jmp     .next
  149.  
  150.   .exit:
  151.         inc     edi
  152.         cmp     edi, NET_DEVICES_MAX
  153.         jb      .loop_outer
  154.  
  155. }
  156.  
  157.  
  158. ;-----------------------------------------------------------------
  159. ;
  160. ; ARP_input
  161. ;
  162. ;  IN:  Pointer to buffer in [esp]
  163. ;       size of buffer in [esp+4]
  164. ;       packet size (without ethernet header) in ecx
  165. ;       packet ptr in edx
  166. ;       device ptr in ebx
  167. ;  OUT: /
  168. ;
  169. ;-----------------------------------------------------------------
  170. align 4
  171. ARP_input:
  172.  
  173. ;-----------------------------------------
  174. ; Check validity and print some debug info
  175.  
  176.         cmp     ecx, sizeof.ARP_header
  177.         jb      .exit
  178.  
  179.         call    NET_ptr_to_num
  180.         cmp     edi, -1
  181.         jz      .exit
  182.  
  183.         inc     [ARP_PACKETS_RX + 4*edi]        ; update stats
  184.  
  185.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: got packet from %u.%u.%u.%u through device %u\n",\
  186.         [edx + ARP_header.SenderIP]:1, [edx + ARP_header.SenderIP + 1]:1,\
  187.         [edx + ARP_header.SenderIP + 2]:1, [edx + ARP_header.SenderIP + 3]:1, edi
  188.  
  189. ;------------------------------
  190. ; First, check for IP collision
  191.  
  192.         mov     eax, [edx + ARP_header.SenderIP]
  193.         cmp     eax, [IP_LIST + 4*edi]
  194.         je      .collision
  195.  
  196. ;---------------------
  197. ; Handle reply packets
  198.  
  199.         cmp     [edx + ARP_header.Opcode], ARP_REP_OPCODE
  200.         jne     .maybe_request
  201.  
  202.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: It's a reply\n"
  203.  
  204.         mov     ecx, [ARP_entries_num + 4*edi]
  205.         test    ecx, ecx
  206.         jz      .exit
  207.  
  208.         mov     esi, (ARP_TABLE_SIZE * sizeof.ARP_entry)
  209.         imul    esi, edi
  210.         add     esi, ARP_table
  211.   .loop:
  212.         cmp     [esi + ARP_entry.IP], eax
  213.         je      .gotit
  214.         add     esi, sizeof.ARP_entry
  215.         dec     ecx
  216.         jnz     .loop
  217.  
  218.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: no matching entry found\n"
  219.         jmp     .exit
  220.  
  221.   .gotit:
  222.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: found matching entry\n"
  223.  
  224.         cmp     [esi + ARP_entry.TTL], ARP_STATIC_ENTRY         ; if it is a static entry, dont touch it
  225.         je      .exit
  226.  
  227.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: updating entry\n"
  228.  
  229.         mov     [esi + ARP_entry.Status], ARP_VALID_MAPPING
  230.         mov     [esi + ARP_entry.TTL], ARP_ENTRY_TTL
  231.  
  232.         mov     eax, dword [edx + ARP_header.SenderMAC]
  233.         mov     dword [esi + ARP_entry.MAC], eax
  234.         mov     cx, word [edx + ARP_header.SenderMAC + 4]
  235.         mov     word [esi + ARP_entry.MAC + 4], cx
  236.  
  237.         jmp     .exit
  238.  
  239. ;-----------------------
  240. ; Handle request packets
  241.  
  242.   .maybe_request:
  243.         cmp     [edx + ARP_header.Opcode], ARP_REQ_OPCODE
  244.         jne     .exit
  245.  
  246.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: its a request\n"
  247.  
  248.         mov     eax, [IP_LIST + 4*edi]
  249.         cmp     eax, [edx + ARP_header.TargetIP]                ; Is it looking for my IP address?
  250.         jne     .exit
  251.  
  252.         push    eax
  253.         push    edi
  254.  
  255. ; OK, it is a request for one of our MAC addresses.
  256. ; Build the frame and send it. We can reuse the buffer.  (faster then using ARP_create_packet)
  257.  
  258.         lea     esi, [edx + ARP_header.SenderMAC]
  259.         lea     edi, [edx + ARP_header.TargetMAC]
  260.         movsd                                                   ; Move Sender Mac to Dest MAC
  261.         movsw                                                   ;
  262.         movsd                                                   ; Move sender IP to Dest IP
  263.  
  264.         pop     esi
  265.         mov     esi, [NET_DRV_LIST + 4*esi]
  266.         lea     esi, [esi + ETH_DEVICE.mac]
  267.         lea     edi, [edx + ARP_header.SenderMAC]
  268.         movsd                                                   ; Copy MAC address from in MAC_LIST
  269.         movsw                                                   ;
  270.         pop     eax
  271.         stosd                                                   ; Write our IP
  272.  
  273.         mov     [edx + ARP_header.Opcode], ARP_REP_OPCODE
  274.  
  275. ; Now, Fill in ETHERNET header
  276.  
  277.         mov     edi, [esp]
  278.         lea     esi, [edx + ARP_header.TargetMAC]
  279.         movsd
  280.         movsw
  281.         lea     esi, [edx + ARP_header.SenderMAC]
  282.         movsd
  283.         movsw
  284. ;        mov     ax , ETHER_ARP                                 ; It's already there, I'm sure of it!
  285. ;        stosw
  286.  
  287.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: Sending reply\n"
  288.  
  289.         call    [ebx + NET_DEVICE.transmit]
  290.         ret
  291.  
  292.   .collision:
  293.         inc     [ARP_CONFLICTS + 4*edi]
  294.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: IP address conflict detected!\n"
  295.  
  296.   .exit:
  297.         call    kernel_free
  298.         add     esp, 4                                          ; pop (balance stack)
  299.  
  300.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_input: exiting\n"
  301.         ret
  302.  
  303.  
  304. ;---------------------------------------------------------------------------
  305. ;
  306. ; ARP_output_request
  307. ;
  308. ; IN:   ebx = device ptr
  309. ;       eax = IP
  310. ; OUT: /
  311. ;       scratched: probably everything
  312. ;
  313. ;---------------------------------------------------------------------------
  314. align 4
  315. ARP_output_request:
  316.  
  317.         push    eax
  318.  
  319.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_output_request: ip=%u.%u.%u.%u device=0x%x\n",\
  320.         [esp]:1, [esp + 1]:1, [esp + 2]:1, [esp + 3]:1, ebx
  321.  
  322.         lea     eax, [ebx + ETH_DEVICE.mac]     ; local device mac
  323.         mov     edx, ETH_BROADCAST              ; broadcast mac
  324.         mov     ecx, sizeof.ARP_header
  325.         mov     di, ETHER_PROTO_ARP
  326.         call    ETH_output
  327.         jz      .exit
  328.  
  329.         mov     [edi + ARP_header.HardwareType], 0x0100         ; Ethernet
  330.         mov     [edi + ARP_header.ProtocolType], 0x0008         ; IP
  331.         mov     [edi + ARP_header.HardwareSize], 6              ; MAC-addr length
  332.         mov     [edi + ARP_header.ProtocolSize], 4              ; IP-addr length
  333.         mov     [edi + ARP_header.Opcode], ARP_REQ_OPCODE       ; Request
  334.  
  335.         add     edi, ARP_header.SenderMAC
  336.         lea     esi, [ebx + ETH_DEVICE.mac]     ; SenderMac
  337.         movsw                                   ;
  338.         movsd                                   ;
  339.  
  340. ;        mov     esi, [ebx + NET_DEVICE.number]
  341.         xor     esi, esi        ;;;; FIXME
  342.         inc     esi ;;;;;;;;;
  343.         inc     [ARP_PACKETS_TX + 4*esi]        ; assume we will succeed
  344.         lea     esi, [IP_LIST + 4*esi]          ; SenderIP
  345.         movsd
  346.  
  347.         mov     esi, ETH_BROADCAST              ; DestMac
  348.         movsw                                   ;
  349.         movsd                                   ;
  350.         popd    [edi]                           ; DestIP
  351.  
  352.         push    edx eax
  353.         call    [ebx + NET_DEVICE.transmit]
  354.         ret
  355.  
  356.   .exit:
  357.         add     esp, 4
  358.         DEBUGF  DEBUG_NETWORK_ERROR, "ARP_output_request: send failed\n"
  359.         ret
  360.  
  361.  
  362. ;-----------------------------------------------------------------
  363. ;
  364. ; ARP_add_entry (or update)
  365. ;
  366. ; IN:  esi = ptr to entry (can easily be made on the stack)
  367. ;      edi = device num
  368. ; OUT: eax = entry #, -1 on error
  369. ;      esi = ptr to newly created entry
  370. ;
  371. ;-----------------------------------------------------------------      ; TODO: use a mutex
  372. align 4
  373. ARP_add_entry:
  374.  
  375.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_add_entry: device=%u\n", edi
  376.  
  377.         mov     ecx, [ARP_entries_num + 4*edi]
  378.         cmp     ecx, ARP_TABLE_SIZE                                     ; list full ?
  379.         jae     .full
  380.  
  381. ; From this point on, we can only fail if IP has a static entry, or if table is corrupt.
  382.  
  383.         inc     [ARP_entries_num + 4*edi]                               ; assume we will succeed
  384.  
  385.         push    edi
  386.         xor     ecx, ecx
  387.         imul    edi, ARP_TABLE_SIZE*sizeof.ARP_entry
  388.         add     edi, ARP_table
  389.         mov     eax, [esi + ARP_entry.IP]
  390.   .loop:
  391.         cmp     [edi + ARP_entry.Status], ARP_NO_ENTRY                  ; is this slot empty?
  392.         je      .add
  393.  
  394.         cmp     [edi + ARP_entry.IP], eax                               ; if not, check if it doesnt collide
  395.         jne     .maybe_next
  396.  
  397.         cmp     [edi + ARP_entry.TTL], ARP_STATIC_ENTRY                 ; ok, its the same IP, update it if not static
  398.         jne     .add
  399.  
  400.         DEBUGF  DEBUG_NETWORK_ERROR, "ARP_add_entry: failed, IP already has a static entry\n"
  401.         jmp     .error
  402.  
  403.   .maybe_next:                                                          ; try the next slot
  404.         add     edi, sizeof.ARP_entry
  405.         inc     ecx
  406.         cmp     ecx, ARP_TABLE_SIZE
  407.         jb      .loop
  408.  
  409.   .add:
  410.         push    ecx
  411.         mov     ecx, sizeof.ARP_entry/2
  412.         rep     movsw
  413.         pop     ecx
  414.         lea     esi, [edi - sizeof.ARP_entry]
  415.         pop     edi
  416.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_add_entry: entry=%u\n", ecx
  417.  
  418.         ret
  419.  
  420.   .error:
  421.         pop     edi
  422.         dec     [ARP_entries_num + 4*edi]
  423.         DEBUGF  DEBUG_NETWORK_ERROR, "ARP_add_entry_failed\n"
  424.   .full:
  425.         mov     eax, -1
  426.         ret
  427.  
  428.  
  429. ;-----------------------------------------------------------------
  430. ;
  431. ; ARP_del_entry
  432. ;
  433. ; IN:   esi = ptr to arp entry
  434. ;       edi = device number
  435. ; OUT:  /
  436. ;
  437. ;-----------------------------------------------------------------
  438. align 4
  439. ARP_del_entry:
  440.  
  441.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: entry=%x entrys=%u\n", esi, [ARP_entries_num + 4*edi]
  442.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: IP=%u.%u.%u.%u\n", \
  443.         [esi + ARP_entry.IP]:1, [esi + ARP_entry.IP + 1]:1, [esi + ARP_entry.IP + 2]:1, [esi + ARP_entry.IP + 3]:1
  444.  
  445.         push    edi
  446.         imul    edi, (ARP_TABLE_SIZE) * sizeof.ARP_entry
  447.         lea     ecx, [ARP_table + (ARP_TABLE_SIZE - 1) * sizeof.ARP_entry + edi]
  448.         sub     ecx, esi
  449.         shr     ecx, 1
  450.  
  451. ; move all trailing entries, sizeof.ARP_entry bytes to left.
  452.         mov     edi, esi
  453.         add     esi, sizeof.ARP_entry
  454.         rep     movsw
  455.  
  456. ; now add an empty entry to the end (erasing previous one)
  457.         xor     eax, eax
  458.         mov     ecx, sizeof.ARP_entry/2
  459.         rep     stosw
  460.  
  461.         pop     edi
  462.         dec     [ARP_entries_num + 4*edi]
  463.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_del_entry: success\n"
  464.  
  465.         ret
  466.  
  467.  
  468.  
  469.  
  470.  
  471. ;-----------------------------------------------------------------
  472. ;
  473. ; ARP_IP_to_MAC
  474. ;
  475. ;  This function translates an IP address to a MAC address
  476. ;
  477. ;  IN:  eax = IPv4 address
  478. ;       edi = device number
  479. ;  OUT: eax = -1 on error, -2 means request send
  480. ;      else, ax = first two bytes of mac (high 16 bits of eax will be 0)
  481. ;       ebx = last four bytes of mac
  482. ;       edi = unchanged
  483. ;
  484. ;-----------------------------------------------------------------
  485. align 4
  486. ARP_IP_to_MAC:
  487.  
  488.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: %u.%u", al, ah
  489.         rol     eax, 16
  490.         DEBUGF  DEBUG_NETWORK_VERBOSE, ".%u.%u device: %u\n", al, ah, edi
  491.         rol     eax, 16
  492.  
  493.         cmp     eax, 0xffffffff
  494.         je      .broadcast
  495.  
  496. ;--------------------------------
  497. ; Try to find the IP in ARP_table
  498.  
  499.         mov     ecx, [ARP_entries_num + 4*edi]
  500.         test    ecx, ecx
  501.         jz      .not_in_list
  502.         mov     esi, edi
  503.         imul    esi, sizeof.ARP_entry * ARP_TABLE_SIZE
  504.         add     esi, ARP_table + ARP_entry.IP
  505.   .scan_loop:
  506.         cmp     [esi], eax
  507.         je      .found_it
  508.         add     esi, sizeof.ARP_entry
  509.         dec     ecx
  510.         jnz     .scan_loop
  511.  
  512.   .not_in_list:
  513.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: preparing for ARP request\n"
  514.  
  515.         push    eax edi                 ; save IP for ARP_output_request
  516. ; Now craft the ARP entry on the stack
  517.         pushw   ARP_REQUEST_TTL         ; TTL
  518.         pushw   ARP_AWAITING_RESPONSE   ; status
  519.         pushd   0                       ; mac
  520.         pushw   0
  521.         pushd   eax                     ; ip
  522.         mov     esi, esp
  523.  
  524. ; Add it to the list
  525.         call    ARP_add_entry
  526.  
  527. ; Delete the temporary entry
  528.         add     esp, sizeof.ARP_entry   ; clear the entry from stack
  529.  
  530. ; If we could not add it to the list, give up
  531.         cmp     eax, -1                 ; did ARP_add_entry fail?
  532.         je      .full
  533.  
  534. ;-----------------------------------------------
  535. ; At this point, we got an ARP entry in the list
  536.  
  537. ; Now send a request packet on the network
  538.         pop     edi eax                 ; IP in eax, device number in ebx, for ARP_output_request
  539.  
  540.         push    esi edi
  541.         mov     ebx, [NET_DRV_LIST + 4*edi]
  542.         call    ARP_output_request
  543.         pop     edi esi
  544.   .found_it:
  545.         cmp     [esi + ARP_entry.Status], ARP_VALID_MAPPING             ; Does it have a MAC assigned?
  546.         je      .valid
  547.  
  548. if ARP_BLOCK
  549.  
  550.         cmp     [esi + ARP_entry.Status], ARP_AWAITING_RESPONSE         ; Are we waiting for reply from remote end?
  551.         jne     .give_up
  552.         push    esi
  553.         mov     esi, 10                 ; wait 10 ms
  554.         call    delay_ms
  555.         pop     esi
  556.         jmp     .found_it               ; now check again
  557.  
  558. else
  559.  
  560.         jmp     .give_up
  561.  
  562. end if
  563.  
  564.   .valid:
  565.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: found MAC\n"
  566.         movzx   eax, word[esi + ARP_entry.MAC]
  567.         mov     ebx, dword[esi + ARP_entry.MAC + 2]
  568.         ret
  569.  
  570.   .full:
  571.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: table is full!\n"
  572.         add     esp, 8
  573.   .give_up:
  574.         DEBUGF  DEBUG_NETWORK_VERBOSE, "ARP_IP_to_MAC: entry has no valid mapping!\n"
  575.         mov     eax, -1
  576.         ret
  577.  
  578.   .broadcast:
  579.         mov     eax, 0x0000ffff
  580.         mov     ebx, 0xffffffff
  581.         ret
  582.  
  583.  
  584. ;-----------------------------------------------------------------
  585. ;
  586. ; ARP_API
  587. ;
  588. ; This function is called by system function 76
  589. ;
  590. ; IN:  subfunction number in bl
  591. ;      device number in bh
  592. ;      ecx, edx, .. depends on subfunction
  593. ;
  594. ; OUT:  ?
  595. ;
  596. ;-----------------------------------------------------------------
  597. align 4
  598. ARP_api:
  599.  
  600.         movzx   eax, bh
  601.         shl     eax, 2
  602.  
  603.         and     ebx, 0xff
  604.         cmp     ebx, .number
  605.         ja      .error
  606.         jmp     dword [.table + 4*ebx]
  607.  
  608.   .table:
  609.         dd      .packets_tx     ; 0
  610.         dd      .packets_rx     ; 1
  611.         dd      .entries        ; 2
  612.         dd      .read           ; 3
  613.         dd      .write          ; 4
  614.         dd      .remove         ; 5
  615.         dd      .send_announce  ; 6
  616.         dd      .conflicts      ; 7
  617.   .number = ($ - .table) / 4 - 1
  618.  
  619.   .error:
  620.         mov     eax, -1
  621.         ret
  622.  
  623.   .packets_tx:
  624.         mov     eax, [ARP_PACKETS_TX + eax]
  625.         ret
  626.  
  627.   .packets_rx:
  628.         mov     eax, [ARP_PACKETS_RX + eax]
  629.         ret
  630.  
  631.   .conflicts:
  632.         mov     eax, [ARP_CONFLICTS + eax]
  633.         ret
  634.  
  635.   .entries:
  636.         mov     eax, [ARP_entries_num + eax]
  637.         ret
  638.  
  639.   .read:
  640.         cmp     ecx, [ARP_entries_num + eax]
  641.         jae     .error
  642.         shr     eax, 2
  643.         imul    eax, sizeof.ARP_entry*ARP_TABLE_SIZE
  644.         add     eax, ARP_table
  645.         ; edi = pointer to buffer
  646.         ; ecx = # entry
  647.         imul    ecx, sizeof.ARP_entry
  648.         lea     esi, [eax + ecx]
  649.         mov     ecx, sizeof.ARP_entry/2
  650.         rep     movsw
  651.  
  652.         xor     eax, eax
  653.         ret
  654.  
  655.   .write:
  656.         ; esi = pointer to buffer
  657.         mov     edi, eax
  658.         shr     edi, 2
  659.         call    ARP_add_entry           ; out: eax = entry number, -1 on error
  660.         ret
  661.  
  662.   .remove:
  663.         ; ecx = # entry
  664.         cmp     ecx, [ARP_entries_num + eax]
  665.         jae     .error
  666.         imul    ecx, sizeof.ARP_entry
  667.         lea     esi, [ARP_table + ecx]
  668.         mov     edi, eax
  669.         shr     edi, 2
  670.         call    ARP_del_entry
  671.         ret
  672.  
  673.   .send_announce:
  674.         mov     ebx, [NET_DRV_LIST + eax]
  675.         mov     eax, [IP_LIST + eax]
  676.         call    ARP_output_request      ; now send a gratuitous ARP
  677.         ret
  678.  
  679.