Subversion Repositories Kolibri OS

Rev

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

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