Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                                 ;;
  3. ;; Copyright (C) KolibriOS team 2004-2010. 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: 1519 $
  20.  
  21. MAX_FRAGMENTS   equ 64
  22. MAX_IP          equ MAX_NET_DEVICES
  23. IP_MAX_INTERFACES   equ MAX_IP
  24.  
  25. struct  IPv4_Packet
  26.         .VersionAndIHL          db  ?  ; Version[0-3 bits] and IHL(header length)[4-7 bits]
  27.         .TypeOfService          db  ?  ; precedence [7-5] minimize delay [4], maximize throughput [3], maximize riliability [2] minimize momentary cost [1] and zero [0]
  28.         .TotalLength            dw  ?
  29.         .Identification         dw  ?
  30.         .FlagsAndFragmentOffset dw  ?  ; Flags[0-2] and FragmentOffset[3-15]
  31.         .TimeToLive             db  ?  ;
  32.         .Protocol               db  ?
  33.         .HeaderChecksum         dw  ?
  34.         .SourceAddress          dd  ?
  35.         .DestinationAddress     dd  ?
  36.         .DataOrOptional:
  37. ends
  38.  
  39. struct  FRAGMENT_slot
  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.         .size:
  46. ends
  47.  
  48. struct  FRAGMENT_entry                 ; This structure will replace the ethernet header in fragmented ip packets
  49.         .PrevPtr                dd  ?  ; Pointer to previous fragment entry  (-1 for first packet)
  50.         .NextPtr                dd  ?  ; Pointer to next fragment entry (-1 for last packet)
  51.         .Owner                  dd  ?  ; Pointer to structure of driver
  52.                                 rb  2  ; to match ethernet header size          ; TODO: fix this hack
  53.         .Data:                         ; Ip header begins here (we will need the IP header to re-construct the complete packet)
  54. ends
  55.  
  56. align 4
  57. uglobal
  58.  
  59.         IP_LIST         rd  MAX_IP
  60.         SUBNET_LIST     rd  MAX_IP
  61.         DNS_LIST        rd  MAX_IP
  62.         GATEWAY_LIST    rd  MAX_IP
  63.  
  64.         IP_PACKETS_TX   rd  MAX_IP
  65.         IP_PACKETS_RX   rd  MAX_IP
  66.  
  67.         FRAGMENT_LIST   rb  MAX_FRAGMENTS*FRAGMENT_slot.size
  68. endg
  69.  
  70.  
  71. ;-----------------------------------------------------------------
  72. ;
  73. ; IPv4_init
  74. ;
  75. ;  This function resets all IP variables
  76. ;
  77. ;  IN:  /
  78. ;  OUT: /
  79. ;
  80. ;-----------------------------------------------------------------
  81. align 4
  82. IPv4_init:
  83.  
  84.         or      eax, -1
  85.         mov     edi, IP_LIST
  86.         mov     ecx, 4*MAX_IP
  87.         rep     stosd
  88.  
  89.         inc     eax
  90.         mov     edi, FRAGMENT_LIST
  91.         mov     ecx, FRAGMENT_slot.size*MAX_FRAGMENTS/4 + 2*MAX_IP
  92.         rep     stosd
  93.  
  94.         ret
  95.  
  96.  
  97.  
  98. ;-----------------------------------------------------------------
  99. ;
  100. ; IPv4_Handler:
  101. ;
  102. ;  Will check if IP Packet isnt damaged
  103. ;  and call appropriate handler. (TCP/UDP/ICMP/..)
  104. ;
  105. ;  It will also re-construct fragmented packets
  106. ;
  107. ;  IN:  Pointer to buffer in [esp]
  108. ;       size of buffer in [esp+4]
  109. ;       pointer to device struct in ebx
  110. ;       pointer to IP Packet data in edx
  111. ;  OUT: /
  112. ;
  113. ;-----------------------------------------------------------------
  114. align 4
  115. IPv4_handler:    ; TODO: implement handler for IP options
  116.                  ; TODO2: add code for raw sockets
  117.  
  118.         DEBUGF  1,"IPv4_Handler, packet from: %u.%u.%u.%u ",\
  119.         [edx + IPv4_Packet.SourceAddress]:1,[edx + IPv4_Packet.SourceAddress + 1]:1,[edx + IPv4_Packet.SourceAddress + 2]:1,[edx + IPv4_Packet.SourceAddress + 3]:1
  120.         DEBUGF  1,"to: %u.%u.%u.%u\n",\
  121.         [edx + IPv4_Packet.DestinationAddress]:1,[edx + IPv4_Packet.DestinationAddress + 1]:1,[edx + IPv4_Packet.DestinationAddress + 2]:1,[edx + IPv4_Packet.DestinationAddress + 3]:1
  122.  
  123. ;-------------------------------------------
  124. ; Check if the packet still has time to live
  125.  
  126.         cmp     byte [edx + IPv4_Packet.TimeToLive], 0
  127.         je      .dump
  128.  
  129. ;--------------------------------------
  130. ; First, check if IP packet has options
  131.  
  132.         movzx   eax, [edx + IPv4_Packet.VersionAndIHL]
  133.         and     al , 0x0f                                       ; get IHL(header length)
  134.         cmp     al , 0x05                                       ; IHL!= 5*4(20 bytes)
  135.         jnz     .has_options
  136.  
  137. ;-------------------------------
  138. ; Now, re-calculate the checksum
  139.  
  140.         push    edx ebx
  141.         mov     esi, edx
  142.         call    IPv4_checksum
  143.         pop     ebx edx
  144.  
  145.         cmp     [edx + IPv4_Packet.HeaderChecksum], 0
  146.         jne     .dump                                           ; if checksum isn't valid then dump packet
  147.  
  148.         DEBUGF  1,"IPv4 Checksum is correct\n"
  149.  
  150. ;-----------------------------------
  151. ; Check if destination IP is correct
  152.  
  153.         call    NET_ptr_to_num
  154.         shl     edi, 2
  155.  
  156.         ; check if it matches local ip
  157.  
  158.         mov     eax, dword[IP_LIST+edi]
  159.         cmp     [edx + IPv4_Packet.DestinationAddress], eax
  160.         je      .ip_ok
  161.  
  162.         ; check for broadcast
  163.  
  164.         mov     eax, dword[SUBNET_LIST+edi]
  165.         not     eax
  166.         or      eax, dword[IP_LIST+edi]
  167.         cmp     [edx + IPv4_Packet.DestinationAddress], eax
  168.         je      .ip_ok
  169.  
  170.         ; or a special broadcast
  171.  
  172.         cmp     [edx + IPv4_Packet.DestinationAddress], -1
  173.         je      .ip_ok
  174.  
  175.         ; maybe it's a multicast then
  176.  
  177.         mov     eax, [edx + IPv4_Packet.DestinationAddress]
  178.         and     eax, 0xff000000
  179. ;        cmp     eax, 224 shl 24
  180. ;        je      .ip_ok
  181.  
  182.         ; or a loopback address
  183.  
  184.         cmp     eax, 127 shl 24
  185.         je      .ip_ok
  186.  
  187.         ; or it's not meant for us..
  188.  
  189.         DEBUGF  2,"Destination address does not match!\n"
  190.         jmp     .dump
  191.  
  192. ;------------------------
  193. ; Now we can update stats
  194.  
  195.   .ip_ok:
  196.         inc     [IP_PACKETS_RX+edi]
  197.  
  198. ;----------------------------------
  199. ; Check if the packet is fragmented
  200.  
  201.         test    [edx + IPv4_Packet.FlagsAndFragmentOffset], 1 shl 5     ; Is 'more fragments' flag set ?
  202.         jnz     .has_fragments                                          ; If so, we definately have a fragmented packet
  203.  
  204.         test    [edx + IPv4_Packet.FlagsAndFragmentOffset], 0xff1f      ; If flag is not set, but there is a fragment offset, the packet is last in series of fragmented packets
  205.         jnz     .is_last_fragment
  206.  
  207. ;-------------------------------------------------------------------
  208. ; No, it's just a regular IP packet, pass it to the higher protocols
  209.  
  210.   .handle_it:                                                   ; We reach here if packet hasnt been fragmented, or when it already has been re-constructed
  211.         movzx   eax, byte [edx + IPv4_Packet.VersionAndIHL]     ; Calculate Header length by using IHL field
  212.         and     eax, 0x0000000f                                 ;
  213.         shl     eax, 2                                          ;
  214.         movzx   ecx, word [edx + IPv4_Packet.TotalLength]       ; Calculate length of encapsulated Packet
  215.         xchg    cl , ch                                         ;
  216.         sub     ecx, eax                                        ;
  217.  
  218.         add     eax, edx
  219.         push    eax
  220.  
  221.         mov     esi, [edx + IPv4_Packet.SourceAddress]          ; These values might be of interest to the higher protocols
  222.         mov     edi, [edx + IPv4_Packet.DestinationAddress]     ;
  223.         mov     al , [edx + IPv4_Packet.Protocol]
  224.         pop     edx                                             ; Offset to data (tcp/udp/icmp/.. Packet)
  225.  
  226.         cmp     al , IP_PROTO_TCP
  227.         je      TCP_input
  228.  
  229.         cmp     al , IP_PROTO_UDP
  230.         je      UDP_input
  231.  
  232.         cmp     al , IP_PROTO_ICMP
  233.         je      ICMP_input
  234.  
  235.         DEBUGF  2,"unknown Internet protocol: %u\n", al
  236.  
  237.   .dump:
  238.         DEBUGF  2,"IP_Handler - dumping\n"
  239. ;        inc     [dumped_rx_count]
  240.         call    kernel_free
  241.         add     esp, 4                                          ; pop (balance stack)
  242.         ret
  243.  
  244.  
  245. ;---------------------------
  246. ; Fragmented packet handler
  247.  
  248.  
  249.   .has_fragments:
  250.         movzx   eax, [edx + IPv4_Packet.FlagsAndFragmentOffset]
  251.         xchg    al , ah
  252.         shl     ax , 3
  253.  
  254.         DEBUGF  1,"Fragmented packet, offset:%u, id:%x\n", ax, [edx + IPv4_Packet.Identification]:4
  255.  
  256.         test    ax , ax                                         ; Is this the first packet of the fragment?
  257.         jz      .is_first_fragment
  258.  
  259.  
  260. ;-------------------------------------------------------
  261. ; We have a fragmented IP packet, but it's not the first
  262.  
  263.         DEBUGF  1,"Middle fragmented packet received!\n"
  264.  
  265.         call    IPv4_find_fragment_slot
  266.         cmp     esi, -1
  267.         je      .dump
  268.  
  269.         mov     word [esi + FRAGMENT_slot.ttl], 15              ; Reset the ttl
  270.         mov     esi, [esi + FRAGMENT_slot.ptr]
  271.         or      edi, -1
  272.   .find_last_entry:                                             ; The following routine will try to find the last entry
  273.         cmp     edi, [esi + FRAGMENT_entry.PrevPtr]
  274.         jne     .destroy_slot                                   ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
  275.         mov     edi, esi
  276.         mov     esi, [esi + FRAGMENT_entry.NextPtr]
  277.         cmp     esi, -1
  278.         jne     .find_last_entry
  279.                                                                 ; We found the last entry (pointer is now in edi)
  280.                                                                 ; We are going to overwrite the ethernet header in received packet with a FRAGMENT_entry structure
  281.  
  282.         pop     eax                                             ; pointer to packet
  283.         mov     [edi + FRAGMENT_entry.NextPtr], eax             ; update pointer of previous entry to the new entry
  284.         mov     [eax + FRAGMENT_entry.NextPtr], -1
  285.         mov     [eax + FRAGMENT_entry.PrevPtr], edi
  286.         mov     [eax + FRAGMENT_entry.Owner], ebx
  287.  
  288.         add     esp, 4
  289.         ret
  290.  
  291.  
  292. ;------------------------------------
  293. ; We have received the first fragment
  294.  
  295.   .is_first_fragment:
  296.         DEBUGF  1,"First fragmented packet received!\n"
  297.                                                                 ; try to locate a free slot..
  298.         mov     ecx, MAX_FRAGMENTS
  299.         mov     esi, FRAGMENT_LIST
  300.   .find_free_slot:
  301.         cmp     word [esi + FRAGMENT_slot.ttl], 0
  302.         je      .found_free_slot
  303.         add     esi, FRAGMENT_slot.size
  304.         loop    .find_free_slot
  305.         jmp     .dump                                           ; If no free slot was found, dump the packet
  306.  
  307.   .found_free_slot:                                             ; We found a free slot, let's fill in the FRAGMENT_slot structure
  308.         mov     word [esi + FRAGMENT_slot.ttl], 15              ; RFC recommends 15 secs as ttl
  309.         mov     ax , word [edx + IPv4_Packet.Identification]
  310.         mov     word [esi + FRAGMENT_slot.id], ax
  311.         mov     eax, dword [edx + IPv4_Packet.SourceAddress]
  312.         mov     dword [esi + FRAGMENT_slot.SrcIP], eax
  313.         mov     eax, dword [edx + IPv4_Packet.DestinationAddress]
  314.         mov     dword [esi + FRAGMENT_slot.DstIP], eax
  315.         pop     eax
  316.         mov     dword [esi + FRAGMENT_slot.ptr], eax
  317.                                                                 ; Now, replace ethernet header in original buffer with a FRAGMENT_entry structure
  318.         mov     [eax + FRAGMENT_entry.NextPtr], -1
  319.         mov     [eax + FRAGMENT_entry.PrevPtr], -1
  320.         mov     [eax + FRAGMENT_entry.Owner], ebx
  321.  
  322.         add     esp, 4                                          ; balance stack and exit
  323.         ret
  324.  
  325.  
  326. ;-----------------------------------
  327. ; We have received the last fragment
  328.  
  329.   .is_last_fragment:
  330.         DEBUGF  1,"Last fragmented packet received!\n"
  331.  
  332.         call    IPv4_find_fragment_slot
  333.         cmp     esi, -1
  334.         je      .dump
  335.  
  336.         mov     esi, [esi + FRAGMENT_slot.ptr]                  ; We found the first entry, let's calculate total size of the packet in eax, so we can allocate a buffer
  337.         push    esi
  338.         xor     eax, eax
  339.         or      edi, -1
  340.  
  341.   .count_bytes:
  342.         cmp     [esi + FRAGMENT_entry.PrevPtr], edi
  343.         jne     .destroy_slot_pop                                                 ; Damn, something screwed up, remove the whole slot (and free buffers too if possible!)
  344.         mov     cx, word [esi + FRAGMENT_entry.Data + IPv4_Packet.TotalLength]    ; Add total length
  345.         xchg    cl, ch
  346.         DEBUGF  1,"Packet size: %u\n", cx
  347.         add     ax, cx
  348.         movzx   cx, byte [esi + FRAGMENT_entry.Data + IPv4_Packet.VersionAndIHL]  ; Sub Header length
  349.         and     cx, 0x000F
  350.         shl     cx, 2
  351.         DEBUGF  1,"Header size: %u\n", cx
  352.         sub     ax, cx
  353.         mov     edi, esi
  354.         mov     esi, [esi + FRAGMENT_entry.NextPtr]
  355.         cmp     esi, -1
  356.         jne     .count_bytes
  357.  
  358.         mov     esi, [esp+4]
  359.         mov     [edi + FRAGMENT_entry.NextPtr], esi                            ; Add this packet to the chain, this simplifies the following code
  360.         mov     [esi + FRAGMENT_entry.NextPtr], -1
  361.         mov     [esi + FRAGMENT_entry.PrevPtr], edi
  362.         mov     [esi + FRAGMENT_entry.Owner], ebx
  363.  
  364.         mov     cx, [edx + IPv4_Packet.TotalLength]                            ; Note: This time we dont substract Header length
  365.         xchg    cl , ch
  366.         DEBUGF  1,"Packet size: %u\n", cx
  367.         add     ax , cx
  368.         DEBUGF  1,"Total Received data size: %u\n", eax
  369.  
  370.         push    eax
  371.         mov     ax , [edx + IPv4_Packet.FlagsAndFragmentOffset]
  372.         xchg    al , ah
  373.         shl     ax , 3
  374.         add     cx , ax
  375.         pop     eax
  376.         DEBUGF  1,"Total Fragment size: %u\n", ecx
  377.  
  378.         cmp     ax, cx
  379.         jne     .destroy_slot_pop
  380.  
  381.         push    eax
  382.         push    eax
  383.         call    kernel_alloc
  384.         test    eax, eax
  385.         je      .destroy_slot_pop                                                       ; If we dont have enough space to allocate the buffer, discard all packets in slot
  386.         mov     edx, [esp+4]                                                            ; Get pointer to first fragment entry back in edx
  387.  
  388.   .rebuild_packet_loop:
  389.         movzx   ecx, word [edx + FRAGMENT_entry.Data + IPv4_Packet.FlagsAndFragmentOffset]      ; Calculate the fragment offset
  390.         xchg    cl , ch                                                                         ;  intel byte order
  391.         shl     cx , 3                                                                          ;   multiply by 8 and clear first 3 bits
  392.         DEBUGF  1,"Fragment offset: %u\n", cx
  393.  
  394.         lea     edi, [eax + ecx]                                                                ; Notice that edi will be equal to eax for first fragment
  395.         movzx   ebx, byte [edx + FRAGMENT_entry.Data + IPv4_Packet.VersionAndIHL]               ; Find header size (in ebx) of fragment
  396.         and     bx , 0x000F                                                                     ;
  397.         shl     bx , 2                                                                          ;
  398.  
  399.         lea     esi, [edx + FRAGMENT_entry.Data]                                                ; Set esi to the correct begin of fragment
  400.         movzx   ecx, word [edx + FRAGMENT_entry.Data + IPv4_Packet.TotalLength]                 ; Calculate total length of fragment
  401.         xchg    cl, ch                                                                          ;  intel byte order
  402.  
  403.         cmp     edi, eax                                                                        ; Is this packet the first fragment ?
  404.         je      .first_fragment
  405.         sub     cx, bx                                                                          ; If not, dont copy the header
  406.         add     esi, ebx                                                                        ;
  407.   .first_fragment:
  408.  
  409.         push    cx                                                                              ; First copy dword-wise, then byte-wise
  410.         shr     cx, 2                                                                           ;
  411.         rep     movsd                                                                           ;
  412.         pop     cx                                                                              ;
  413.         and     cx, 3                                                                           ;
  414.         rep     movsb                                                                           ;
  415.  
  416.         push    eax
  417.         push    edx                                                                             ; Push pointer to fragment onto stack
  418.         mov     ebx, [edx + FRAGMENT_entry.Owner]                                               ; we need to remeber the owner, in case this is the last packet
  419.         mov     edx, [edx + FRAGMENT_entry.NextPtr]                                             ; Set edx to the next pointer
  420.         call    kernel_free                                                                     ; free the previous fragment buffer (this uses the value from stack)
  421.         pop     eax
  422.         cmp     edx, -1                                                                         ; Check if it is last fragment in chain
  423.         jne     .rebuild_packet_loop
  424.  
  425.         pop     ecx                                                                             ;
  426.         xchg    cl, ch
  427.         mov     edx, eax
  428.         mov     word [edx + IPv4_Packet.TotalLength], cx
  429.         add     esp, 8
  430.  
  431.         xchg    cl, ch              ;
  432.  
  433.         push    ecx                ;;;;
  434.         push    eax                ;;;;
  435.  
  436. ;        mov     esi, edx           ;  This prints the IP packet to the debug board (usefull when using serial output debug..)
  437. ;                                   ;
  438. ;       @@:                         ;
  439. ;        lodsb                      ;
  440. ;        DEBUGF  1,"%x ", eax:2     ;
  441. ;        loop    @r                 ;
  442.  
  443.         jmp     .handle_it          ; edx = buf ptr, ecx = size, [esp] buf ptr, [esp+4], total size, ebx=device ptr
  444.  
  445.   .destroy_slot_pop:
  446.         add     esp, 4
  447.   .destroy_slot:
  448.         DEBUGF  1,"Destroy fragment slot!\n"
  449.         ; TODO!
  450.         jmp     .dump
  451.  
  452.  
  453.  
  454.  
  455. ;-----------------------------------
  456. ; The IP packet has some options
  457.  
  458.   .has_options:
  459.         jmp     .dump
  460.  
  461.  
  462.  
  463.  
  464.  
  465.  
  466. ;-----------------------------------------------------------------
  467. ;
  468. ; find fragment slot
  469. ;
  470. ; IN: pointer to fragmented packet in edx
  471. ; OUT: pointer to slot in edi, -1 on error
  472. ;
  473. ;-----------------------------------------------------------------
  474. align 4
  475. IPv4_find_fragment_slot:
  476.  
  477. ;;; TODO: the RFC says we should check protocol number too
  478.  
  479.         push    eax ebx ecx edx
  480.         mov     ax , word [edx + IPv4_Packet.Identification]
  481.         mov     ecx, MAX_FRAGMENTS
  482.         mov     esi, FRAGMENT_LIST
  483.         mov     ebx, dword [edx + IPv4_Packet.SourceAddress]
  484.         mov     edx, dword [edx + IPv4_Packet.DestinationAddress]
  485.   .find_slot:
  486.         cmp     word [esi + FRAGMENT_slot.id], ax
  487.         jne     .try_next
  488.         cmp     dword [esi + FRAGMENT_slot.SrcIP], ebx
  489.         jne     .try_next
  490.         cmp     dword [esi + FRAGMENT_slot.DstIP], edx
  491.         je      .found_slot
  492.   .try_next:
  493.         add     esi, FRAGMENT_slot.size
  494.         loop    .find_slot
  495. ;        pop     edx ebx
  496.         or      esi, -1
  497. ;        ret
  498.  
  499.   .found_slot:
  500.         pop     edx ecx ebx eax
  501.         ret
  502.  
  503.  
  504. ;-----------------------------------------------------------------
  505. ;
  506. ; Decrease TimeToLive of all fragment slots
  507. ;
  508. ; IN: /
  509. ; OUT: /
  510. ;
  511. ;-----------------------------------------------------------------
  512. align 4
  513. IPv4_decrease_fragment_ttls:
  514.  
  515.         mov     esi, FRAGMENT_LIST
  516.         mov     ecx, MAX_FRAGMENTS
  517.   .loop:
  518.         cmp     [esi + FRAGMENT_slot.ttl], 0
  519.         je      .try_next
  520.         dec     [esi + FRAGMENT_slot.ttl]
  521.         jnz     .try_next
  522.         DEBUGF 1,"Fragment slot timed-out!\n"
  523. ;;; TODO: clear all entry's of timed-out slot
  524.   .try_next:
  525.         add     esi, 4
  526.         loop    .loop
  527.         ret
  528.  
  529.  
  530.  
  531.  
  532.  
  533. ;------------------------------------------------------------------
  534. ;
  535. ;
  536. ; IN: dword [esp] = pointer to packet to be fragmented
  537. ;     dword [esp+4] = buffer size
  538. ;     edx = pointer to IPv4 header in that packet
  539. ;     ecx = data length
  540. ;     ebx = device structure
  541. ;
  542. ; OUT: /
  543. ;
  544. ;------------------------------------------------------------------
  545. align 4
  546. IPv4_fragment:
  547.  
  548. ;;; TODO: write code here
  549.  
  550.  
  551.         call    kernel_free
  552.         add     esp, 4
  553.  
  554.         ret
  555.  
  556.  
  557.  
  558.  
  559. ;------------------------------------------------------------------
  560. ;
  561. ; Create_IPv4_Packet
  562. ;
  563. ; IN: eax = dest ip
  564. ;     ebx = source ip
  565. ;     ecx = data length
  566. ;     dx  = fragment id  ;;;;
  567. ;     di  = protocol
  568. ;
  569. ; OUT: eax = pointer to buffer start
  570. ;      ebx = pointer to device struct (needed for sending procedure)
  571. ;      ecx = unchanged (packet size of embedded data)
  572. ;      edx = size of complete buffer
  573. ;      edi = pointer to start of data (0 on error)
  574. ;
  575. ;------------------------------------------------------------------
  576. align 4
  577. IPv4_create_packet:
  578.  
  579.         DEBUGF 1,"Create IPv4 Packet (size=%u)\n", ecx
  580.  
  581.         cmp     ecx, 65500            ; Max IPv4 packet size
  582.         jg      .exit_
  583.  
  584.         test    ebx, ebx              ; if source ip = 0
  585.         jnz     .ip_ok                ; and local ip is valid
  586.                                       ; use local ip instead
  587.         cmp     [IP_LIST],0xffffffff  ;
  588.         je      .ip_ok                ; TODO: find solution to send broadcast
  589.                                       ;  on device other then device 0
  590.         mov     ebx, [IP_LIST]        ;
  591.                                       ;
  592.   .ip_ok:                             ;
  593.  
  594.         push    ecx eax ebx dx di
  595.  
  596.         cmp     eax, -1
  597.         je      .broadcast              ; If it is broadcast, just send
  598.  
  599.         call    ARP_IP_to_MAC
  600.  
  601.         cmp     eax, -1
  602.         je      .not_found
  603.  
  604.         push    ebx
  605.         push    ax
  606.  
  607.         jmp     .send
  608.  
  609.   .broadcast:
  610.         push    word -1
  611.         push    dword -1
  612.  
  613.   .send:
  614.         call    IPv4_dest_to_dev
  615.         inc     [IP_PACKETS_TX+4*edi]
  616.         mov     edx, [NET_DRV_LIST + 4*edi]
  617.         lea     eax, [edx + ETH_DEVICE.mac]
  618.         mov     ebx, esp
  619.         mov     ecx, [esp+18]    ;; 18 or  22 ??
  620.         add     ecx, IPv4_Packet.DataOrOptional
  621.         mov     di , ETHER_IPv4
  622.         ;;; TODO: detect if packet is too large for ethernet, if so, call IPv4_fragment
  623.         call    ETH_create_packet                  ;;; TODO: figure out a way to make this work with other protocols too
  624.         add     esp, 6
  625.         test    edi, edi
  626.         jz      .exit
  627.  
  628.         mov     [edi + IPv4_Packet.VersionAndIHL], 0x45   ; IPv4, normal length (no Optional header)
  629.         mov     [edi + IPv4_Packet.TypeOfService], 0
  630.         xchg    ch, cl
  631.         mov     [edi + IPv4_Packet.TotalLength], cx
  632.         mov     [edi + IPv4_Packet.FlagsAndFragmentOffset], 0x0000
  633.         mov     [edi + IPv4_Packet.TimeToLive], 128
  634.         mov     [edi + IPv4_Packet.HeaderChecksum], 0
  635.         pop     cx
  636.         mov     [edi + IPv4_Packet.Protocol], cl
  637.         pop     cx
  638.         mov     [edi + IPv4_Packet.Identification], cx
  639.         pop     ecx
  640.         mov     [edi + IPv4_Packet.SourceAddress], ecx
  641.         pop     ecx
  642.         mov     [edi + IPv4_Packet.DestinationAddress], ecx
  643.  
  644.         push    eax edx esi
  645.         mov     esi, edi
  646.         call    IPv4_checksum
  647.         pop     esi edx eax ecx
  648.         add     edi, IPv4_Packet.DataOrOptional
  649.  
  650.         DEBUGF  1,"IPv4 Packet for device %x created successfully\n", ebx
  651.  
  652.         ret
  653.  
  654.  
  655.   .not_found:
  656.         DEBUGF  1,"Create IPv4 Packet - ARP entry not found!\n"
  657.         ;;;;;;
  658.   .exit:
  659.         add     esp, 16
  660.   .exit_:
  661.         DEBUGF  1,"Create IPv4 Packet - failed\n"
  662.         and     edi, 0
  663.         ret
  664.  
  665.  
  666.  
  667. align 4
  668. IPv4_checksum:
  669.  
  670. ; This is the fast procedure to create or check a IP header without options
  671. ;
  672. ; To create a new checksum, the checksum field must be set to 0 before computation
  673. ;
  674. ; To check an existing checksum, leave the checksum as is, and it will be 0 after this procedure, if it was correct
  675.  
  676.         xor     edx, edx
  677.  
  678.         add     dl, [esi+1]
  679.         adc     dh, [esi+0]
  680.  
  681.         adc     dl, [esi+3]
  682.         adc     dh, [esi+2]
  683.  
  684.         adc     dl, [esi+5]
  685.         adc     dh, [esi+4]
  686.  
  687.         adc     dl, [esi+7]
  688.         adc     dh, [esi+6]
  689.  
  690.         adc     dl, [esi+9]
  691.         adc     dh, [esi+8]
  692.  
  693. ; we skip 11th and 12th byte, they are the checksum bytes and should be 0 for re-calculation
  694.  
  695.         adc     dl, [esi+13]
  696.         adc     dh, [esi+12]
  697.  
  698.         adc     dl, [esi+15]
  699.         adc     dh, [esi+14]
  700.  
  701.         adc     dl, [esi+17]
  702.         adc     dh, [esi+16]
  703.  
  704.         adc     dl, [esi+19]
  705.         adc     dh, [esi+18]
  706.  
  707.         adc     edx, 0
  708.  
  709.         call    checksum_2
  710.  
  711.         neg     word [esi+10]           ; zero will stay zero so we just get the checksum
  712.         add     word [esi+10], dx       ;  , else we will get (new checksum - old checksum) in the end, wich should be 0 :)
  713.  
  714.         ret
  715.  
  716.  
  717.  
  718.  
  719.  
  720. ;---------------------------------------------------------------------------
  721. ;
  722. ; IPv4_dest_to_dev
  723. ;
  724. ; IN: Destination IP in eax
  725. ; OUT: device id in edi
  726. ;
  727. ;---------------------------------------------------------------------------
  728. align 4
  729. IPv4_dest_to_dev:
  730.  
  731.         DEBUGF 1,"IPv4 destination to device: "
  732.  
  733.         xor     edi, edi
  734.         mov     ecx, MAX_IP
  735.  
  736.   .loop:
  737.         mov     ebx, [IP_LIST+edi]              ; we dont need to worry about non exisiting ip interfaces
  738.         and     ebx, [SUBNET_LIST+edi]          ; they have IP and SUBNET set to all one's, so they will have no match except 255.255.255.255
  739.                                                 ; (only a moron would insert that ip into this function..)
  740.         mov     edx, eax
  741.         and     edx, [SUBNET_LIST+edi]
  742.  
  743.         cmp     ebx, edx
  744.         je      .found_it
  745.  
  746.         add     edi, 4
  747.         loop    .loop
  748.  
  749.         xor     edi, edi        ; if none found, use device 0 as default device
  750.  
  751.   .found_it:
  752.         shr     edi, 2
  753.  
  754.         DEBUGF  1,"%u\n",edi
  755.  
  756.         ret
  757.  
  758.  
  759.  
  760. ;---------------------------------------------------------------------------
  761. ;
  762. ; IPv4_get_frgmnt_num
  763. ;
  764. ; IN: /
  765. ; OUT: fragment number in ax
  766. ;
  767. ;---------------------------------------------------------------------------
  768. align 4
  769. IPv4_get_frgmnt_num:
  770.         xor     ax, ax  ;;; TODO: replace this with real code
  771.  
  772.         ret
  773.  
  774.  
  775. ;---------------------------------------------------------------------------
  776. ;
  777. ; IPv4_API
  778. ;
  779. ; This function is called by system function 75
  780. ;
  781. ; IN:  subfunction number in bl
  782. ;      device number in bh
  783. ;      ecx, edx, .. depends on subfunction
  784. ;
  785. ; OUT:
  786. ;
  787. ;---------------------------------------------------------------------------
  788. align 4
  789. IPv4_API:
  790.  
  791.         movzx   eax, bh
  792.         shl     eax, 2
  793.  
  794.         test    bl, bl
  795.         jz      .packets_tx     ; 0
  796.         dec     bl
  797.         jz      .packets_rx     ; 1
  798.         dec     bl
  799.         jz      .read_ip        ; 2
  800.         dec     bl
  801.         jz      .write_ip       ; 3
  802.         dec     bl
  803.         jz      .read_dns       ; 4
  804.         dec     bl
  805.         jz      .write_dns      ; 5
  806.         dec     bl
  807.         jz      .read_subnet    ; 6
  808.         dec     bl
  809.         jz      .write_subnet   ; 7
  810.         dec     bl
  811.         jz      .read_gateway   ; 8
  812.         dec     bl
  813.         jz      .write_gateway  ; 9
  814.  
  815.   .error:
  816.         mov     eax, -1
  817.         ret
  818.  
  819.   .packets_tx:
  820.         add     eax, IP_PACKETS_TX
  821.         mov     eax, [eax]
  822.         ret
  823.  
  824.   .packets_rx:
  825.         add     eax, IP_PACKETS_RX
  826.         mov     eax, [eax]
  827.         ret
  828.  
  829.   .read_ip:
  830.         add     eax, IP_LIST
  831.         mov     eax, [eax]
  832.         ret
  833.  
  834.   .write_ip:
  835.         add     eax, IP_LIST
  836.         mov     [eax], ecx
  837.         xor     eax, eax
  838.         ret
  839.  
  840.   .read_dns:
  841.         add     eax, DNS_LIST
  842.         mov     eax, [eax]
  843.         ret
  844.  
  845.   .write_dns:
  846.         add     eax, DNS_LIST
  847.         mov     [eax], ecx
  848.         xor     eax, eax
  849.         ret
  850.  
  851.   .read_subnet:
  852.         add     eax, SUBNET_LIST
  853.         mov     eax, [eax]
  854.         ret
  855.  
  856.   .write_subnet:
  857.         add     eax, SUBNET_LIST
  858.         mov     [eax], ecx
  859.         xor     eax, eax
  860.         ret
  861.  
  862.   .read_gateway:
  863.         add     eax, GATEWAY_LIST
  864.         mov     eax, [eax]
  865.         ret
  866.  
  867.   .write_gateway:
  868.         add     eax, GATEWAY_LIST
  869.         mov     [eax], ecx
  870.         xor     eax, eax
  871.         ret
  872.  
  873.  
  874.  
  875.  
  876.