Subversion Repositories Kolibri OS

Rev

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

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