Subversion Repositories Kolibri OS

Rev

Rev 4053 | Rev 4259 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2013. 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. IPv4_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  IPv4_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  IPv4_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. uglobal
  59. align 4
  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.         IPv4_packets_tx         rd NET_DEVICES_MAX
  68.         IPv4_packets_rx         rd NET_DEVICES_MAX
  69.         IPv4_packets_dumped     rd NET_DEVICES_MAX
  70.  
  71.         IPv4_FRAGMENT_LIST      rb IPv4_MAX_FRAGMENTS * sizeof.IPv4_FRAGMENT_slot
  72.  
  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*NET_DEVICES_MAX + (sizeof.IPv4_FRAGMENT_slot*IPv4_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, IPv4_FRAGMENT_LIST
  103.         mov     ecx, IPv4_MAX_FRAGMENTS
  104.   .loop:
  105.         cmp     [esi + IPv4_FRAGMENT_slot.ttl], 0
  106.         je      .next
  107.         dec     [esi + IPv4_FRAGMENT_slot.ttl]
  108.         jz      .died
  109.   .next:
  110.         add     esi, sizeof.IPv4_FRAGMENT_slot
  111.         dec     ecx
  112.         jnz     .loop
  113.         jmp     .done
  114.  
  115.   .died:
  116.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4 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  DEBUG_NETWORK_VERBOSE, "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  DEBUG_NETWORK_VERBOSE, "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  DEBUG_NETWORK_VERBOSE, "IPv4_input: Checksum ok\n"
  223.  
  224. ;-----------------------------------
  225. ; Check if destination IP is correct
  226.  
  227.         call    NET_ptr_to_num4
  228.  
  229.         ; check if it matches local ip (Using RFC1122 strong end system model)
  230.  
  231.         mov     eax, [edx + IPv4_header.DestinationAddress]
  232.         cmp     eax, [IP_LIST + edi]
  233.         je      .ip_ok
  234.  
  235.         ; check for broadcast (IP or (not SUBNET))
  236.  
  237.         cmp     eax, [BROADCAST_LIST + edi]
  238.         je      .ip_ok
  239.  
  240.         ; or a special broadcast (255.255.255.255)
  241.  
  242.         cmp     eax, 0xffffffff
  243.         je      .ip_ok
  244.  
  245.         ; maybe it's a multicast (224.0.0.0/4)
  246.  
  247.         and     eax, 0x0fffffff
  248.         cmp     eax, 224
  249.         je      .ip_ok
  250.  
  251.         ; or a loopback address (127.0.0.0/8)
  252.  
  253.         and     eax, 0x00ffffff
  254.         cmp     eax, 127
  255.         je      .ip_ok
  256.  
  257.         ; or it's just not meant for us.. :(
  258.  
  259.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Destination address does not match!\n"
  260.         jmp     .dump
  261.  
  262. ;------------------------
  263. ; Now we can update stats
  264.  
  265.   .ip_ok:
  266.         inc     [IPv4_packets_rx + edi]
  267.  
  268. ;----------------------------------
  269. ; Check if the packet is fragmented
  270.  
  271.         test    [edx + IPv4_header.FlagsAndFragmentOffset], 1 shl 5     ; Is 'more fragments' flag set ?
  272.         jnz     .has_fragments                                          ; If so, we definately have a fragmented packet
  273.  
  274.         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
  275.         jnz     .is_last_fragment
  276.  
  277. ;-------------------------------------------------------------------
  278. ; No, it's just a regular IP packet, pass it to the higher protocols
  279.  
  280.   .handle_it:                                                   ; We reach here if packet hasnt been fragmented, or when it already has been re-constructed
  281.  
  282.         movzx   esi, [edx + IPv4_header.VersionAndIHL]          ; Calculate Header length by using IHL field
  283.         and     esi, 0x0000000f                                 ;
  284.         shl     esi, 2                                          ;
  285.  
  286.         movzx   ecx, [edx + IPv4_header.TotalLength]            ; Calculate length of encapsulated Packet
  287.         xchg    cl, ch                                          ;
  288.         sub     ecx, esi                                        ;
  289.  
  290.         lea     edi, [edx + IPv4_header.SourceAddress]          ; make edi ptr to source and dest IPv4 address
  291.         mov     al, [edx + IPv4_header.Protocol]
  292.         add     esi, edx                                        ; make esi ptr to data
  293.  
  294.         cmp     al, IP_PROTO_TCP
  295.         je      TCP_input
  296.  
  297.         cmp     al, IP_PROTO_UDP
  298.         je      UDP_input
  299.  
  300.         cmp     al, IP_PROTO_ICMP
  301.         je      ICMP_input
  302.  
  303.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: unknown protocol %u\n", al
  304.  
  305.   .dump:
  306.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: dumping\n"
  307.         inc     [IPv4_packets_dumped]                           ; FIXME: use correct interface
  308.         call    NET_packet_free
  309.         add     esp, 4                                          ; pop (balance stack)
  310.         ret
  311.  
  312.  
  313. ;---------------------------
  314. ; Fragmented packet handler
  315.  
  316.  
  317.   .has_fragments:
  318.         movzx   eax, [edx + IPv4_header.FlagsAndFragmentOffset]
  319.         xchg    al, ah
  320.         shl     ax, 3
  321.  
  322.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: fragmented packet offset=%u id=%x ptr=0x%x\n", ax, [edx + IPv4_header.Identification]:4, edx
  323.  
  324.         test    ax, ax                                          ; Is this the first packet of the fragment?
  325.         jz      .is_first_fragment
  326.  
  327.  
  328. ;-------------------------------------------------------
  329. ; We have a fragmented IP packet, but it's not the first
  330.  
  331.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Middle fragment packet received!\n"
  332.  
  333.         call    IPv4_find_fragment_slot
  334.         cmp     esi, -1
  335.         je      .dump
  336.  
  337.         mov     [esi + IPv4_FRAGMENT_slot.ttl], 15              ; Reset the ttl
  338.         mov     esi, [esi + IPv4_FRAGMENT_slot.ptr]
  339.         or      edi, -1
  340.   .find_last_entry:                                             ; The following routine will try to find the last entry
  341.         cmp     edi, [esi + IPv4_FRAGMENT_entry.PrevPtr]
  342.         jne     .destroy_slot                                   ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
  343.         mov     edi, esi
  344.         mov     esi, [esi + IPv4_FRAGMENT_entry.NextPtr]
  345.         cmp     esi, -1
  346.         jne     .find_last_entry
  347.                                                                 ; We found the last entry (pointer is now in edi)
  348.                                                                 ; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure
  349.  
  350.         pop     eax                                             ; pointer to packet
  351.         mov     [edi + IPv4_FRAGMENT_entry.NextPtr], eax        ; update pointer of previous entry to the new entry
  352.         mov     [eax + IPv4_FRAGMENT_entry.NextPtr], -1
  353.         mov     [eax + IPv4_FRAGMENT_entry.PrevPtr], edi
  354.         mov     [eax + IPv4_FRAGMENT_entry.Owner], ebx
  355.  
  356.         add     esp, 4
  357.         ret
  358.  
  359.  
  360. ;------------------------------------
  361. ; We have received the first fragment
  362.  
  363.   .is_first_fragment:
  364.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: First fragment packet received!\n"
  365.                                                                 ; try to locate a free slot..
  366.         mov     ecx, IPv4_MAX_FRAGMENTS
  367.         mov     esi, IPv4_FRAGMENT_LIST
  368.   .find_free_slot:
  369.         cmp     word [esi + IPv4_FRAGMENT_slot.ttl], 0
  370.         je      .found_free_slot
  371.         add     esi, sizeof.IPv4_FRAGMENT_slot
  372.         loop    .find_free_slot
  373.         jmp     .dump                                           ; If no free slot was found, dump the packet
  374.  
  375.   .found_free_slot:                                             ; We found a free slot, let's fill in the FRAGMENT_slot structure
  376.         mov     [esi + IPv4_FRAGMENT_slot.ttl], 15              ; RFC recommends 15 secs as ttl
  377.         mov     ax, [edx + IPv4_header.Identification]
  378.         mov     [esi + IPv4_FRAGMENT_slot.id], ax
  379.         mov     eax, [edx + IPv4_header.SourceAddress]
  380.         mov     [esi + IPv4_FRAGMENT_slot.SrcIP], eax
  381.         mov     eax, [edx + IPv4_header.DestinationAddress]
  382.         mov     [esi + IPv4_FRAGMENT_slot.DstIP], eax
  383.         pop     eax
  384.         mov     [esi + IPv4_FRAGMENT_slot.ptr], eax
  385.                                                                 ; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure
  386.         mov     [eax + IPv4_FRAGMENT_entry.NextPtr], -1
  387.         mov     [eax + IPv4_FRAGMENT_entry.PrevPtr], -1
  388.         mov     [eax + IPv4_FRAGMENT_entry.Owner], ebx
  389.  
  390.         add     esp, 4                                          ; balance stack and exit
  391.         ret
  392.  
  393.  
  394. ;-----------------------------------
  395. ; We have received the last fragment
  396.  
  397.   .is_last_fragment:
  398.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Last fragment packet received!\n"
  399.  
  400.         call    IPv4_find_fragment_slot
  401.         cmp     esi, -1
  402.         je      .dump
  403.  
  404.         mov     esi, [esi + IPv4_FRAGMENT_slot.ptr]                     ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer
  405.         push    esi
  406.         xor     eax, eax
  407.         or      edi, -1
  408.  
  409.   .count_bytes:
  410.         cmp     [esi + IPv4_FRAGMENT_entry.PrevPtr], edi
  411.         jne     .destroy_slot_pop                                                       ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
  412.         mov     cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength]        ; Add total length
  413.         xchg    cl, ch
  414.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
  415.         add     ax, cx
  416.         movzx   cx, [esi + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL]      ; Sub Header length
  417.         and     cx, 0x000F
  418.         shl     cx, 2
  419.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Header size=%u\n", cx
  420.         sub     ax, cx
  421.         mov     edi, esi
  422.         mov     esi, [esi + IPv4_FRAGMENT_entry.NextPtr]
  423.         cmp     esi, -1
  424.         jne     .count_bytes
  425.  
  426.         mov     esi, [esp+4]
  427.         mov     [edi + IPv4_FRAGMENT_entry.NextPtr], esi                                ; Add this packet to the chain, this simplifies the following code
  428.         mov     [esi + IPv4_FRAGMENT_entry.NextPtr], -1
  429.         mov     [esi + IPv4_FRAGMENT_entry.PrevPtr], edi
  430.         mov     [esi + IPv4_FRAGMENT_entry.Owner], ebx
  431.  
  432.         mov     cx, [edx + IPv4_header.TotalLength]                                     ; Note: This time we dont substract Header length
  433.         xchg    cl, ch
  434.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet size=%u\n", cx
  435.         add     ax, cx
  436.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Received data size=%u\n", eax
  437.  
  438.         push    eax
  439.         mov     ax, [edx + IPv4_header.FlagsAndFragmentOffset]
  440.         xchg    al, ah
  441.         shl     ax, 3
  442.         add     cx, ax
  443.         pop     eax
  444.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Total Fragment size=%u\n", ecx
  445.  
  446.         cmp     ax, cx
  447.         jne     .destroy_slot_pop
  448.  
  449.         push    eax
  450.         push    eax
  451.         call    kernel_alloc
  452.         test    eax, eax
  453.         je      .destroy_slot_pop                                                       ; If we dont have enough space to allocate the buffer, discard all packets in slot
  454.         mov     edx, [esp+4]                                                            ; Get pointer to first fragment entry back in edx
  455.  
  456.   .rebuild_packet_loop:
  457.         movzx   ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.FlagsAndFragmentOffset] ; Calculate the fragment offset
  458.         xchg    cl, ch                                                                  ;  intel byte order
  459.         shl     cx, 3                                                                   ;   multiply by 8 and clear first 3 bits
  460.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Fragment offset=%u\n", cx
  461.  
  462.         lea     edi, [eax + ecx]                                                        ; Notice that edi will be equal to eax for first fragment
  463.         movzx   ebx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.VersionAndIHL]     ; Find header size (in ebx) of fragment
  464.         and     bx, 0x000F                                                              ;
  465.         shl     bx, 2                                                                   ;
  466.  
  467.         lea     esi, [edx + sizeof.IPv4_FRAGMENT_entry]                                 ; Set esi to the correct begin of fragment
  468.         movzx   ecx, [edx + sizeof.IPv4_FRAGMENT_entry + IPv4_header.TotalLength]       ; Calculate total length of fragment
  469.         xchg    cl, ch                                                                  ;  intel byte order
  470.  
  471.         cmp     edi, eax                                                                ; Is this packet the first fragment ?
  472.         je      .first_fragment
  473.         sub     cx, bx                                                                  ; If not, dont copy the header
  474.         add     esi, ebx                                                                ;
  475.   .first_fragment:
  476.  
  477.  
  478.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Copying %u bytes from 0x%x to 0x%x\n", ecx, esi, edi
  479.         push    cx                                                                      ; First copy dword-wise, then byte-wise
  480.         shr     cx, 2                                                                   ;
  481.         rep movsd                                                                       ;
  482.         pop     cx                                                                      ;
  483.         and     cx, 3                                                                   ;
  484.         rep movsb                                                                       ;
  485.  
  486.         push    eax
  487.         push    [edx + IPv4_FRAGMENT_entry.Owner]                                  ; we need to remeber the owner, in case this is the last packet
  488.         push    [edx + IPv4_FRAGMENT_entry.NextPtr]                                ; Set edx to the next pointer
  489.         push    edx                                                                     ; Push pointer to fragment onto stack
  490.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Next Fragment: 0x%x\n", edx
  491.         call    NET_packet_free                                                         ; free the previous fragment buffer (this uses the value from stack)
  492.         pop     edx ebx eax
  493.         cmp     edx, -1                                                                 ; Check if it is last fragment in chain
  494.         jne     .rebuild_packet_loop
  495.  
  496.         pop     ecx
  497.         xchg    cl, ch
  498.         mov     edx, eax
  499.         mov     [edx + IPv4_header.TotalLength], cx
  500.         add     esp, 8
  501.         xchg    cl, ch
  502.         push    ecx
  503.  
  504.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Packet is now de-fragmented\n"
  505.  
  506.         push    eax
  507.         jmp     .handle_it          ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
  508.  
  509.   .destroy_slot_pop:
  510.         add     esp, 4
  511.   .destroy_slot:
  512.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_input: Destroy fragment slot!\n"
  513.         ; TODO!
  514.         jmp     .dump
  515.  
  516.  
  517.  
  518.  
  519.  
  520. ;-----------------------------------------------------------------
  521. ;
  522. ; find fragment slot
  523. ;
  524. ; IN: pointer to fragmented packet in edx
  525. ; OUT: pointer to slot in esi, -1 on error
  526. ;
  527. ;-----------------------------------------------------------------
  528. align 4
  529. IPv4_find_fragment_slot:
  530.  
  531. ;;; TODO: the RFC says we should check protocol number too
  532.  
  533.         push    eax ebx ecx edx
  534.         mov     ax, [edx + IPv4_header.Identification]
  535.         mov     ecx, IPv4_MAX_FRAGMENTS
  536.         mov     esi, IPv4_FRAGMENT_LIST
  537.         mov     ebx, [edx + IPv4_header.SourceAddress]
  538.         mov     edx, [edx + IPv4_header.DestinationAddress]
  539.   .find_slot:
  540.         cmp     [esi + IPv4_FRAGMENT_slot.id], ax
  541.         jne     .try_next
  542.         cmp     [esi + IPv4_FRAGMENT_slot.SrcIP], ebx
  543.         jne     .try_next
  544.         cmp     [esi + IPv4_FRAGMENT_slot.DstIP], edx
  545.         je      .found_slot
  546.   .try_next:
  547.         add     esi, sizeof.IPv4_FRAGMENT_slot
  548.         loop    .find_slot
  549.  
  550.         or      esi, -1
  551.   .found_slot:
  552.         pop     edx ecx ebx eax
  553.         ret
  554.  
  555.  
  556. ;------------------------------------------------------------------
  557. ;
  558. ; IPv4_output
  559. ;
  560. ; IN:   eax = Destination IP
  561. ;       ecx = data length
  562. ;       edx = Source IP
  563. ;       di  = TTL shl 8 + protocol
  564. ;
  565. ; OUT:  eax = pointer to buffer start
  566. ;       ebx = pointer to device struct (needed for sending procedure)
  567. ;       ecx = unchanged (packet size of embedded data)
  568. ;       edx = size of complete buffer
  569. ;       edi = pointer to start of data (0 on error)
  570. ;
  571. ;------------------------------------------------------------------
  572. align 4
  573. IPv4_output:
  574.  
  575.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: size=%u ip=0x%x\n", ecx, eax
  576.  
  577.         cmp     ecx, 65500              ; Max IPv4 packet size
  578.         ja      .too_large
  579.  
  580.         push    ecx di eax
  581.         call    IPv4_route              ; outputs device number in edi, dest ip in eax, source IP in edx
  582.         push    edx
  583.  
  584.         test    edi, edi
  585.         jz      .loopback
  586.  
  587.         call    ARP_IP_to_MAC
  588.         test    eax, 0xffff0000         ; error bits
  589.         jnz     .arp_error
  590.         push    ebx                     ; push the mac onto the stack
  591.         push    ax
  592.  
  593.         inc     [IPv4_packets_tx + edi]   ; update stats
  594.  
  595.         mov     ebx, [NET_DRV_LIST + edi]
  596.         lea     eax, [ebx + ETH_DEVICE.mac]
  597.         mov     edx, esp
  598.         mov     ecx, [esp + 6 + 8 + 2]
  599.         add     ecx, sizeof.IPv4_header
  600.         mov     di, ETHER_PROTO_IPv4
  601.         call    ETH_output
  602.         jz      .eth_error
  603.         add     esp, 6                  ; pop the mac out of the stack
  604.  
  605.   .continue:
  606.         xchg    cl, ch                                  ; internet byte order
  607.         mov     [edi + IPv4_header.VersionAndIHL], 0x45 ; IPv4, normal length (no Optional header)
  608.         mov     [edi + IPv4_header.TypeOfService], 0    ; nothing special, just plain ip packet
  609.         mov     [edi + IPv4_header.TotalLength], cx
  610.         mov     [edi + IPv4_header.Identification], 0   ; fragment id: FIXME
  611.         mov     [edi + IPv4_header.FlagsAndFragmentOffset], 0
  612.  
  613.         mov     [edi + IPv4_header.HeaderChecksum], 0
  614.         popd    [edi + IPv4_header.SourceAddress]
  615.         popd    [edi + IPv4_header.DestinationAddress]
  616.  
  617.         pop     word[edi + IPv4_header.TimeToLive]      ; ttl shl 8 + protocol
  618. ;               [edi + IPv4_header.Protocol]
  619.  
  620.         pop     ecx
  621.  
  622.         IPv4_checksum edi
  623.         add     edi, sizeof.IPv4_header
  624.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_output: success!\n"
  625.         ret
  626.  
  627.   .eth_error:
  628.         DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ethernet error\n"
  629.         add     esp, 3*4+2+6
  630.         xor     edi, edi
  631.         ret
  632.  
  633.   .arp_error:
  634.         DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: ARP error=%x\n", eax
  635.         add     esp, 3*4+2
  636.         xor     edi, edi
  637.         ret
  638.  
  639.   .too_large:
  640.         DEBUGF  DEBUG_NETWORK_ERROR, "IPv4_output: Packet too large!\n"
  641.         xor     edi, edi
  642.         ret
  643.  
  644.   .loopback:
  645.         mov     dword [esp + 2], eax            ; change source IP to dest IP
  646.         mov     ecx, [esp + 10]
  647.         add     ecx, sizeof.IPv4_header
  648.         mov     edi, AF_INET4
  649.         call    LOOP_output
  650.         jmp     .continue
  651.  
  652.  
  653.  
  654.  
  655. ;------------------------------------------------------------------
  656. ;
  657. ; IPv4_output_raw
  658. ;
  659. ; IN: eax = socket ptr
  660. ;     ecx = data length
  661. ;     esi = data ptr
  662. ;
  663. ; OUT: /
  664. ;
  665. ;------------------------------------------------------------------
  666. align 4
  667. IPv4_output_raw:
  668.  
  669.         DEBUGF 1,"IPv4_output_raw: size=%u ptr=%x socket=%x\n", ecx, esi, eax
  670.  
  671.         cmp     ecx, 1480               ;;;;; FIXME
  672.         ja      .too_large
  673.  
  674.         sub     esp, 8
  675.         push    esi eax
  676.  
  677.         call    IPv4_route
  678.         call    ARP_IP_to_MAC
  679.  
  680.         test    eax, 0xffff0000         ; error bits
  681.         jnz     .arp_error
  682.  
  683.         push    ebx                     ; push the mac
  684.         push    ax
  685.  
  686.         inc     [IPv4_packets_tx + 4*edi]
  687.         mov     ebx, [NET_DRV_LIST + 4*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_PROTO_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  DEBUG_NETWORK_VERBOSE, "IPv4_output_raw: device=%x\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  DEBUG_NETWORK_ERROR, "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  DEBUG_NETWORK_VERBOSE, "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  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: new fragment"
  782.  
  783.  
  784.         mov     eax, [esp + 3*4]
  785.         lea     ebx, [esp + 4*4]
  786.         mov     di , ETHER_PROTO_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  DEBUG_NETWORK_VERBOSE, "IPv4_fragment: copying %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  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: %u bytes remaining\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  DEBUG_NETWORK_ERROR, "Ipv4_fragment: failed\n"
  850.       .done:
  851.         add     esp, 12 + 4 + 6
  852.       .err2:
  853.         DEBUGF  DEBUG_NETWORK_VERBOSE, "Ipv4_fragment: dumping\n"
  854.         call    NET_packet_free
  855.         add     esp, 4
  856.  
  857.         ret
  858.  
  859.  
  860.  
  861. ;---------------------------------------------------------------------------
  862. ;
  863. ; IPv4_route
  864. ;
  865. ; IN:   eax = Destination IP
  866. ;       edx = Source IP
  867. ; OUT:  eax = Destination IP (or gateway IP)
  868. ;       edx = Source IP
  869. ;       edi = device number*4
  870. ; DESTROYED:
  871. ;       ecx
  872. ;
  873. ;---------------------------------------------------------------------------
  874. align 4
  875. IPv4_route:     ; TODO: return error if no valid route found
  876.  
  877.         cmp     eax, 0xffffffff
  878.         je      .broadcast
  879.  
  880.         xor     edi, edi
  881.   .loop:
  882.         mov     ebx, [IP_LIST + edi]
  883.         and     ebx, [SUBNET_LIST + edi]
  884.         jz      .next
  885.         mov     ecx, eax
  886.         and     ecx, [SUBNET_LIST + edi]
  887.         cmp     ebx, ecx
  888.         je      .got_it
  889.   .next:
  890.         add     edi, 4
  891.         cmp     edi, 4*NET_DEVICES_MAX
  892.         jb      .loop
  893.  
  894.         mov     eax, [GATEWAY_LIST + 4]         ; TODO: let user (or a user space daemon) configure default route
  895.   .broadcast:
  896.         mov     edi, 4                          ; TODO: same as above
  897.   .got_it:
  898.         DEBUGF  DEBUG_NETWORK_VERBOSE, "IPv4_route: %u\n", edi
  899.         test    edx, edx
  900.         jnz     @f
  901.         mov     edx, [IP_LIST + edi]
  902.   @@:
  903.  
  904.         ret
  905.  
  906.  
  907.  
  908. ;---------------------------------------------------------------------------
  909. ;
  910. ; IPv4_get_frgmnt_num
  911. ;
  912. ; IN: /
  913. ; OUT: fragment number in ax
  914. ;
  915. ;---------------------------------------------------------------------------
  916. align 4
  917. IPv4_get_frgmnt_num:
  918.         xor     ax, ax  ;;; TODO: replace this with real code
  919.  
  920.         ret
  921.  
  922.  
  923. ;-----------------------------------------------------------------
  924. ;
  925. ; IPv4_connect
  926. ;
  927. ;   IN: eax = socket pointer
  928. ;  OUT: eax = 0 ok / -1 error
  929. ;       ebx = error code
  930. ;
  931. ;-------------------------
  932. align 4
  933. IPv4_connect:
  934.  
  935.         push    eax edx
  936.         lea     ecx, [eax + SOCKET.mutex]
  937.         call    mutex_lock
  938.         pop     edx eax
  939.  
  940. ; Fill in local IP
  941.         cmp     [eax + IP_SOCKET.LocalIP], 0
  942.         jne     @f
  943.         push    [IP_LIST + 4]                                   ; FIXME: use correct local IP
  944.         pop     [eax + IP_SOCKET.LocalIP]
  945.  
  946. ; Fill in remote IP
  947.         pushd   [edx + 4]
  948.         pop     [eax + IP_SOCKET.RemoteIP]
  949.  
  950. ; Set up data receiving queue
  951.         push    eax
  952.         init_queue (eax + SOCKET_QUEUE_LOCATION)
  953.         pop     eax
  954.  
  955.         lea     ecx, [eax + SOCKET.mutex]
  956.         call    mutex_unlock
  957.  
  958.         xor     eax, eax
  959.         ret
  960.  
  961.  
  962. ;---------------------------------------------------------------------------
  963. ;
  964. ; IPv4_API
  965. ;
  966. ; This function is called by system function 75
  967. ;
  968. ; IN:  subfunction number in bl
  969. ;      device number in bh
  970. ;      ecx, edx, .. depends on subfunction
  971. ;
  972. ; OUT:
  973. ;
  974. ;---------------------------------------------------------------------------
  975. align 4
  976. IPv4_api:
  977.  
  978.         movzx   eax, bh
  979.         shl     eax, 2
  980.  
  981.         and     ebx, 0x000000ff
  982.         cmp     ebx, .number
  983.         ja      .error
  984.         jmp     dword [.table + 4*ebx]
  985.  
  986.   .table:
  987.         dd      .packets_tx     ; 0
  988.         dd      .packets_rx     ; 1
  989.         dd      .read_ip        ; 2
  990.         dd      .write_ip       ; 3
  991.         dd      .read_dns       ; 4
  992.         dd      .write_dns      ; 5
  993.         dd      .read_subnet    ; 6
  994.         dd      .write_subnet   ; 7
  995.         dd      .read_gateway   ; 8
  996.         dd      .write_gateway  ; 9
  997.   .number = ($ - .table) / 4 - 1
  998.  
  999.   .error:
  1000.         mov     eax, -1
  1001.         ret
  1002.  
  1003.   .packets_tx:
  1004.         mov     eax, [IPv4_packets_tx + eax]
  1005.         ret
  1006.  
  1007.   .packets_rx:
  1008.         mov     eax, [IPv4_packets_rx + eax]
  1009.         ret
  1010.  
  1011.   .read_ip:
  1012.         mov     eax, [IP_LIST + eax]
  1013.         ret
  1014.  
  1015.   .write_ip:
  1016.         mov     [IP_LIST + eax], ecx
  1017.         mov     edi, eax                        ; device number, we'll need it for ARP
  1018.  
  1019.         ; pre-calculate the local broadcast address
  1020.         mov     ebx, [SUBNET_LIST + eax]
  1021.         not     ebx
  1022.         or      ebx, ecx
  1023.         mov     [BROADCAST_LIST + eax], ebx
  1024.  
  1025.         mov     ebx, [NET_DRV_LIST + eax]
  1026.         mov     eax, [IP_LIST + eax]
  1027.         call    ARP_output_request              ; now send a gratuitous ARP
  1028.  
  1029.         call    NET_send_event
  1030.         xor     eax, eax
  1031.         ret
  1032.  
  1033.   .read_dns:
  1034.         mov     eax, [DNS_LIST + eax]
  1035.         ret
  1036.  
  1037.   .write_dns:
  1038.         mov     [DNS_LIST + eax], ecx
  1039.         call    NET_send_event
  1040.         xor     eax, eax
  1041.         ret
  1042.  
  1043.   .read_subnet:
  1044.         mov     eax, [SUBNET_LIST + eax]
  1045.         ret
  1046.  
  1047.   .write_subnet:
  1048.         mov     [SUBNET_LIST + eax], ecx
  1049.  
  1050.         ; pre-calculate the local broadcast address
  1051.         mov     ebx, [IP_LIST + eax]
  1052.         not     ecx
  1053.         or      ecx, ebx
  1054.         mov     [BROADCAST_LIST + eax], ecx
  1055.  
  1056.         call    NET_send_event
  1057.         xor     eax, eax
  1058.         ret
  1059.  
  1060.   .read_gateway:
  1061.         mov     eax, [GATEWAY_LIST + eax]
  1062.         ret
  1063.  
  1064.   .write_gateway:
  1065.         mov     [GATEWAY_LIST + eax], ecx
  1066.  
  1067.         call    NET_send_event
  1068.         xor     eax, eax
  1069.         ret