Subversion Repositories Kolibri OS

Rev

Rev 2553 | Blame | Last modification | View Log | Download | RSS feed

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