Subversion Repositories Kolibri OS

Rev

Rev 1473 | Blame | Last modification | View Log | Download | RSS feed

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