Subversion Repositories Kolibri OS

Rev

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

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