Serenity Operating System
at hosted 160 lines 6.3 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include <AK/HashMap.h> 28#include <Kernel/Net/LoopbackAdapter.h> 29#include <Kernel/Net/Routing.h> 30#include <Kernel/Thread.h> 31 32//#define ROUTING_DEBUG 33 34namespace Kernel { 35 36Lockable<HashMap<IPv4Address, MACAddress>>& arp_table() 37{ 38 static Lockable<HashMap<IPv4Address, MACAddress>>* the; 39 if (!the) 40 the = new Lockable<HashMap<IPv4Address, MACAddress>>; 41 return *the; 42} 43 44bool RoutingDecision::is_zero() const 45{ 46 return adapter.is_null() || next_hop.is_zero(); 47} 48 49RoutingDecision route_to(const IPv4Address& target, const IPv4Address& source, const RefPtr<NetworkAdapter> through) 50{ 51 auto matches = [&](auto& adapter) { 52 if (!through) 53 return true; 54 55 return through == adapter; 56 }; 57 auto if_matches = [&](auto& adapter, const auto& mac) -> RoutingDecision { 58 if (!matches(adapter)) 59 return { nullptr, {} }; 60 return { adapter, mac }; 61 }; 62 63 if (target[0] == 127) 64 return if_matches(LoopbackAdapter::the(), LoopbackAdapter::the().mac_address()); 65 66 auto target_addr = target.to_u32(); 67 auto source_addr = source.to_u32(); 68 69 RefPtr<NetworkAdapter> local_adapter = nullptr; 70 RefPtr<NetworkAdapter> gateway_adapter = nullptr; 71 72 NetworkAdapter::for_each([source_addr, &target_addr, &local_adapter, &gateway_adapter, &matches](auto& adapter) { 73 auto adapter_addr = adapter.ipv4_address().to_u32(); 74 auto adapter_mask = adapter.ipv4_netmask().to_u32(); 75 76 if (source_addr != 0 && source_addr != adapter_addr) 77 return; 78 79 if ((target_addr & adapter_mask) == (adapter_addr & adapter_mask) && matches(adapter)) 80 local_adapter = adapter; 81 82 if (adapter.ipv4_gateway().to_u32() != 0 && matches(adapter)) 83 gateway_adapter = adapter; 84 }); 85 86 if (local_adapter && target == local_adapter->ipv4_address()) 87 return { local_adapter, local_adapter->mac_address() }; 88 89 if (!local_adapter && !gateway_adapter) { 90#ifdef ROUTING_DEBUG 91 klog() << "Routing: Couldn't find a suitable adapter for route to " << target.to_string().characters(); 92#endif 93 return { nullptr, {} }; 94 } 95 96 RefPtr<NetworkAdapter> adapter = nullptr; 97 IPv4Address next_hop_ip; 98 99 if (local_adapter) { 100#ifdef ROUTING_DEBUG 101 klog() << "Routing: Got adapter for route (direct): " << local_adapter->name().characters() << " (" << local_adapter->ipv4_address().to_string().characters() << "/" << local_adapter->ipv4_netmask().to_string().characters() << ") for " << target.to_string().characters(); 102#endif 103 adapter = local_adapter; 104 next_hop_ip = target; 105 } else if (gateway_adapter) { 106#ifdef ROUTING_DEBUG 107 klog() << "Routing: Got adapter for route (using gateway " << gateway_adapter->ipv4_gateway().to_string().characters() << "): " << gateway_adapter->name().characters() << " (" << gateway_adapter->ipv4_address().to_string().characters() << "/" << gateway_adapter->ipv4_netmask().to_string().characters() << ") for " << target.to_string().characters(); 108#endif 109 adapter = gateway_adapter; 110 next_hop_ip = gateway_adapter->ipv4_gateway(); 111 } else { 112 return { nullptr, {} }; 113 } 114 115 { 116 LOCKER(arp_table().lock()); 117 auto addr = arp_table().resource().get(next_hop_ip); 118 if (addr.has_value()) { 119#ifdef ROUTING_DEBUG 120 klog() << "Routing: Using cached ARP entry for " << next_hop_ip.to_string().characters() << " (" << addr.value().to_string().characters() << ")"; 121#endif 122 return { adapter, addr.value() }; 123 } 124 } 125 126#ifdef ROUTING_DEBUG 127 klog() << "Routing: Sending ARP request via adapter " << adapter->name().characters() << " for IPv4 address " << next_hop_ip.to_string().characters(); 128#endif 129 130 ARPPacket request; 131 request.set_operation(ARPOperation::Request); 132 request.set_target_hardware_address({ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }); 133 request.set_target_protocol_address(next_hop_ip); 134 request.set_sender_hardware_address(adapter->mac_address()); 135 request.set_sender_protocol_address(adapter->ipv4_address()); 136 adapter->send({ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, request); 137 138 (void)Thread::current->block_until("Routing (ARP)", [next_hop_ip] { 139 return arp_table().resource().get(next_hop_ip).has_value(); 140 }); 141 142 { 143 LOCKER(arp_table().lock()); 144 auto addr = arp_table().resource().get(next_hop_ip); 145 if (addr.has_value()) { 146#ifdef ROUTING_DEBUG 147 klog() << "Routing: Got ARP response using adapter " << adapter->name().characters() << " for " << next_hop_ip.to_string().characters() << " (" << addr.value().to_string().characters() << ")"; 148#endif 149 return { adapter, addr.value() }; 150 } 151 } 152 153#ifdef ROUTING_DEBUG 154 klog() << "Routing: Couldn't find route using adapter " << adapter->name().characters() << " for " << target.to_string().characters(); 155#endif 156 157 return { nullptr, {} }; 158} 159 160}