1c22d69bfSAxel Dörfler /* 23c13a5f5SAxel Dörfler * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. 3c22d69bfSAxel Dörfler * Distributed under the terms of the MIT License. 4c22d69bfSAxel Dörfler * 5c22d69bfSAxel Dörfler * Authors: 6c22d69bfSAxel Dörfler * Axel Dörfler, axeld@pinc-software.de 7c22d69bfSAxel Dörfler */ 8c22d69bfSAxel Dörfler 9c22d69bfSAxel Dörfler 10c22d69bfSAxel Dörfler #include "domains.h" 11c22d69bfSAxel Dörfler #include "interfaces.h" 12409b1fc0SHugo Santos #include "utility.h" 13fb300cfdSHugo Santos #include "stack_private.h" 14c22d69bfSAxel Dörfler 159206bb37SAxel Dörfler #include <net_device.h> 16c22d69bfSAxel Dörfler 17c22d69bfSAxel Dörfler #include <lock.h> 18c22d69bfSAxel Dörfler #include <util/AutoLock.h> 19c22d69bfSAxel Dörfler 209206bb37SAxel Dörfler #include <KernelExport.h> 219206bb37SAxel Dörfler 229206bb37SAxel Dörfler #include <net/if_media.h> 23c22d69bfSAxel Dörfler #include <new> 24c22d69bfSAxel Dörfler #include <string.h> 25fb300cfdSHugo Santos #include <sys/sockio.h> 26c22d69bfSAxel Dörfler 27c22d69bfSAxel Dörfler 28c22d69bfSAxel Dörfler #define TRACE_DOMAINS 29c22d69bfSAxel Dörfler #ifdef TRACE_DOMAINS 30c22d69bfSAxel Dörfler # define TRACE(x) dprintf x 31c22d69bfSAxel Dörfler #else 32c22d69bfSAxel Dörfler # define TRACE(x) ; 33c22d69bfSAxel Dörfler #endif 34c22d69bfSAxel Dörfler 352b07b8e0SIngo Weinhold static mutex sDomainLock; 36c22d69bfSAxel Dörfler static list sDomains; 37c22d69bfSAxel Dörfler 38c22d69bfSAxel Dörfler 39*26153d0fSAxel Dörfler /*! Scans the domain list for the specified family. 40c22d69bfSAxel Dörfler You need to hold the sDomainLock when calling this function. 41c22d69bfSAxel Dörfler */ 42c22d69bfSAxel Dörfler static net_domain_private* 43c22d69bfSAxel Dörfler lookup_domain(int family) 44c22d69bfSAxel Dörfler { 45c22d69bfSAxel Dörfler net_domain_private* domain = NULL; 46c22d69bfSAxel Dörfler while (true) { 47c22d69bfSAxel Dörfler domain = (net_domain_private*)list_get_next_item(&sDomains, domain); 48c22d69bfSAxel Dörfler if (domain == NULL) 49c22d69bfSAxel Dörfler break; 50c22d69bfSAxel Dörfler 51c22d69bfSAxel Dörfler if (domain->family == family) 52c22d69bfSAxel Dörfler return domain; 53c22d69bfSAxel Dörfler } 54c22d69bfSAxel Dörfler 55c22d69bfSAxel Dörfler return NULL; 56c22d69bfSAxel Dörfler } 57c22d69bfSAxel Dörfler 58c22d69bfSAxel Dörfler 59c22d69bfSAxel Dörfler // #pragma mark - 60c22d69bfSAxel Dörfler 61c22d69bfSAxel Dörfler 62*26153d0fSAxel Dörfler /*! Gets the domain of the specified family. 63c22d69bfSAxel Dörfler */ 64c22d69bfSAxel Dörfler net_domain* 65c22d69bfSAxel Dörfler get_domain(int family) 66c22d69bfSAxel Dörfler { 672b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 68c22d69bfSAxel Dörfler return lookup_domain(family); 69c22d69bfSAxel Dörfler } 70c22d69bfSAxel Dörfler 71c22d69bfSAxel Dörfler 72c22d69bfSAxel Dörfler uint32 73c22d69bfSAxel Dörfler count_domain_interfaces() 74c22d69bfSAxel Dörfler { 752b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 76c22d69bfSAxel Dörfler 77c22d69bfSAxel Dörfler net_domain_private* domain = NULL; 78c22d69bfSAxel Dörfler uint32 count = 0; 79c22d69bfSAxel Dörfler 80c22d69bfSAxel Dörfler while (true) { 81c22d69bfSAxel Dörfler domain = (net_domain_private*)list_get_next_item(&sDomains, domain); 82c22d69bfSAxel Dörfler if (domain == NULL) 83c22d69bfSAxel Dörfler break; 84c22d69bfSAxel Dörfler 85c22d69bfSAxel Dörfler net_interface* interface = NULL; 86c22d69bfSAxel Dörfler while (true) { 87c22d69bfSAxel Dörfler interface = (net_interface*)list_get_next_item(&domain->interfaces, 88c22d69bfSAxel Dörfler interface); 89c22d69bfSAxel Dörfler if (interface == NULL) 90c22d69bfSAxel Dörfler break; 91c22d69bfSAxel Dörfler 92c22d69bfSAxel Dörfler count++; 93c22d69bfSAxel Dörfler } 94c22d69bfSAxel Dörfler } 95c22d69bfSAxel Dörfler 96c22d69bfSAxel Dörfler return count; 97c22d69bfSAxel Dörfler } 98c22d69bfSAxel Dörfler 99c22d69bfSAxel Dörfler 100c22d69bfSAxel Dörfler /*! 101c22d69bfSAxel Dörfler Dumps a list of all interfaces into the supplied userland buffer. 102c22d69bfSAxel Dörfler If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is 103c22d69bfSAxel Dörfler returned. 104c22d69bfSAxel Dörfler */ 105c22d69bfSAxel Dörfler status_t 106409b1fc0SHugo Santos list_domain_interfaces(void* _buffer, size_t* bufferSize) 107c22d69bfSAxel Dörfler { 1082b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 109c22d69bfSAxel Dörfler 110409b1fc0SHugo Santos UserBuffer buffer(_buffer, *bufferSize); 111c22d69bfSAxel Dörfler net_domain_private* domain = NULL; 112c22d69bfSAxel Dörfler 113c22d69bfSAxel Dörfler while (true) { 114c22d69bfSAxel Dörfler domain = (net_domain_private*)list_get_next_item(&sDomains, domain); 115c22d69bfSAxel Dörfler if (domain == NULL) 116c22d69bfSAxel Dörfler break; 117c22d69bfSAxel Dörfler 118*26153d0fSAxel Dörfler RecursiveLocker locker(domain->lock); 1199206bb37SAxel Dörfler 120c22d69bfSAxel Dörfler net_interface* interface = NULL; 121c22d69bfSAxel Dörfler while (true) { 122c22d69bfSAxel Dörfler interface = (net_interface*)list_get_next_item(&domain->interfaces, 123c22d69bfSAxel Dörfler interface); 124c22d69bfSAxel Dörfler if (interface == NULL) 125c22d69bfSAxel Dörfler break; 126c22d69bfSAxel Dörfler 127c22d69bfSAxel Dörfler ifreq request; 128c22d69bfSAxel Dörfler strlcpy(request.ifr_name, interface->name, IF_NAMESIZE); 1299206bb37SAxel Dörfler if (interface->address != NULL) { 1309206bb37SAxel Dörfler memcpy(&request.ifr_addr, interface->address, 1319206bb37SAxel Dörfler interface->address->sa_len); 1329206bb37SAxel Dörfler } else { 133c22d69bfSAxel Dörfler // empty address 134c22d69bfSAxel Dörfler request.ifr_addr.sa_len = 2; 135c22d69bfSAxel Dörfler request.ifr_addr.sa_family = AF_UNSPEC; 136c22d69bfSAxel Dörfler } 137c22d69bfSAxel Dörfler 138409b1fc0SHugo Santos if (buffer.Copy(&request, IF_NAMESIZE 139409b1fc0SHugo Santos + request.ifr_addr.sa_len) == NULL) 140409b1fc0SHugo Santos return buffer.Status(); 141c22d69bfSAxel Dörfler } 142c22d69bfSAxel Dörfler } 143c22d69bfSAxel Dörfler 144409b1fc0SHugo Santos *bufferSize = buffer.ConsumedAmount(); 145c22d69bfSAxel Dörfler return B_OK; 146c22d69bfSAxel Dörfler } 147c22d69bfSAxel Dörfler 148c22d69bfSAxel Dörfler 149c22d69bfSAxel Dörfler status_t 150c22d69bfSAxel Dörfler add_interface_to_domain(net_domain* _domain, 151c22d69bfSAxel Dörfler struct ifreq& request) 152c22d69bfSAxel Dörfler { 153c22d69bfSAxel Dörfler net_domain_private* domain = (net_domain_private*)_domain; 154c22d69bfSAxel Dörfler 155c22d69bfSAxel Dörfler const char* deviceName = request.ifr_parameter.device[0] 156c22d69bfSAxel Dörfler ? request.ifr_parameter.device : request.ifr_name; 15720b534cdSHugo Santos const char* baseName = request.ifr_parameter.base_name[0] 15820b534cdSHugo Santos ? request.ifr_parameter.base_name : request.ifr_name; 15920b534cdSHugo Santos 160c22d69bfSAxel Dörfler net_device_interface* deviceInterface = get_device_interface(deviceName); 161c22d69bfSAxel Dörfler if (deviceInterface == NULL) 162c22d69bfSAxel Dörfler return ENODEV; 163c22d69bfSAxel Dörfler 164*26153d0fSAxel Dörfler RecursiveLocker locker(domain->lock); 165c22d69bfSAxel Dörfler 16620b534cdSHugo Santos net_interface_private* interface = NULL; 16720b534cdSHugo Santos status_t status; 16820b534cdSHugo Santos 169a3513e7bSAxel Dörfler if (find_interface(domain, request.ifr_name) == NULL) { 170a3513e7bSAxel Dörfler // We must not hold the domain's link when creating the interface: 171a3513e7bSAxel Dörfler // this will call get_module() which might want to access a network 172a3513e7bSAxel Dörfler // device when booting from network. 173a3513e7bSAxel Dörfler locker.Unlock(); 17420b534cdSHugo Santos status = create_interface(domain, request.ifr_name, 17520b534cdSHugo Santos baseName, deviceInterface, &interface); 176a3513e7bSAxel Dörfler locker.Lock(); 177a3513e7bSAxel Dörfler 178a3513e7bSAxel Dörfler if (find_interface(domain, request.ifr_name) != NULL) { 179a3513e7bSAxel Dörfler delete_interface(interface); 180a3513e7bSAxel Dörfler status = B_NAME_IN_USE; 181a3513e7bSAxel Dörfler } 182a3513e7bSAxel Dörfler } else 183a3513e7bSAxel Dörfler status = B_NAME_IN_USE; 184c22d69bfSAxel Dörfler 185c22d69bfSAxel Dörfler put_device_interface(deviceInterface); 186c22d69bfSAxel Dörfler 187d68ffdedSAxel Dörfler if (status == B_OK) { 188c22d69bfSAxel Dörfler list_add_item(&domain->interfaces, interface); 189d68ffdedSAxel Dörfler notify_interface_added(interface); 190d68ffdedSAxel Dörfler } 19120b534cdSHugo Santos 19220b534cdSHugo Santos return status; 193c22d69bfSAxel Dörfler } 194c22d69bfSAxel Dörfler 195c22d69bfSAxel Dörfler 196c22d69bfSAxel Dörfler /*! 197c22d69bfSAxel Dörfler Removes the interface from its domain, and deletes it. 198c22d69bfSAxel Dörfler You need to hold the domain's lock when calling this function. 199c22d69bfSAxel Dörfler */ 200c22d69bfSAxel Dörfler status_t 201c22d69bfSAxel Dörfler remove_interface_from_domain(net_interface* interface) 202c22d69bfSAxel Dörfler { 203c22d69bfSAxel Dörfler net_domain_private* domain = (net_domain_private*)interface->domain; 204c22d69bfSAxel Dörfler 205c22d69bfSAxel Dörfler list_remove_item(&domain->interfaces, interface); 206d68ffdedSAxel Dörfler notify_interface_removed(interface); 207c22d69bfSAxel Dörfler delete_interface((net_interface_private*)interface); 208c22d69bfSAxel Dörfler return B_OK; 209c22d69bfSAxel Dörfler } 210c22d69bfSAxel Dörfler 211c22d69bfSAxel Dörfler 212fb300cfdSHugo Santos status_t 213fb300cfdSHugo Santos domain_interface_control(net_domain_private* domain, int32 option, 214fb300cfdSHugo Santos ifreq* request) 215fb300cfdSHugo Santos { 216fb300cfdSHugo Santos const char* name = request->ifr_name; 217fb300cfdSHugo Santos status_t status = B_OK; 218fb300cfdSHugo Santos 219fb300cfdSHugo Santos net_device_interface* device = get_device_interface(name, false); 220fb300cfdSHugo Santos if (device == NULL) 221fb300cfdSHugo Santos return ENODEV; 2223c13a5f5SAxel Dörfler 2233c13a5f5SAxel Dörfler // The locking protocol dictates that if both the receive lock 2243c13a5f5SAxel Dörfler // and domain locks are required, we MUST obtain the receive 2253c13a5f5SAxel Dörfler // lock before the domain lock. 2263c13a5f5SAxel Dörfler RecursiveLocker _1(device->receive_lock); 227*26153d0fSAxel Dörfler RecursiveLocker _2(domain->lock); 228fb300cfdSHugo Santos 229fb300cfdSHugo Santos net_interface* interface = find_interface(domain, name); 230fb300cfdSHugo Santos if (interface != NULL) { 231fb300cfdSHugo Santos switch (option) { 232fb300cfdSHugo Santos case SIOCDIFADDR: 233fb300cfdSHugo Santos remove_interface_from_domain(interface); 234fb300cfdSHugo Santos break; 235fb300cfdSHugo Santos 236fb300cfdSHugo Santos case SIOCSIFFLAGS: 237ae074c5dSHugo Santos { 238ae074c5dSHugo Santos uint32 requestFlags = request->ifr_flags; 239ae074c5dSHugo Santos request->ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST); 240ae074c5dSHugo Santos 241ae074c5dSHugo Santos if ((requestFlags & IFF_UP) != (interface->flags & IFF_UP)) { 242ae074c5dSHugo Santos if (requestFlags & IFF_UP) { 243fb300cfdSHugo Santos status = interface->first_info->interface_up( 244fb300cfdSHugo Santos interface->first_protocol); 245ae074c5dSHugo Santos if (status == B_OK) 246fb300cfdSHugo Santos interface->flags |= IFF_UP; 247ae074c5dSHugo Santos } else { 248ae074c5dSHugo Santos interface_set_down(interface); 249fb300cfdSHugo Santos } 250fb300cfdSHugo Santos } 251fb300cfdSHugo Santos 25274ff314bSAxel Dörfler if (status == B_OK) { 25374ff314bSAxel Dörfler // TODO: why shouldn't we able to delete IFF_BROADCAST? 25474ff314bSAxel Dörfler interface->flags &= IFF_UP | IFF_LINK | IFF_BROADCAST; 255ae074c5dSHugo Santos interface->flags |= request->ifr_flags; 25674ff314bSAxel Dörfler } 257fb300cfdSHugo Santos break; 258fb300cfdSHugo Santos } 259fb300cfdSHugo Santos } 260fb300cfdSHugo Santos } 261fb300cfdSHugo Santos 2623c13a5f5SAxel Dörfler // If the SIOCDIFADDR call above removed the last interface associated with 2633c13a5f5SAxel Dörfler // the device interface, this will effectively remove the interface 264fb300cfdSHugo Santos put_device_interface(device); 265fb300cfdSHugo Santos 266fb300cfdSHugo Santos return status; 267fb300cfdSHugo Santos } 268fb300cfdSHugo Santos 269fb300cfdSHugo Santos 2703c13a5f5SAxel Dörfler /*! You need to hold the domain lock when calling this function. */ 2719206bb37SAxel Dörfler void 272c64feccaSHugo Santos domain_interface_went_down(net_interface* interface) 273c64feccaSHugo Santos { 274*26153d0fSAxel Dörfler ASSERT_LOCKED_RECURSIVE(&((net_domain_private*)interface->domain)->lock); 275c64feccaSHugo Santos 2763c13a5f5SAxel Dörfler TRACE(("domain_interface_went_down(%i, %s)\n", 2773c13a5f5SAxel Dörfler interface->domain->family, interface->name)); 278c64feccaSHugo Santos 279c64feccaSHugo Santos invalidate_routes(interface->domain, interface); 280c64feccaSHugo Santos } 281c64feccaSHugo Santos 282c64feccaSHugo Santos 283c64feccaSHugo Santos void 2843c13a5f5SAxel Dörfler domain_removed_device_interface(net_device_interface* deviceInterface) 285c64feccaSHugo Santos { 2862b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 287c64feccaSHugo Santos 288c64feccaSHugo Santos net_domain_private* domain = NULL; 289c64feccaSHugo Santos while (true) { 290c64feccaSHugo Santos domain = (net_domain_private*)list_get_next_item(&sDomains, domain); 291c64feccaSHugo Santos if (domain == NULL) 292c64feccaSHugo Santos break; 293c64feccaSHugo Santos 294*26153d0fSAxel Dörfler RecursiveLocker locker(domain->lock); 295c64feccaSHugo Santos 2963c13a5f5SAxel Dörfler net_interface_private* interface = find_interface(domain, 2973c13a5f5SAxel Dörfler deviceInterface->device->name); 2983c13a5f5SAxel Dörfler if (interface == NULL) 299c64feccaSHugo Santos continue; 300c64feccaSHugo Santos 3013c13a5f5SAxel Dörfler remove_interface_from_domain(interface); 302c64feccaSHugo Santos } 303c64feccaSHugo Santos } 304c64feccaSHugo Santos 305c64feccaSHugo Santos 306c22d69bfSAxel Dörfler status_t 307c22d69bfSAxel Dörfler register_domain(int family, const char* name, 308c22d69bfSAxel Dörfler struct net_protocol_module_info* module, 309c22d69bfSAxel Dörfler struct net_address_module_info* addressModule, 310c22d69bfSAxel Dörfler net_domain** _domain) 311c22d69bfSAxel Dörfler { 312c22d69bfSAxel Dörfler TRACE(("register_domain(%d, %s)\n", family, name)); 3132b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 314c22d69bfSAxel Dörfler 315c22d69bfSAxel Dörfler struct net_domain_private* domain = lookup_domain(family); 316c22d69bfSAxel Dörfler if (domain != NULL) 317c22d69bfSAxel Dörfler return B_NAME_IN_USE; 318c22d69bfSAxel Dörfler 319c22d69bfSAxel Dörfler domain = new(std::nothrow) net_domain_private; 320c22d69bfSAxel Dörfler if (domain == NULL) 321c22d69bfSAxel Dörfler return B_NO_MEMORY; 322c22d69bfSAxel Dörfler 323*26153d0fSAxel Dörfler recursive_lock_init(&domain->lock, name); 324c22d69bfSAxel Dörfler 325c22d69bfSAxel Dörfler domain->family = family; 326c22d69bfSAxel Dörfler domain->name = name; 327c22d69bfSAxel Dörfler domain->module = module; 328c22d69bfSAxel Dörfler domain->address_module = addressModule; 329c22d69bfSAxel Dörfler 330c22d69bfSAxel Dörfler list_init(&domain->interfaces); 331c22d69bfSAxel Dörfler 332c22d69bfSAxel Dörfler list_add_item(&sDomains, domain); 333c22d69bfSAxel Dörfler 334c22d69bfSAxel Dörfler *_domain = domain; 335c22d69bfSAxel Dörfler return B_OK; 336c22d69bfSAxel Dörfler } 337c22d69bfSAxel Dörfler 338c22d69bfSAxel Dörfler 339c22d69bfSAxel Dörfler status_t 340c22d69bfSAxel Dörfler unregister_domain(net_domain* _domain) 341c22d69bfSAxel Dörfler { 3423c13a5f5SAxel Dörfler TRACE(("unregister_domain(%p, %d, %s)\n", _domain, _domain->family, 3433c13a5f5SAxel Dörfler _domain->name)); 344c22d69bfSAxel Dörfler 345c22d69bfSAxel Dörfler net_domain_private* domain = (net_domain_private*)_domain; 3462b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 347c22d69bfSAxel Dörfler 348c22d69bfSAxel Dörfler list_remove_item(&sDomains, domain); 349c22d69bfSAxel Dörfler 350c22d69bfSAxel Dörfler net_interface_private* interface = NULL; 351c22d69bfSAxel Dörfler while (true) { 3523c13a5f5SAxel Dörfler interface = (net_interface_private*)list_remove_head_item( 3533c13a5f5SAxel Dörfler &domain->interfaces); 354c22d69bfSAxel Dörfler if (interface == NULL) 355c22d69bfSAxel Dörfler break; 356c22d69bfSAxel Dörfler 357c22d69bfSAxel Dörfler delete_interface(interface); 358c22d69bfSAxel Dörfler } 359c22d69bfSAxel Dörfler 360*26153d0fSAxel Dörfler recursive_lock_destroy(&domain->lock); 361c22d69bfSAxel Dörfler delete domain; 362c22d69bfSAxel Dörfler return B_OK; 363c22d69bfSAxel Dörfler } 364c22d69bfSAxel Dörfler 365c22d69bfSAxel Dörfler 366c22d69bfSAxel Dörfler status_t 367c22d69bfSAxel Dörfler init_domains() 368c22d69bfSAxel Dörfler { 3692b07b8e0SIngo Weinhold mutex_init(&sDomainLock, "net domains"); 370c22d69bfSAxel Dörfler 371c22d69bfSAxel Dörfler list_init_etc(&sDomains, offsetof(struct net_domain_private, link)); 372c22d69bfSAxel Dörfler return B_OK; 373c22d69bfSAxel Dörfler } 374c22d69bfSAxel Dörfler 375c22d69bfSAxel Dörfler 376c22d69bfSAxel Dörfler status_t 377c22d69bfSAxel Dörfler uninit_domains() 378c22d69bfSAxel Dörfler { 3792b07b8e0SIngo Weinhold mutex_destroy(&sDomainLock); 380c22d69bfSAxel Dörfler return B_OK; 381c22d69bfSAxel Dörfler } 382c22d69bfSAxel Dörfler 383