Subversion Repositories Kolibri OS

Rev

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