Subversion Repositories Kolibri OS

Rev

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