Subversion Repositories Kolibri OS

Rev

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