Subversion Repositories Kolibri OS

Rev

Rev 2614 | 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: 2621 $
  20.  
  21. MAX_FRAGMENTS           = 64
  22. MAX_IP                  = MAX_NET_DEVICES
  23. IP_MAX_INTERFACES       = 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 header in edx
  198. ;       size of IP packet in ecx
  199. ;  OUT: /
  200. ;
  201. ;-----------------------------------------------------------------
  202. align 4
  203. IPv4_input:      ; TODO: 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. ; Now, re-calculate the checksum
  218.  
  219.         IPv4_checksum edx
  220.         jnz     .dump                                           ; if checksum isn't valid then dump packet
  221.  
  222.         DEBUGF  1,"IPv4 Checksum is correct\n"
  223.  
  224. ;-----------------------------------
  225. ; Check if destination IP is correct
  226.  
  227.         call    NET_ptr_to_num
  228.         shl     edi, 2
  229.  
  230.         ; check if it matches local ip
  231.  
  232.         mov     eax, [IP_LIST+edi]
  233.         cmp     [edx + IPv4_header.DestinationAddress], eax
  234.         je      .ip_ok
  235.  
  236.         ; check for broadcast
  237.  
  238.         mov     eax, [SUBNET_LIST+edi]
  239.         not     eax
  240.         or      eax, [IP_LIST+edi]
  241.         cmp     [edx + IPv4_header.DestinationAddress], eax
  242.         je      .ip_ok
  243.  
  244.         ; or a special broadcast
  245.  
  246.         cmp     [edx + IPv4_header.DestinationAddress], -1
  247.         je      .ip_ok
  248.  
  249.         ; maybe it's a multicast then
  250.  
  251.         mov     eax, [edx + IPv4_header.DestinationAddress]
  252.         and     eax, 0xff000000
  253. ;        cmp     eax, 224 shl 24
  254. ;        je      .ip_ok
  255.  
  256.         ; or a loopback address
  257.  
  258.         cmp     eax, 127 shl 24
  259.         je      .ip_ok
  260.  
  261.         ; or it's not meant for us..
  262.  
  263.         DEBUGF  2,"Destination address does not match!\n"
  264.         jmp     .dump
  265.  
  266. ;------------------------
  267. ; Now we can update stats
  268.  
  269.   .ip_ok:
  270.         inc     [IP_PACKETS_RX+edi]
  271.  
  272. ;----------------------------------
  273. ; Check if the packet is fragmented
  274.  
  275.         test    [edx + IPv4_header.FlagsAndFragmentOffset], 1 shl 5     ; Is 'more fragments' flag set ?
  276.         jnz     .has_fragments                                          ; If so, we definately have a fragmented packet
  277.  
  278.         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
  279.         jnz     .is_last_fragment
  280.  
  281. ;-------------------------------------------------------------------
  282. ; No, it's just a regular IP packet, pass it to the higher protocols
  283.  
  284.   .handle_it:                                                   ; We reach here if packet hasnt been fragmented, or when it already has been re-constructed
  285.  
  286.         movzx   esi, [edx + IPv4_header.VersionAndIHL]          ; Calculate Header length by using IHL field
  287.         and     esi, 0x0000000f                                 ;
  288.         shl     esi, 2                                          ;
  289.  
  290.         movzx   ecx, [edx + IPv4_header.TotalLength]            ; Calculate length of encapsulated Packet
  291.         xchg    cl , ch                                         ;
  292.         sub     ecx, esi                                        ;
  293.  
  294.         lea     edi, [edx + IPv4_header.SourceAddress]          ; make edi ptr to source and dest IPv4 address
  295.         mov     al , [edx + IPv4_header.Protocol]
  296.         add     esi, edx                                        ; make esi ptr to data
  297.  
  298.         cmp     al, IP_PROTO_TCP
  299.         je      TCP_input
  300.  
  301.         cmp     al, IP_PROTO_UDP
  302.         je      UDP_input
  303.  
  304.         cmp     al, IP_PROTO_ICMP
  305.         je      ICMP_input
  306.  
  307.         DEBUGF  2,"unknown Internet protocol: %u\n", al
  308.  
  309.   .dump:
  310.         DEBUGF  2,"IP_Handler - dumping\n"
  311. ;        inc     [dumped_rx_count]
  312.         call    kernel_free
  313.         add     esp, 4                                          ; pop (balance stack)
  314.         ret
  315.  
  316.  
  317. ;---------------------------
  318. ; Fragmented packet handler
  319.  
  320.  
  321.   .has_fragments:
  322.         movzx   eax, [edx + IPv4_header.FlagsAndFragmentOffset]
  323.         xchg    al , ah
  324.         shl     ax , 3
  325.  
  326.         DEBUGF  1,"Fragmented packet, offset:%u, id:%x\n", ax, [edx + IPv4_header.Identification]:4
  327.  
  328.         test    ax , ax                                         ; Is this the first packet of the fragment?
  329.         jz      .is_first_fragment
  330.  
  331.  
  332. ;-------------------------------------------------------
  333. ; We have a fragmented IP packet, but it's not the first
  334.  
  335.         DEBUGF  1,"Middle fragmented packet received!\n"
  336.  
  337.         call    IPv4_find_fragment_slot
  338.         cmp     esi, -1
  339.         je      .dump
  340.  
  341.         mov     [esi + FRAGMENT_slot.ttl], 15                   ; Reset the ttl
  342.         mov     esi, [esi + FRAGMENT_slot.ptr]
  343.         or      edi, -1
  344.   .find_last_entry:                                             ; The following routine will try to find the last entry
  345.         cmp     edi, [esi + FRAGMENT_entry.PrevPtr]
  346.         jne     .destroy_slot                                   ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
  347.         mov     edi, esi
  348.         mov     esi, [esi + FRAGMENT_entry.NextPtr]
  349.         cmp     esi, -1
  350.         jne     .find_last_entry
  351.                                                                 ; We found the last entry (pointer is now in edi)
  352.                                                                 ; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure
  353.  
  354.         pop     eax                                             ; pointer to packet
  355.         mov     [edi + FRAGMENT_entry.NextPtr], eax             ; update pointer of previous entry to the new entry
  356.         mov     [eax + FRAGMENT_entry.NextPtr], -1
  357.         mov     [eax + FRAGMENT_entry.PrevPtr], edi
  358.         mov     [eax + FRAGMENT_entry.Owner], ebx
  359.  
  360.         add     esp, 4
  361.         ret
  362.  
  363.  
  364. ;------------------------------------
  365. ; We have received the first fragment
  366.  
  367.   .is_first_fragment:
  368.         DEBUGF  1,"First fragmented packet received!\n"
  369.                                                                 ; try to locate a free slot..
  370.         mov     ecx, MAX_FRAGMENTS
  371.         mov     esi, FRAGMENT_LIST
  372.   .find_free_slot:
  373.         cmp     word [esi + FRAGMENT_slot.ttl], 0
  374.         je      .found_free_slot
  375.         add     esi, sizeof.FRAGMENT_slot
  376.         loop    .find_free_slot
  377.         jmp     .dump                                           ; If no free slot was found, dump the packet
  378.  
  379.   .found_free_slot:                                             ; We found a free slot, let's fill in the FRAGMENT_slot structure
  380.         mov     [esi + FRAGMENT_slot.ttl], 15                   ; RFC recommends 15 secs as ttl
  381.         mov     ax , [edx + IPv4_header.Identification]
  382.         mov     [esi + FRAGMENT_slot.id], ax
  383.         mov     eax,[edx + IPv4_header.SourceAddress]
  384.         mov     [esi + FRAGMENT_slot.SrcIP], eax
  385.         mov     eax, [edx + IPv4_header.DestinationAddress]
  386.         mov     [esi + FRAGMENT_slot.DstIP], eax
  387.         pop     eax
  388.         mov     [esi + FRAGMENT_slot.ptr], eax
  389.                                                                 ; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure
  390.         mov     [eax + FRAGMENT_entry.NextPtr], -1
  391.         mov     [eax + FRAGMENT_entry.PrevPtr], -1
  392.         mov     [eax + FRAGMENT_entry.Owner], ebx
  393.  
  394.         add     esp, 4                                          ; balance stack and exit
  395.         ret
  396.  
  397.  
  398. ;-----------------------------------
  399. ; We have received the last fragment
  400.  
  401.   .is_last_fragment:
  402.         DEBUGF  1,"Last fragmented packet received!\n"
  403.  
  404.         call    IPv4_find_fragment_slot
  405.         cmp     esi, -1
  406.         je      .dump
  407.  
  408.         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
  409.         push    esi
  410.         xor     eax, eax
  411.         or      edi, -1
  412.  
  413.   .count_bytes:
  414.         cmp     [esi + FRAGMENT_entry.PrevPtr], edi
  415.         jne     .destroy_slot_pop                                               ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
  416.         mov     cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.TotalLength]       ; Add total length
  417.         xchg    cl, ch
  418.         DEBUGF  1,"Packet size: %u\n", cx
  419.         add     ax, cx
  420.         movzx   cx, [esi + sizeof.FRAGMENT_entry + IPv4_header.VersionAndIHL]     ; Sub Header length
  421.         and     cx, 0x000F
  422.         shl     cx, 2
  423.         DEBUGF  1,"Header size: %u\n", cx
  424.         sub     ax, cx
  425.         mov     edi, esi
  426.         mov     esi, [esi + FRAGMENT_entry.NextPtr]
  427.         cmp     esi, -1
  428.         jne     .count_bytes
  429.  
  430.         mov     esi, [esp+4]
  431.         mov     [edi + FRAGMENT_entry.NextPtr], esi                            ; Add this packet to the chain, this simplifies the following code
  432.         mov     [esi + FRAGMENT_entry.NextPtr], -1
  433.         mov     [esi + FRAGMENT_entry.PrevPtr], edi
  434.         mov     [esi + FRAGMENT_entry.Owner], ebx
  435.  
  436.         mov     cx, [edx + IPv4_header.TotalLength]                            ; Note: This time we dont substract Header length
  437.         xchg    cl , ch
  438.         DEBUGF  1,"Packet size: %u\n", cx
  439.         add     ax , cx
  440.         DEBUGF  1,"Total Received data size: %u\n", eax
  441.  
  442.         push    eax
  443.         mov     ax , [edx + IPv4_header.FlagsAndFragmentOffset]
  444.         xchg    al , ah
  445.         shl     ax , 3
  446.         add     cx , ax
  447.         pop     eax
  448.         DEBUGF  1,"Total Fragment size: %u\n", ecx
  449.  
  450.         cmp     ax, cx
  451.         jne     .destroy_slot_pop
  452.  
  453.         push    eax
  454.         push    eax
  455.         call    kernel_alloc
  456.         test    eax, eax
  457.         je      .destroy_slot_pop                                                       ; If we dont have enough space to allocate the buffer, discard all packets in slot
  458.         mov     edx, [esp+4]                                                            ; Get pointer to first fragment entry back in edx
  459.  
  460.   .rebuild_packet_loop:
  461.         movzx   ecx, [edx + sizeof.FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset]   ; Calculate the fragment offset
  462.         xchg    cl , ch                                                                 ;  intel byte order
  463.         shl     cx , 3                                                                  ;   multiply by 8 and clear first 3 bits
  464.         DEBUGF  1,"Fragment offset: %u\n", cx
  465.  
  466.         lea     edi, [eax + ecx]                                                        ; Notice that edi will be equal to eax for first fragment
  467.         movzx   ebx, [edx + sizeof.FRAGMENT_entry + IPv4_header.VersionAndIHL]            ; Find header size (in ebx) of fragment
  468.         and     bx , 0x000F                                                             ;
  469.         shl     bx , 2                                                                  ;
  470.  
  471.         lea     esi, [edx + sizeof.FRAGMENT_entry]                                        ; Set esi to the correct begin of fragment
  472.         movzx   ecx, [edx + sizeof.FRAGMENT_entry + IPv4_header.TotalLength]              ; Calculate total length of fragment
  473.         xchg    cl, ch                                                                  ;  intel byte order
  474.  
  475.         cmp     edi, eax                                                                ; Is this packet the first fragment ?
  476.         je      .first_fragment
  477.         sub     cx, bx                                                                  ; If not, dont copy the header
  478.         add     esi, ebx                                                                ;
  479.   .first_fragment:
  480.  
  481.         push    cx                                                                      ; First copy dword-wise, then byte-wise
  482.         shr     cx, 2                                                                   ;
  483.         rep     movsd                                                                   ;
  484.         pop     cx                                                                      ;
  485.         and     cx, 3                                                                   ;
  486.         rep     movsb                                                                   ;
  487.  
  488.         push    eax
  489.         push    edx                                                                     ; Push pointer to fragment onto stack
  490.         mov     ebx, [edx + FRAGMENT_entry.Owner]                                       ; we need to remeber the owner, in case this is the last packet
  491.         mov     edx, [edx + FRAGMENT_entry.NextPtr]                                     ; Set edx to the next pointer
  492.         call    kernel_free                                                             ; free the previous fragment buffer (this uses the value from stack)
  493.         pop     eax
  494.         cmp     edx, -1                                                                 ; Check if it is last fragment in chain
  495.         jne     .rebuild_packet_loop
  496.  
  497.         pop     ecx
  498.         xchg    cl, ch
  499.         mov     edx, eax
  500.         mov     [edx + IPv4_header.TotalLength], cx
  501.         add     esp, 8
  502.  
  503.         xchg    cl, ch              ;
  504.  
  505.         push    ecx                ;;;;
  506.         push    eax                ;;;;
  507.  
  508. ;        mov     esi, edx           ;  This prints the IP packet to the debug board (usefull when using serial output debug..)
  509. ;                                   ;
  510. ;        packet_to_debug
  511.  
  512.         jmp     .handle_it          ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
  513.  
  514.   .destroy_slot_pop:
  515.         add     esp, 4
  516.   .destroy_slot:
  517.         DEBUGF  1,"Destroy fragment slot!\n"
  518.         ; TODO!
  519.         jmp     .dump
  520.  
  521.  
  522.  
  523.  
  524.  
  525. ;-----------------------------------------------------------------
  526. ;
  527. ; find fragment slot
  528. ;
  529. ; IN: pointer to fragmented packet in edx
  530. ; OUT: pointer to slot in edi, -1 on error
  531. ;
  532. ;-----------------------------------------------------------------
  533. align 4
  534. IPv4_find_fragment_slot:
  535.  
  536. ;;; TODO: the RFC says we should check protocol number too
  537.  
  538.         push    eax ebx ecx edx
  539.         mov     ax , [edx + IPv4_header.Identification]
  540.         mov     ecx, MAX_FRAGMENTS
  541.         mov     esi, FRAGMENT_LIST
  542.         mov     ebx, [edx + IPv4_header.SourceAddress]
  543.         mov     edx, [edx + IPv4_header.DestinationAddress]
  544.   .find_slot:
  545.         cmp     [esi + FRAGMENT_slot.id], ax
  546.         jne     .try_next
  547.         cmp     [esi + FRAGMENT_slot.SrcIP], ebx
  548.         jne     .try_next
  549.         cmp     [esi + FRAGMENT_slot.DstIP], edx
  550.         je      .found_slot
  551.   .try_next:
  552.         add     esi, sizeof.FRAGMENT_slot
  553.         loop    .find_slot
  554. ;        pop     edx ebx
  555.         or      esi, -1
  556. ;        ret
  557.  
  558.   .found_slot:
  559.         pop     edx ecx ebx eax
  560.         ret
  561.  
  562.  
  563. ;------------------------------------------------------------------
  564. ;
  565. ; IPv4_output
  566. ;
  567. ; IN: eax = dest ip
  568. ;     ebx = source ip
  569. ;     ecx = data length
  570. ;     dx  = fragment id
  571. ;     di  = TTL shl 8 + protocol
  572. ;
  573. ; OUT: eax = pointer to buffer start
  574. ;      ebx = pointer to device struct (needed for sending procedure)
  575. ;      ecx = unchanged (packet size of embedded data)
  576. ;      edx = size of complete buffer
  577. ;      edi = pointer to start of data (0 on error)
  578. ;
  579. ;------------------------------------------------------------------
  580. align 4
  581. IPv4_output:
  582.  
  583.         DEBUGF  1,"IPv4_output: size=%u\n", ecx
  584.  
  585.         cmp     ecx, 65500              ; Max IPv4 packet size
  586.         ja      .too_large
  587.  
  588.         push    ecx eax ebx dx di
  589.  
  590.         call    ARP_IP_to_MAC
  591.  
  592.         test    eax, 0xffff0000         ; error bits
  593.         jnz     .arp_error
  594.  
  595.   .continue:
  596.  
  597.         push    ebx     ; push the mac
  598.         push    ax
  599.  
  600.         call    IPv4_dest_to_dev
  601.         inc     [IP_PACKETS_TX+edi]
  602.         mov     ebx, [NET_DRV_LIST+edi]
  603.         lea     eax, [ebx + ETH_DEVICE.mac]
  604.         mov     edx, esp
  605.         mov     ecx, [esp + 18]
  606.         add     ecx, sizeof.IPv4_header
  607.         mov     di , ETHER_IPv4
  608.         call    ETH_output
  609.         jz      .eth_error
  610.  
  611.         add     esp, 6  ; pop the mac
  612.  
  613.         mov     [edi + IPv4_header.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
  614.         mov     [edi + IPv4_header.TypeOfService], 0    ; nothing special, just plain ip packet
  615.         mov     [edi + IPv4_header.TotalLength], cx
  616.         rol     [edi + IPv4_header.TotalLength], 8      ; internet byte order
  617.         mov     [edi + IPv4_header.FlagsAndFragmentOffset], 0x0000
  618.         mov     [edi + IPv4_header.HeaderChecksum], 0
  619.         pop     word [edi + IPv4_header.TimeToLive]     ; ttl shl 8 + protocol
  620. ;               [edi + IPv4_header.Protocol]
  621.         popw    [edi + IPv4_header.Identification]      ; fragment id
  622.         popd    [edi + IPv4_header.SourceAddress]
  623.         popd    [edi + IPv4_header.DestinationAddress]
  624.  
  625.         pop     ecx
  626.  
  627.         IPv4_checksum edi
  628.         add     edi, sizeof.IPv4_header
  629.         DEBUGF  1,"IPv4 Packet for device %x created successfully\n", ebx
  630.         ret
  631.  
  632.   .eth_error:
  633.         DEBUGF  1,"IPv4_output: ethernet error\n"
  634.         add     esp, 3*4+2*2+6
  635.         sub     edi, edi
  636.         ret
  637.  
  638.   .arp_error:
  639.         DEBUGF  1,"IPv4_output: ARP error (0x%x)\n", eax
  640.         add     esp, 4+4+4+2+2
  641.         sub     edi, edi
  642.         ret
  643.  
  644.   .too_large:
  645.         DEBUGF  1,"IPv4_output: error: Packet too large!\n"
  646.         sub     edi, edi
  647.         ret
  648.  
  649.  
  650.  
  651.  
  652.  
  653. ;------------------------------------------------------------------
  654. ;
  655. ; IPv4_output_raw
  656. ;
  657. ; IN: eax = socket ptr
  658. ;     ecx = data length
  659. ;     esi = data ptr
  660. ;
  661. ; OUT: /
  662. ;
  663. ;------------------------------------------------------------------
  664. align 4
  665. IPv4_output_raw:
  666.  
  667.         DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax
  668.  
  669.         cmp     ecx, 1480               ;;;;; FIXME
  670.         ja      .too_large
  671.  
  672.         sub     esp, 8
  673.         push    esi eax
  674.  
  675.         call    ARP_IP_to_MAC
  676.  
  677.         test    eax, 0xffff0000         ; error bits
  678.         jnz     .arp_error
  679.  
  680.   .continue:
  681.  
  682.         push    ebx     ; push the mac
  683.         push    ax
  684.  
  685.         call    IPv4_dest_to_dev
  686.         inc     [IP_PACKETS_TX+edi]
  687.         mov     ebx, [NET_DRV_LIST+edi]
  688.         lea     eax, [ebx + ETH_DEVICE.mac]
  689.         mov     edx, esp
  690.         mov     ecx, [esp + 6+4]
  691.         add     ecx, sizeof.IPv4_header
  692.         mov     di, ETHER_IPv4
  693.         call    ETH_output
  694.         jz      .error
  695.  
  696.         add     esp, 6  ; pop the mac
  697.  
  698.         mov     dword[esp+4+4], edx
  699.         mov     dword[esp+4+4+4], eax
  700.  
  701.         pop     eax esi
  702. ;; todo: check socket options if we should add header, or just compute checksum
  703.  
  704.         push    edi ecx
  705.         rep     movsb
  706.         pop     ecx edi
  707.  
  708. ;        [edi + IPv4_header.VersionAndIHL]              ; IPv4, normal length (no Optional header)
  709. ;        [edi + IPv4_header.TypeOfService]              ; nothing special, just plain ip packet
  710. ;        [edi + IPv4_header.TotalLength]
  711. ;        [edi + IPv4_header.TotalLength]                ; internet byte order
  712. ;        [edi + IPv4_header.FlagsAndFragmentOffset]
  713.  
  714.         mov     [edi + IPv4_header.HeaderChecksum], 0
  715.  
  716. ;        [edi + IPv4_header.TimeToLive]                 ; ttl shl 8 + protocol
  717. ;        [edi + IPv4_header.Protocol]
  718. ;        [edi + IPv4_header.Identification]             ; fragment id
  719. ;        [edi + IPv4_header.SourceAddress]
  720. ;        [edi + IPv4_header.DestinationAddress]
  721.  
  722.         IPv4_checksum edi                       ;;;; todo: checksum for IP packet with options!
  723.         add     edi, sizeof.IPv4_header
  724.         DEBUGF  1,"IPv4 Packet for device %x created successfully\n", ebx
  725.         call    [ebx + NET_DEVICE.transmit]
  726.         ret
  727.  
  728.   .error:
  729.         add     esp, 6
  730.   .arp_error:
  731.         add     esp, 8+4+4
  732.   .too_large:
  733.         DEBUGF  1,"IPv4_output_raw: Failed\n"
  734.         sub     edi, edi
  735.         ret
  736.  
  737.  
  738. ;--------------------------------------------------------
  739. ;
  740. ;
  741. ; IN: dword [esp] = pointer to buffer containing ipv4 packet to be fragmented
  742. ;     dword [esp+4] = buffer size
  743. ;     esi = pointer to ip header in that buffer
  744. ;     ecx = max size of fragments
  745. ;
  746. ; OUT: /
  747. ;
  748. ;--------------------------------------------------------
  749.  
  750. align 4
  751. IPv4_fragment:
  752.  
  753.         DEBUGF 1,"IPv4_fragment\n"
  754.  
  755.         and     ecx, not 111b   ; align 4
  756.  
  757.         cmp     ecx, sizeof.IPv4_header + 8     ; must be able to put at least 8 bytes
  758.         jb      .err2
  759.  
  760.         push    esi ecx
  761.         mov     eax, [esi + IPv4_header.DestinationAddress]
  762.         call    ARP_IP_to_MAC
  763.         pop     ecx esi
  764.         cmp     eax, -1
  765.         jz      .err2
  766.  
  767.         push    ebx
  768.         push    ax
  769.  
  770.         mov     ebx, [NET_DRV_LIST]
  771.         lea     eax, [ebx + ETH_DEVICE.mac]
  772.         push    eax
  773.  
  774.  
  775.         push    esi                             ; ptr to ip header
  776.         sub     ecx, sizeof.IPv4_header         ; substract header size
  777.         push    ecx                             ; max data size
  778.         push    dword 0                         ; offset
  779.  
  780.   .new_fragment:
  781.         DEBUGF 1,"Ipv4_fragment - new_fragmentn"
  782.  
  783.  
  784.         mov     eax, [esp + 3*4]
  785.         lea     ebx, [esp + 4*4]
  786.         mov     di , ETHER_IPv4
  787.         call    ETH_output
  788.  
  789.         cmp     edi, -1
  790.         jz      .err
  791.  
  792. ; copy header
  793.         mov     esi, [esp + 2*4]
  794.         mov     ecx, 5  ; 5 dwords: TODO: use IHL field of the header!
  795.         rep     movsd
  796.  
  797. ; copy data
  798.         mov     esi, [esp + 2*4]
  799.         add     esi, sizeof.IPv4_header
  800.         add     esi, [esp]      ; offset
  801.  
  802.         mov     ecx, [esp + 1*4]
  803.         DEBUGF 1,"IPv4_fragment - copying data (%u bytes)\n", ecx
  804.         rep     movsb
  805.  
  806. ; now, correct header
  807.         mov     ecx, [esp + 1*4]
  808.         add     ecx, sizeof.IPv4_header
  809.         xchg    cl, ch
  810.         mov     [edi + IPv4_header.TotalLength], cx
  811.  
  812.         mov     ecx, [esp]              ; offset
  813.         xchg    cl, ch
  814.  
  815. ;        cmp     dword[esp + 4*4], 0     ; last fragment?;<<<<<<
  816. ;        je      .last_fragment
  817.         or      cx, 1 shl 2             ; more fragments
  818. ;  .last_fragment:
  819.         mov     [edi + IPv4_header.FlagsAndFragmentOffset], cx
  820.  
  821.         mov     [edi + IPv4_header.HeaderChecksum], 0
  822.  
  823.         ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<< send the packet
  824.         mov     ecx, [esp + 1*4]
  825.  
  826.         push    edx eax
  827.         IPv4_checksum edi
  828.  
  829.         call    [ebx + NET_DEVICE.transmit]
  830.         ;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  831.  
  832.         mov     ecx,  [esp+4]
  833.         add     [esp], ecx
  834.  
  835.         mov     ecx, [esp+3*4+6+4]      ; ptr to begin of buff
  836.         add     ecx, [esp+3*4+6+4+4]    ; buff size
  837.         sub     ecx, [esp+2*4]          ; ptr to ip header
  838.         add     ecx, [esp]              ; offset
  839.  
  840.         DEBUGF 1,"Ipv4_fragment - bytes remaining: %u\n", ecx
  841.  
  842.         cmp     ecx, [esp+1*4]
  843.         jae     .new_fragment
  844.  
  845.         mov     [esp+4], ecx            ; set fragment size to remaining packet size
  846.         jmp     .new_fragment
  847.  
  848.       .err:
  849.         DEBUGF 1,"Ipv4_fragment - failed\n"
  850.       .done:
  851.         add     esp, 12 + 4 + 6
  852.       .err2:
  853.         DEBUGF 1,"Ipv4_fragment - dumping\n"
  854.         call    kernel_free
  855.         add     esp, 4
  856.  
  857.         ret
  858.  
  859.  
  860.  
  861. ;---------------------------------------------------------------------------
  862. ;
  863. ; IPv4_dest_to_dev
  864. ;
  865. ; IN:  eax = Destination IP
  866. ; OUT: edi = device id * 4
  867. ;
  868. ;---------------------------------------------------------------------------
  869. align 4
  870. IPv4_dest_to_dev:
  871.  
  872.         cmp     eax, 0xffffffff
  873.         je      .invalid
  874.  
  875.         xor     edi, edi
  876.         mov     ecx, MAX_IP
  877.  
  878.   .loop:
  879.         mov     ebx, [IP_LIST+edi]
  880.         and     ebx, [SUBNET_LIST+edi]
  881.         jz      .next
  882.  
  883.         mov     edx, eax
  884.         and     edx, [SUBNET_LIST+edi]
  885.  
  886.         cmp     ebx, edx
  887.         je      .found_it
  888.   .next:
  889.         add     edi, 4
  890.         loop    .loop
  891.  
  892.   .invalid:
  893.         xor     edi, edi                        ; if none found, use device 0 as default device
  894.  
  895.   .found_it:
  896.         DEBUGF  1,"IPv4_dest_to_dev: %u\n", edi
  897.  
  898.         ret
  899.  
  900.  
  901.  
  902. ;---------------------------------------------------------------------------
  903. ;
  904. ; IPv4_get_frgmnt_num
  905. ;
  906. ; IN: /
  907. ; OUT: fragment number in ax
  908. ;
  909. ;---------------------------------------------------------------------------
  910. align 4
  911. IPv4_get_frgmnt_num:
  912.         xor     ax, ax  ;;; TODO: replace this with real code
  913.  
  914.         ret
  915.  
  916.  
  917. ;---------------------------------------------------------------------------
  918. ;
  919. ; IPv4_API
  920. ;
  921. ; This function is called by system function 75
  922. ;
  923. ; IN:  subfunction number in bl
  924. ;      device number in bh
  925. ;      ecx, edx, .. depends on subfunction
  926. ;
  927. ; OUT:
  928. ;
  929. ;---------------------------------------------------------------------------
  930. align 4
  931. IPv4_api:
  932.  
  933.         movzx   eax, bh
  934.         shl     eax, 2
  935.  
  936.         and     ebx, 0x000000ff
  937.         cmp     ebx, .number
  938.         ja      .error
  939.         jmp     dword [.table + 4*ebx]
  940.  
  941.   .table:
  942.         dd      .packets_tx     ; 0
  943.         dd      .packets_rx     ; 1
  944.         dd      .read_ip        ; 2
  945.         dd      .write_ip       ; 3
  946.         dd      .read_dns       ; 4
  947.         dd      .write_dns      ; 5
  948.         dd      .read_subnet    ; 6
  949.         dd      .write_subnet   ; 7
  950.         dd      .read_gateway   ; 8
  951.         dd      .write_gateway  ; 9
  952.   .number = ($ - .table) / 4 - 1
  953.  
  954.   .error:
  955.         mov     eax, -1
  956.         ret
  957.  
  958.   .packets_tx:
  959.         mov     eax, [IP_PACKETS_TX + eax]
  960.         ret
  961.  
  962.   .packets_rx:
  963.         mov     eax, [IP_PACKETS_RX + eax]
  964.         ret
  965.  
  966.   .read_ip:
  967.         mov     eax, [IP_LIST + eax]
  968.         ret
  969.  
  970.   .write_ip:
  971.         mov     [IP_LIST + eax], ecx
  972.         xor     eax, eax
  973.         ret
  974.  
  975.   .read_dns:
  976.         mov     eax, [DNS_LIST + eax]
  977.         ret
  978.  
  979.   .write_dns:
  980.         mov     [DNS_LIST + eax], ecx
  981.         xor     eax, eax
  982.         ret
  983.  
  984.   .read_subnet:
  985.         mov     eax, [SUBNET_LIST + eax]
  986.         ret
  987.  
  988.   .write_subnet:
  989.         mov     [SUBNET_LIST + eax], ecx
  990.         xor     eax, eax
  991.         ret
  992.  
  993.   .read_gateway:
  994.         mov     eax, [GATEWAY_LIST + eax]
  995.         ret
  996.  
  997.   .write_gateway:
  998.         mov     [GATEWAY_LIST + eax], ecx
  999.         xor     eax, eax
  1000.         ret