Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2010. All rights reserved.    ;;
  4. ;; Distributed under terms of the GNU General Public License       ;;
  5. ;;                                                                 ;;
  6. ;;  IPv4.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: 1529 $
  20.  
  21. MAX_FRAGMENTS   equ 64
  22. MAX_IP          equ MAX_NET_DEVICES
  23. IP_MAX_INTERFACES   equ MAX_IP
  24.  
  25. struct  IPv4_Packet
  26.         .VersionAndIHL          db  ?  ; Version[0-3 bits] and IHL(header length)[4-7 bits]
  27.         .TypeOfService          db  ?  ; precedence [7-5] minimize delay [4], maximize throughput [3], maximize riliability [2] minimize momentary cost [1] and zero [0]
  28.         .TotalLength            dw  ?
  29.         .Identification         dw  ?
  30.         .FlagsAndFragmentOffset dw  ?  ; Flags[0-2] and FragmentOffset[3-15]
  31.         .TimeToLive             db  ?  ;
  32.         .Protocol               db  ?
  33.         .HeaderChecksum         dw  ?
  34.         .SourceAddress          dd  ?
  35.         .DestinationAddress     dd  ?
  36.         .DataOrOptional:
  37. ends
  38.  
  39. struct  FRAGMENT_slot
  40.         .ttl                    dw  ?  ; Time to live for this entry, 0 for empty slot's
  41.         .id                     dw  ?  ; Identification field from IP header
  42.         .SrcIP                  dd  ?  ; .. from IP header
  43.         .DstIP                  dd  ?  ; .. from IP header
  44.         .ptr                    dd  ?  ; Pointer to first packet
  45.         .size:
  46. ends
  47.  
  48. struct  FRAGMENT_entry                 ; This structure will replace the ethernet header in fragmented ip packets
  49.         .PrevPtr                dd  ?  ; Pointer to previous fragment entry  (-1 for first packet)
  50.         .NextPtr                dd  ?  ; Pointer to next fragment entry (-1 for last packet)
  51.         .Owner                  dd  ?  ; Pointer to structure of driver
  52.                                 rb  2  ; to match ethernet header size          ; TODO: fix this hack
  53.         .Data:                         ; Ip header begins here (we will need the IP header to re-construct the complete packet)
  54. ends
  55.  
  56.  
  57.  
  58.  
  59. macro IPv4_checksum ptr {
  60.  
  61. ; This is the fast procedure to create or check a IP header without options
  62. ; To create a new checksum, the checksum field must be set to 0 before computation
  63. ; To check an existing checksum, leave the checksum as is, and it will be 0 after this procedure, if it was correct
  64.  
  65.         push    ebx
  66.         xor     ebx, ebx
  67.         add     bl, [ptr+1]
  68.         adc     bh, [ptr+0]
  69.  
  70.         adc     bl, [ptr+3]
  71.         adc     bh, [ptr+2]
  72.  
  73.         adc     bl, [ptr+5]
  74.         adc     bh, [ptr+4]
  75.  
  76.         adc     bl, [ptr+7]
  77.         adc     bh, [ptr+6]
  78.  
  79.         adc     bl, [ptr+9]
  80.         adc     bh, [ptr+8]
  81.  
  82. ; we skip 11th and 12th byte, they are the checksum bytes and should be 0 for re-calculation
  83.  
  84.         adc     bl, [ptr+13]
  85.         adc     bh, [ptr+12]
  86.  
  87.         adc     bl, [ptr+15]
  88.         adc     bh, [ptr+14]
  89.  
  90.         adc     bl, [ptr+17]
  91.         adc     bh, [ptr+16]
  92.  
  93.         adc     bl, [ptr+19]
  94.         adc     bh, [ptr+18]
  95.  
  96.         adc     ebx, 0
  97.  
  98.         push    ecx
  99.         mov     ecx, ebx
  100.         shr     ecx, 16
  101.         and     ebx, 0xffff
  102.         add     ebx, ecx
  103.  
  104.         mov     ecx, ebx
  105.         shr     ecx, 16
  106.         add     ebx, ecx
  107.  
  108.         not     bx
  109.         jnz     .not_zero
  110.         dec     bx
  111.   .not_zero:
  112.         xchg    bl, bh
  113.         pop     ecx
  114.  
  115.         neg     word [ptr+10]           ; zero will stay zero so we just get the checksum
  116.         add     word [ptr+10], bx       ;  , else we will get (new checksum - old checksum) in the end, wich should be 0 :)
  117.         pop     ebx
  118.  
  119. }
  120.  
  121.  
  122.  
  123. align 4
  124. uglobal
  125.  
  126.         IP_LIST         rd  MAX_IP
  127.         SUBNET_LIST     rd  MAX_IP
  128.         DNS_LIST        rd  MAX_IP
  129.         GATEWAY_LIST    rd  MAX_IP
  130.  
  131.         IP_PACKETS_TX   rd  MAX_IP
  132.         IP_PACKETS_RX   rd  MAX_IP
  133.  
  134.         FRAGMENT_LIST   rb  MAX_FRAGMENTS*FRAGMENT_slot.size
  135. endg
  136.  
  137.  
  138. ;-----------------------------------------------------------------
  139. ;
  140. ; IPv4_init
  141. ;
  142. ;  This function resets all IP variables
  143. ;
  144. ;-----------------------------------------------------------------
  145. macro   IPv4_init {
  146.  
  147.         xor     eax, eax
  148.         mov     edi, IP_LIST
  149.         mov     ecx, 4*MAX_IP
  150.         rep     stosd
  151.  
  152.         mov     edi, FRAGMENT_LIST
  153.         mov     ecx, FRAGMENT_slot.size*MAX_FRAGMENTS/4 + 2*MAX_IP
  154.         rep     stosd
  155.  
  156. }
  157.  
  158.  
  159. ;-----------------------------------------------------------------
  160. ;
  161. ; Decrease TimeToLive of all fragment slots
  162. ;
  163. ;-----------------------------------------------------------------
  164. macro IPv4_decrease_fragment_ttls {
  165.  
  166. local   .loop
  167.  
  168.         mov     esi, FRAGMENT_LIST
  169.         mov     ecx, MAX_FRAGMENTS
  170.   .loop:
  171.         cmp     [esi + FRAGMENT_slot.ttl], 0
  172.         je      .try_next
  173.         dec     [esi + FRAGMENT_slot.ttl]
  174.         jnz     .try_next
  175.         DEBUGF 1,"Fragment slot timed-out!\n"
  176. ;;; TODO: clear all entry's of timed-out slot
  177.   .try_next:
  178.         add     esi, 4
  179.         loop    .loop
  180. }
  181.  
  182.  
  183.  
  184. ;-----------------------------------------------------------------
  185. ;
  186. ; IPv4_input:
  187. ;
  188. ;  Will check if IP Packet isnt damaged
  189. ;  and call appropriate handler. (TCP/UDP/ICMP/..)
  190. ;
  191. ;  It will also re-construct fragmented packets
  192. ;
  193. ;  IN:  Pointer to buffer in [esp]
  194. ;       size of buffer in [esp+4]
  195. ;       pointer to device struct in ebx
  196. ;       pointer to IP Packet data in edx
  197. ;  OUT: /
  198. ;
  199. ;-----------------------------------------------------------------
  200. align 4
  201. IPv4_input:      ; TODO: implement handler for IP options
  202.                  ; TODO2: add code for raw sockets
  203.  
  204.         DEBUGF  1,"IPv4_Handler, packet from: %u.%u.%u.%u ",\
  205.         [edx + IPv4_Packet.SourceAddress]:1,[edx + IPv4_Packet.SourceAddress + 1]:1,[edx + IPv4_Packet.SourceAddress + 2]:1,[edx + IPv4_Packet.SourceAddress + 3]:1
  206.         DEBUGF  1,"to: %u.%u.%u.%u\n",\
  207.         [edx + IPv4_Packet.DestinationAddress]:1,[edx + IPv4_Packet.DestinationAddress + 1]:1,[edx + IPv4_Packet.DestinationAddress + 2]:1,[edx + IPv4_Packet.DestinationAddress + 3]:1
  208.  
  209. ;-------------------------------------------
  210. ; Check if the packet still has time to live
  211.  
  212.         cmp     byte [edx + IPv4_Packet.TimeToLive], 0
  213.         je      .dump
  214.  
  215. ;--------------------------------------
  216. ; First, check if IP packet has options
  217.  
  218.         movzx   eax, [edx + IPv4_Packet.VersionAndIHL]
  219.         and     al , 0x0f                                       ; get IHL(header length)
  220.         cmp     al , 0x05                                       ; IHL!= 5*4(20 bytes)
  221.         jnz     .has_options
  222.  
  223. ;-------------------------------
  224. ; Now, re-calculate the checksum
  225.  
  226.         IPv4_checksum edx
  227.         jnz     .dump                                           ; if checksum isn't valid then dump packet
  228.  
  229.         DEBUGF  1,"IPv4 Checksum is correct\n"
  230.  
  231. ;-----------------------------------
  232. ; Check if destination IP is correct
  233.  
  234.         call    NET_ptr_to_num
  235.         shl     edi, 2
  236.  
  237.         ; check if it matches local ip
  238.  
  239.         mov     eax, dword[IP_LIST+edi]
  240.         cmp     [edx + IPv4_Packet.DestinationAddress], eax
  241.         je      .ip_ok
  242.  
  243.         ; check for broadcast
  244.  
  245.         mov     eax, dword[SUBNET_LIST+edi]
  246.         not     eax
  247.         or      eax, dword[IP_LIST+edi]
  248.         cmp     [edx + IPv4_Packet.DestinationAddress], eax
  249.         je      .ip_ok
  250.  
  251.         ; or a special broadcast
  252.  
  253.         cmp     [edx + IPv4_Packet.DestinationAddress], -1
  254.         je      .ip_ok
  255.  
  256.         ; maybe it's a multicast then
  257.  
  258.         mov     eax, [edx + IPv4_Packet.DestinationAddress]
  259.         and     eax, 0xff000000
  260. ;        cmp     eax, 224 shl 24
  261. ;        je      .ip_ok
  262.  
  263.         ; or a loopback address
  264.  
  265.         cmp     eax, 127 shl 24
  266.         je      .ip_ok
  267.  
  268.         ; or it's not meant for us..
  269.  
  270.         DEBUGF  2,"Destination address does not match!\n"
  271.         jmp     .dump
  272.  
  273. ;------------------------
  274. ; Now we can update stats
  275.  
  276.   .ip_ok:
  277.         inc     [IP_PACKETS_RX+edi]
  278.  
  279. ;----------------------------------
  280. ; Check if the packet is fragmented
  281.  
  282.         test    [edx + IPv4_Packet.FlagsAndFragmentOffset], 1 shl 5     ; Is 'more fragments' flag set ?
  283.         jnz     .has_fragments                                          ; If so, we definately have a fragmented packet
  284.  
  285.         test    [edx + IPv4_Packet.FlagsAndFragmentOffset], 0xff1f      ; If flag is not set, but there is a fragment offset, the packet is last in series of fragmented packets
  286.         jnz     .is_last_fragment
  287.  
  288. ;-------------------------------------------------------------------
  289. ; No, it's just a regular IP packet, pass it to the higher protocols
  290.  
  291.   .handle_it:                                                   ; We reach here if packet hasnt been fragmented, or when it already has been re-constructed
  292.         movzx   eax, byte [edx + IPv4_Packet.VersionAndIHL]     ; Calculate Header length by using IHL field
  293.         and     eax, 0x0000000f                                 ;
  294.         shl     eax, 2                                          ;
  295.         movzx   ecx, word [edx + IPv4_Packet.TotalLength]       ; Calculate length of encapsulated Packet
  296.         xchg    cl , ch                                         ;
  297.         sub     ecx, eax                                        ;
  298.  
  299.         add     eax, edx
  300.         push    eax
  301.  
  302.         mov     esi, [edx + IPv4_Packet.SourceAddress]          ; These values might be of interest to the higher protocols
  303.         mov     edi, [edx + IPv4_Packet.DestinationAddress]     ;
  304.         mov     al , [edx + IPv4_Packet.Protocol]
  305.         pop     edx                                             ; Offset to data (tcp/udp/icmp/.. Packet)
  306.  
  307.         cmp     al , IP_PROTO_TCP
  308.         je      TCP_input
  309.  
  310.         cmp     al , IP_PROTO_UDP
  311.         je      UDP_input
  312.  
  313.         cmp     al , IP_PROTO_ICMP
  314.         je      ICMP_input
  315.  
  316.         DEBUGF  2,"unknown Internet protocol: %u\n", al
  317.  
  318.   .dump:
  319.         DEBUGF  2,"IP_Handler - dumping\n"
  320. ;        inc     [dumped_rx_count]
  321.         call    kernel_free
  322.         add     esp, 4                                          ; pop (balance stack)
  323.         ret
  324.  
  325.  
  326. ;---------------------------
  327. ; Fragmented packet handler
  328.  
  329.  
  330.   .has_fragments:
  331.         movzx   eax, [edx + IPv4_Packet.FlagsAndFragmentOffset]
  332.         xchg    al , ah
  333.         shl     ax , 3
  334.  
  335.         DEBUGF  1,"Fragmented packet, offset:%u, id:%x\n", ax, [edx + IPv4_Packet.Identification]:4
  336.  
  337.         test    ax , ax                                         ; Is this the first packet of the fragment?
  338.         jz      .is_first_fragment
  339.  
  340.  
  341. ;-------------------------------------------------------
  342. ; We have a fragmented IP packet, but it's not the first
  343.  
  344.         DEBUGF  1,"Middle fragmented packet received!\n"
  345.  
  346.         call    IPv4_find_fragment_slot
  347.         cmp     esi, -1
  348.         je      .dump
  349.  
  350.         mov     word [esi + FRAGMENT_slot.ttl], 15              ; Reset the ttl
  351.         mov     esi, [esi + FRAGMENT_slot.ptr]
  352.         or      edi, -1
  353.   .find_last_entry:                                             ; The following routine will try to find the last entry
  354.         cmp     edi, [esi + FRAGMENT_entry.PrevPtr]
  355.         jne     .destroy_slot                                   ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
  356.         mov     edi, esi
  357.         mov     esi, [esi + FRAGMENT_entry.NextPtr]
  358.         cmp     esi, -1
  359.         jne     .find_last_entry
  360.                                                                 ; We found the last entry (pointer is now in edi)
  361.                                                                 ; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure
  362.  
  363.         pop     eax                                             ; pointer to packet
  364.         mov     [edi + FRAGMENT_entry.NextPtr], eax             ; update pointer of previous entry to the new entry
  365.         mov     [eax + FRAGMENT_entry.NextPtr], -1
  366.         mov     [eax + FRAGMENT_entry.PrevPtr], edi
  367.         mov     [eax + FRAGMENT_entry.Owner], ebx
  368.  
  369.         add     esp, 4
  370.         ret
  371.  
  372.  
  373. ;------------------------------------
  374. ; We have received the first fragment
  375.  
  376.   .is_first_fragment:
  377.         DEBUGF  1,"First fragmented packet received!\n"
  378.                                                                 ; try to locate a free slot..
  379.         mov     ecx, MAX_FRAGMENTS
  380.         mov     esi, FRAGMENT_LIST
  381.   .find_free_slot:
  382.         cmp     word [esi + FRAGMENT_slot.ttl], 0
  383.         je      .found_free_slot
  384.         add     esi, FRAGMENT_slot.size
  385.         loop    .find_free_slot
  386.         jmp     .dump                                           ; If no free slot was found, dump the packet
  387.  
  388.   .found_free_slot:                                             ; We found a free slot, let's fill in the FRAGMENT_slot structure
  389.         mov     word [esi + FRAGMENT_slot.ttl], 15              ; RFC recommends 15 secs as ttl
  390.         mov     ax , word [edx + IPv4_Packet.Identification]
  391.         mov     word [esi + FRAGMENT_slot.id], ax
  392.         mov     eax, dword [edx + IPv4_Packet.SourceAddress]
  393.         mov     dword [esi + FRAGMENT_slot.SrcIP], eax
  394.         mov     eax, dword [edx + IPv4_Packet.DestinationAddress]
  395.         mov     dword [esi + FRAGMENT_slot.DstIP], eax
  396.         pop     eax
  397.         mov     dword [esi + FRAGMENT_slot.ptr], eax
  398.                                                                 ; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure
  399.         mov     [eax + FRAGMENT_entry.NextPtr], -1
  400.         mov     [eax + FRAGMENT_entry.PrevPtr], -1
  401.         mov     [eax + FRAGMENT_entry.Owner], ebx
  402.  
  403.         add     esp, 4                                          ; balance stack and exit
  404.         ret
  405.  
  406.  
  407. ;-----------------------------------
  408. ; We have received the last fragment
  409.  
  410.   .is_last_fragment:
  411.         DEBUGF  1,"Last fragmented packet received!\n"
  412.  
  413.         call    IPv4_find_fragment_slot
  414.         cmp     esi, -1
  415.         je      .dump
  416.  
  417.         mov     esi, [esi + FRAGMENT_slot.ptr]                  ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer
  418.         push    esi
  419.         xor     eax, eax
  420.         or      edi, -1
  421.  
  422.   .count_bytes:
  423.         cmp     [esi + FRAGMENT_entry.PrevPtr], edi
  424.         jne     .destroy_slot_pop                                                 ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
  425.         mov     cx, word [esi + FRAGMENT_entry.Data + IPv4_Packet.TotalLength]    ; Add total length
  426.         xchg    cl, ch
  427.         DEBUGF  1,"Packet size: %u\n", cx
  428.         add     ax, cx
  429.         movzx   cx, byte [esi + FRAGMENT_entry.Data + IPv4_Packet.VersionAndIHL]  ; Sub Header length
  430.         and     cx, 0x000F
  431.         shl     cx, 2
  432.         DEBUGF  1,"Header size: %u\n", cx
  433.         sub     ax, cx
  434.         mov     edi, esi
  435.         mov     esi, [esi + FRAGMENT_entry.NextPtr]
  436.         cmp     esi, -1
  437.         jne     .count_bytes
  438.  
  439.         mov     esi, [esp+4]
  440.         mov     [edi + FRAGMENT_entry.NextPtr], esi                            ; Add this packet to the chain, this simplifies the following code
  441.         mov     [esi + FRAGMENT_entry.NextPtr], -1
  442.         mov     [esi + FRAGMENT_entry.PrevPtr], edi
  443.         mov     [esi + FRAGMENT_entry.Owner], ebx
  444.  
  445.         mov     cx, [edx + IPv4_Packet.TotalLength]                            ; Note: This time we dont substract Header length
  446.         xchg    cl , ch
  447.         DEBUGF  1,"Packet size: %u\n", cx
  448.         add     ax , cx
  449.         DEBUGF  1,"Total Received data size: %u\n", eax
  450.  
  451.         push    eax
  452.         mov     ax , [edx + IPv4_Packet.FlagsAndFragmentOffset]
  453.         xchg    al , ah
  454.         shl     ax , 3
  455.         add     cx , ax
  456.         pop     eax
  457.         DEBUGF  1,"Total Fragment size: %u\n", ecx
  458.  
  459.         cmp     ax, cx
  460.         jne     .destroy_slot_pop
  461.  
  462.         push    eax
  463.         push    eax
  464.         call    kernel_alloc
  465.         test    eax, eax
  466.         je      .destroy_slot_pop                                                       ; If we dont have enough space to allocate the buffer, discard all packets in slot
  467.         mov     edx, [esp+4]                                                            ; Get pointer to first fragment entry back in edx
  468.  
  469.   .rebuild_packet_loop:
  470.         movzx   ecx, word [edx + FRAGMENT_entry.Data + IPv4_Packet.FlagsAndFragmentOffset]      ; Calculate the fragment offset
  471.         xchg    cl , ch                                                                         ;  intel byte order
  472.         shl     cx , 3                                                                          ;   multiply by 8 and clear first 3 bits
  473.         DEBUGF  1,"Fragment offset: %u\n", cx
  474.  
  475.         lea     edi, [eax + ecx]                                                                ; Notice that edi will be equal to eax for first fragment
  476.         movzx   ebx, byte [edx + FRAGMENT_entry.Data + IPv4_Packet.VersionAndIHL]               ; Find header size (in ebx) of fragment
  477.         and     bx , 0x000F                                                                     ;
  478.         shl     bx , 2                                                                          ;
  479.  
  480.         lea     esi, [edx + FRAGMENT_entry.Data]                                                ; Set esi to the correct begin of fragment
  481.         movzx   ecx, word [edx + FRAGMENT_entry.Data + IPv4_Packet.TotalLength]                 ; Calculate total length of fragment
  482.         xchg    cl, ch                                                                          ;  intel byte order
  483.  
  484.         cmp     edi, eax                                                                        ; Is this packet the first fragment ?
  485.         je      .first_fragment
  486.         sub     cx, bx                                                                          ; If not, dont copy the header
  487.         add     esi, ebx                                                                        ;
  488.   .first_fragment:
  489.  
  490.         push    cx                                                                              ; First copy dword-wise, then byte-wise
  491.         shr     cx, 2                                                                           ;
  492.         rep     movsd                                                                           ;
  493.         pop     cx                                                                              ;
  494.         and     cx, 3                                                                           ;
  495.         rep     movsb                                                                           ;
  496.  
  497.         push    eax
  498.         push    edx                                                                             ; Push pointer to fragment onto stack
  499.         mov     ebx, [edx + FRAGMENT_entry.Owner]                                               ; we need to remeber the owner, in case this is the last packet
  500.         mov     edx, [edx + FRAGMENT_entry.NextPtr]                                             ; Set edx to the next pointer
  501.         call    kernel_free                                                                     ; free the previous fragment buffer (this uses the value from stack)
  502.         pop     eax
  503.         cmp     edx, -1                                                                         ; Check if it is last fragment in chain
  504.         jne     .rebuild_packet_loop
  505.  
  506.         pop     ecx                                                                             ;
  507.         xchg    cl, ch
  508.         mov     edx, eax
  509.         mov     word [edx + IPv4_Packet.TotalLength], cx
  510.         add     esp, 8
  511.  
  512.         xchg    cl, ch              ;
  513.  
  514.         push    ecx                ;;;;
  515.         push    eax                ;;;;
  516.  
  517. ;        mov     esi, edx           ;  This prints the IP packet to the debug board (usefull when using serial output debug..)
  518. ;                                   ;
  519. ;        packet_to_debug
  520.  
  521.         jmp     .handle_it          ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
  522.  
  523.   .destroy_slot_pop:
  524.         add     esp, 4
  525.   .destroy_slot:
  526.         DEBUGF  1,"Destroy fragment slot!\n"
  527.         ; TODO!
  528.         jmp     .dump
  529.  
  530.  
  531.  
  532.  
  533. ;-----------------------------------
  534. ; The IP packet has some options
  535.  
  536.   .has_options:
  537.         jmp     .dump
  538.  
  539.  
  540.  
  541. ;-----------------------------------------------------------------
  542. ;
  543. ; find fragment slot
  544. ;
  545. ; IN: pointer to fragmented packet in edx
  546. ; OUT: pointer to slot in edi, -1 on error
  547. ;
  548. ;-----------------------------------------------------------------
  549. align 4
  550. IPv4_find_fragment_slot:
  551.  
  552. ;;; TODO: the RFC says we should check protocol number too
  553.  
  554.         push    eax ebx ecx edx
  555.         mov     ax , word [edx + IPv4_Packet.Identification]
  556.         mov     ecx, MAX_FRAGMENTS
  557.         mov     esi, FRAGMENT_LIST
  558.         mov     ebx, dword [edx + IPv4_Packet.SourceAddress]
  559.         mov     edx, dword [edx + IPv4_Packet.DestinationAddress]
  560.   .find_slot:
  561.         cmp     word [esi + FRAGMENT_slot.id], ax
  562.         jne     .try_next
  563.         cmp     dword [esi + FRAGMENT_slot.SrcIP], ebx
  564.         jne     .try_next
  565.         cmp     dword [esi + FRAGMENT_slot.DstIP], edx
  566.         je      .found_slot
  567.   .try_next:
  568.         add     esi, FRAGMENT_slot.size
  569.         loop    .find_slot
  570. ;        pop     edx ebx
  571.         or      esi, -1
  572. ;        ret
  573.  
  574.   .found_slot:
  575.         pop     edx ecx ebx eax
  576.         ret
  577.  
  578.  
  579. ;------------------------------------------------------------------
  580. ;
  581. ; IPv4_output
  582. ;
  583. ; IN: eax = dest ip
  584. ;     ebx = source ip
  585. ;     ecx = data length
  586. ;     dx  = fragment id
  587. ;     di  = TTL shl 8 + protocol
  588. ;
  589. ; OUT: eax = pointer to buffer start
  590. ;      ebx = pointer to device struct (needed for sending procedure)
  591. ;      ecx = unchanged (packet size of embedded data)
  592. ;      edx = size of complete buffer
  593. ;      edi = pointer to start of data (0 on error)
  594. ;
  595. ;------------------------------------------------------------------
  596. align 4
  597. IPv4_output:
  598.  
  599.         DEBUGF 1,"IPv4_create_packet: size=%u\n", ecx
  600.  
  601.         cmp     ecx, 65500              ; Max IPv4 packet size
  602.         jg      .too_large
  603.  
  604.         push    ecx eax ebx dx di
  605.  
  606.         call    ARP_IP_to_MAC
  607.  
  608.         test    eax, 0xffff0000         ; error bits
  609.         jnz     .arp_error
  610.  
  611.         push    ebx     ; push the mac
  612.         push    ax
  613.  
  614.         call    IPv4_dest_to_dev
  615.         inc     [IP_PACKETS_TX+edi]
  616.         mov     ebx, [NET_DRV_LIST+edi]
  617.         lea     eax, [ebx + ETH_DEVICE.mac]
  618.         mov     edx, esp
  619.         mov     ecx, [esp + 18]
  620.         add     ecx, IPv4_Packet.DataOrOptional
  621.         mov     di , ETHER_IPv4
  622.         call    ETH_output
  623.         jz      .error
  624.  
  625.         add     esp, 6  ; pop the mac
  626.  
  627.         mov     [edi + IPv4_Packet.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
  628.         mov     [edi + IPv4_Packet.TypeOfService], 0    ; nothing special, just plain ip packet
  629.         mov     [edi + IPv4_Packet.TotalLength], cx
  630.         rol     [edi + IPv4_Packet.TotalLength], 8      ; internet byte order
  631.         mov     [edi + IPv4_Packet.FlagsAndFragmentOffset], 0x0000
  632.         mov     [edi + IPv4_Packet.HeaderChecksum], 0
  633.         popw    word [edi + IPv4_Packet.TimeToLive]     ; ttl shl 8 + protocol
  634. ;               [edi + IPv4_Packet.Protocol]
  635.         popw    [edi + IPv4_Packet.Identification]      ; fragment id
  636.         popd    [edi + IPv4_Packet.SourceAddress]
  637.         popd    [edi + IPv4_Packet.DestinationAddress]
  638.  
  639.         pop     ecx
  640.  
  641.         IPv4_checksum edi
  642.         add     edi, IPv4_Packet.DataOrOptional
  643.         DEBUGF  1,"IPv4 Packet for device %x created successfully\n", ebx
  644.         ret
  645.  
  646.   .error:
  647.         add     esp, 6
  648.   .arp_error:
  649.         add     esp, 4+4+4+2+2
  650.   .too_large:
  651.         DEBUGF  1,"IPv4_create_packet: Failed\n"
  652.         sub     edi, edi
  653.         ret
  654.  
  655.  
  656. ;--------------------------------------------------------
  657. ;
  658. ;
  659. ; IN: dword [esp] = pointer to buffer containing ipv4 packet to be fragmented
  660. ;     dword [esp+4] = buffer size
  661. ;     esi = pointer to ip header in that buffer
  662. ;     ecx = max size of fragments
  663. ;
  664. ; OUT: /
  665. ;
  666. ;--------------------------------------------------------
  667.  
  668. align 4
  669. IPv4_fragment:
  670.  
  671.         DEBUGF 1,"IPv4_fragment\n"
  672.  
  673.         and     ecx, not 111b   ; align 4
  674.  
  675.         cmp     ecx, IPv4_Packet.DataOrOptional + 8     ; must be able to put at least 8 bytes
  676.         jl      .err2
  677.  
  678.         push    esi ecx
  679.         mov     eax, [esi + IPv4_Packet.DestinationAddress]
  680.         call    ARP_IP_to_MAC
  681.         pop     ecx esi
  682.         cmp     eax, -1
  683.         jz      .err2
  684.  
  685.         push    ebx
  686.         push    ax
  687.  
  688.         mov     ebx, [NET_DRV_LIST]
  689.         lea     eax, [ebx + ETH_DEVICE.mac]
  690.         push    eax
  691.  
  692.  
  693.         push    esi             ; ptr to ip header
  694.         sub     ecx, 20         ; substract header size
  695.         push    ecx             ; max data size
  696.         push    dword 0         ; offset
  697.  
  698.   .new_fragment:
  699.         DEBUGF 1,"Ipv4_fragment - new_fragmentn"
  700.  
  701.  
  702.         mov     eax, [esp + 3*4]
  703.         lea     ebx, [esp + 4*4]
  704.         mov     di , ETHER_IPv4
  705.         call    ETH_output
  706.  
  707.         cmp     edi, -1
  708.         jz      .err
  709.  
  710. ; copy header
  711.         mov     esi, [esp + 2*4]
  712.         mov     ecx, 5  ; 5 dwords: TODO: use IHL field of the header!
  713.         rep     movsd
  714.  
  715. ; copy data
  716.         mov     esi, [esp + 2*4]
  717.         add     esi, 20
  718.         add     esi, [esp]      ; offset
  719.  
  720.         mov     ecx, [esp + 1*4]
  721.         DEBUGF 1,"IPv4_fragment - copying data (%u bytes)\n", ecx
  722.         rep     movsb
  723.  
  724. ; now, correct header
  725.         mov     ecx, [esp + 1*4]
  726.         add     ecx, 20
  727.         xchg    cl, ch
  728.         mov     [edi + IPv4_Packet.TotalLength], cx
  729.  
  730.         mov     ecx, [esp]              ; offset
  731.         xchg    cl, ch
  732.  
  733. ;        cmp     dword[esp + 4*4], 0     ; last fragment?;<<<<<<
  734. ;        je      .last_fragment
  735.         or      cx, 1 shl 2             ; more fragments
  736. ;  .last_fragment:
  737.         mov     [edi + IPv4_Packet.FlagsAndFragmentOffset], cx
  738.  
  739.         mov     [edi + IPv4_Packet.HeaderChecksum], 0
  740.  
  741.         ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet
  742.         mov     ecx, [esp + 1*4]
  743.  
  744.         push    edx eax
  745.         IPv4_checksum edi
  746.  
  747.         call    [ebx + NET_DEVICE.transmit]
  748.         ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  749.  
  750.         mov     ecx,  [esp+4]
  751.         add     [esp], ecx
  752.  
  753.         mov     ecx, [esp+3*4+6+4]      ; ptr to begin of buff
  754.         add     ecx, [esp+3*4+6+4+4]    ; buff size
  755.         sub     ecx, [esp+2*4]          ; ptr to ip header
  756.         add     ecx, [esp]              ; offset
  757.  
  758.         DEBUGF 1,"Ipv4_fragment - bytes remaining: %u\n", ecx
  759.  
  760.         cmp     ecx, [esp+1*4]
  761.         jge     .new_fragment
  762.  
  763.         mov     [esp+4], ecx            ; set fragment size to remaining packet size
  764.         jmp     .new_fragment
  765.  
  766.       .err:
  767.         DEBUGF 1,"Ipv4_fragment - failed\n"
  768.       .done:
  769.         add     esp, 12 + 4 + 6
  770.       .err2:
  771.         DEBUGF 1,"Ipv4_fragment - dumping\n"
  772.         call    kernel_free
  773.         add     esp, 4
  774.  
  775.         ret
  776.  
  777.  
  778.  
  779. ;---------------------------------------------------------------------------
  780. ;
  781. ; IPv4_dest_to_dev
  782. ;
  783. ; IN:  eax = Destination IP
  784. ; OUT: edi = device id * 4
  785. ;
  786. ;---------------------------------------------------------------------------
  787. align 4
  788. IPv4_dest_to_dev:
  789.  
  790.         cmp     eax, 0xffffffff
  791.         je      .invalid
  792.  
  793.         xor     edi, edi
  794.         mov     ecx, MAX_IP
  795.  
  796.   .loop:
  797.         mov     ebx, [IP_LIST+edi]
  798.         and     ebx, [SUBNET_LIST+edi]
  799.         jz      .next
  800.  
  801.         mov     edx, eax
  802.         and     edx, [SUBNET_LIST+edi]
  803.  
  804.         cmp     ebx, edx
  805.         je      .found_it
  806.   .next:
  807.         add     edi, 4
  808.         loop    .loop
  809.  
  810.   .invalid:
  811.         xor     edi, edi                        ; if none found, use device 0 as default device
  812.  
  813.   .found_it:
  814.         DEBUGF  1,"IPv4_dest_to_dev: %u\n", edi
  815.  
  816.         ret
  817.  
  818.  
  819.  
  820. ;---------------------------------------------------------------------------
  821. ;
  822. ; IPv4_get_frgmnt_num
  823. ;
  824. ; IN: /
  825. ; OUT: fragment number in ax
  826. ;
  827. ;---------------------------------------------------------------------------
  828. align 4
  829. IPv4_get_frgmnt_num:
  830.         xor     ax, ax  ;;; TODO: replace this with real code
  831.  
  832.         ret
  833.  
  834.  
  835. ;---------------------------------------------------------------------------
  836. ;
  837. ; IPv4_API
  838. ;
  839. ; This function is called by system function 75
  840. ;
  841. ; IN:  subfunction number in bl
  842. ;      device number in bh
  843. ;      ecx, edx, .. depends on subfunction
  844. ;
  845. ; OUT:
  846. ;
  847. ;---------------------------------------------------------------------------
  848. align 4
  849. IPv4_API:
  850.  
  851.         movzx   eax, bh
  852.         shl     eax, 2
  853.  
  854.         test    bl, bl
  855.         jz      .packets_tx     ; 0
  856.         dec     bl
  857.         jz      .packets_rx     ; 1
  858.         dec     bl
  859.         jz      .read_ip        ; 2
  860.         dec     bl
  861.         jz      .write_ip       ; 3
  862.         dec     bl
  863.         jz      .read_dns       ; 4
  864.         dec     bl
  865.         jz      .write_dns      ; 5
  866.         dec     bl
  867.         jz      .read_subnet    ; 6
  868.         dec     bl
  869.         jz      .write_subnet   ; 7
  870.         dec     bl
  871.         jz      .read_gateway   ; 8
  872.         dec     bl
  873.         jz      .write_gateway  ; 9
  874.  
  875.   .error:
  876.         mov     eax, -1
  877.         ret
  878.  
  879.   .packets_tx:
  880.         add     eax, IP_PACKETS_TX
  881.         mov     eax, [eax]
  882.         ret
  883.  
  884.   .packets_rx:
  885.         add     eax, IP_PACKETS_RX
  886.         mov     eax, [eax]
  887.         ret
  888.  
  889.   .read_ip:
  890.         add     eax, IP_LIST
  891.         mov     eax, [eax]
  892.         ret
  893.  
  894.   .write_ip:
  895.         add     eax, IP_LIST
  896.         mov     [eax], ecx
  897.         xor     eax, eax
  898.         ret
  899.  
  900.   .read_dns:
  901.         add     eax, DNS_LIST
  902.         mov     eax, [eax]
  903.         ret
  904.  
  905.   .write_dns:
  906.         add     eax, DNS_LIST
  907.         mov     [eax], ecx
  908.         xor     eax, eax
  909.         ret
  910.  
  911.   .read_subnet:
  912.         add     eax, SUBNET_LIST
  913.         mov     eax, [eax]
  914.         ret
  915.  
  916.   .write_subnet:
  917.         add     eax, SUBNET_LIST
  918.         mov     [eax], ecx
  919.         xor     eax, eax
  920.         ret
  921.  
  922.   .read_gateway:
  923.         add     eax, GATEWAY_LIST
  924.         mov     eax, [eax]
  925.         ret
  926.  
  927.   .write_gateway:
  928.         add     eax, GATEWAY_LIST
  929.         mov     [eax], ecx
  930.         xor     eax, eax
  931.         ret