Subversion Repositories Kolibri OS

Rev

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

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