Serenity Operating System
at portability 167 lines 6.1 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) 50{ 51 if (target[0] == 127) 52 return { LoopbackAdapter::the(), LoopbackAdapter::the().mac_address() }; 53 54 auto target_addr = target.to_u32(); 55 auto source_addr = source.to_u32(); 56 57 RefPtr<NetworkAdapter> local_adapter = nullptr; 58 RefPtr<NetworkAdapter> gateway_adapter = nullptr; 59 60 NetworkAdapter::for_each([source_addr, &target_addr, &local_adapter, &gateway_adapter](auto& adapter) { 61 auto adapter_addr = adapter.ipv4_address().to_u32(); 62 auto adapter_mask = adapter.ipv4_netmask().to_u32(); 63 64 if (source_addr != 0 && source_addr != adapter_addr) 65 return; 66 67 if ((target_addr & adapter_mask) == (adapter_addr & adapter_mask)) 68 local_adapter = adapter; 69 70 if (adapter.ipv4_gateway().to_u32() != 0) 71 gateway_adapter = adapter; 72 }); 73 74 if (local_adapter && target == local_adapter->ipv4_address()) 75 return { local_adapter, local_adapter->mac_address() }; 76 77 if (!local_adapter && !gateway_adapter) { 78#ifdef ROUTING_DEBUG 79 kprintf("Routing: Couldn't find a suitable adapter for route to %s\n", 80 target.to_string().characters()); 81#endif 82 return { nullptr, {} }; 83 } 84 85 RefPtr<NetworkAdapter> adapter = nullptr; 86 IPv4Address next_hop_ip; 87 88 if (local_adapter) { 89#ifdef ROUTING_DEBUG 90 kprintf("Routing: Got adapter for route (direct): %s (%s/%s) for %s\n", 91 local_adapter->name().characters(), 92 local_adapter->ipv4_address().to_string().characters(), 93 local_adapter->ipv4_netmask().to_string().characters(), 94 target.to_string().characters()); 95#endif 96 adapter = local_adapter; 97 next_hop_ip = target; 98 } else if (gateway_adapter) { 99#ifdef ROUTING_DEBUG 100 kprintf("Routing: Got adapter for route (using gateway %s): %s (%s/%s) for %s\n", 101 gateway_adapter->ipv4_gateway().to_string().characters(), 102 gateway_adapter->name().characters(), 103 gateway_adapter->ipv4_address().to_string().characters(), 104 gateway_adapter->ipv4_netmask().to_string().characters(), 105 target.to_string().characters()); 106#endif 107 adapter = gateway_adapter; 108 next_hop_ip = gateway_adapter->ipv4_gateway(); 109 } else { 110 return { nullptr, {} }; 111 } 112 113 { 114 LOCKER(arp_table().lock()); 115 auto addr = arp_table().resource().get(next_hop_ip); 116 if (addr.has_value()) { 117#ifdef ROUTING_DEBUG 118 kprintf("Routing: Using cached ARP entry for %s (%s)\n", 119 next_hop_ip.to_string().characters(), 120 addr.value().to_string().characters()); 121#endif 122 return { adapter, addr.value() }; 123 } 124 } 125 126#ifdef ROUTING_DEBUG 127 kprintf("Routing: Sending ARP request via adapter %s for IPv4 address %s\n", 128 adapter->name().characters(), 129 next_hop_ip.to_string().characters()); 130#endif 131 132 ARPPacket request; 133 request.set_operation(ARPOperation::Request); 134 request.set_target_hardware_address({ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }); 135 request.set_target_protocol_address(next_hop_ip); 136 request.set_sender_hardware_address(adapter->mac_address()); 137 request.set_sender_protocol_address(adapter->ipv4_address()); 138 adapter->send({ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, request); 139 140 (void)Thread::current->block_until("Routing (ARP)", [next_hop_ip] { 141 return arp_table().resource().get(next_hop_ip).has_value(); 142 }); 143 144 { 145 LOCKER(arp_table().lock()); 146 auto addr = arp_table().resource().get(next_hop_ip); 147 if (addr.has_value()) { 148#ifdef ROUTING_DEBUG 149 kprintf("Routing: Got ARP response using adapter %s for %s (%s)\n", 150 adapter->name().characters(), 151 next_hop_ip.to_string().characters(), 152 addr.value().to_string().characters()); 153#endif 154 return { adapter, addr.value() }; 155 } 156 } 157 158#ifdef ROUTING_DEBUG 159 kprintf("Routing: Couldn't find route using adapter %s for %s\n", 160 adapter->name().characters(), 161 target.to_string().characters()); 162#endif 163 164 return { nullptr, {} }; 165} 166 167}