Subversion Repositories Kolibri OS

Rev

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

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