Subversion Repositories Kolibri OS

Rev

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