1c22d69bfSAxel Dörfler /* 2a3513e7bSAxel Dörfler * Copyright 2006-2008, 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 39c22d69bfSAxel Dörfler /*! 40c22d69bfSAxel Dörfler Scans the domain list for the specified family. 41c22d69bfSAxel Dörfler You need to hold the sDomainLock when calling this function. 42c22d69bfSAxel Dörfler */ 43c22d69bfSAxel Dörfler static net_domain_private * 44c22d69bfSAxel Dörfler lookup_domain(int family) 45c22d69bfSAxel Dörfler { 46c22d69bfSAxel Dörfler net_domain_private *domain = NULL; 47c22d69bfSAxel Dörfler while (true) { 48c22d69bfSAxel Dörfler domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 49c22d69bfSAxel Dörfler if (domain == NULL) 50c22d69bfSAxel Dörfler break; 51c22d69bfSAxel Dörfler 52c22d69bfSAxel Dörfler if (domain->family == family) 53c22d69bfSAxel Dörfler return domain; 54c22d69bfSAxel Dörfler } 55c22d69bfSAxel Dörfler 56c22d69bfSAxel Dörfler return NULL; 57c22d69bfSAxel Dörfler } 58c22d69bfSAxel Dörfler 59c22d69bfSAxel Dörfler 60c22d69bfSAxel Dörfler // #pragma mark - 61c22d69bfSAxel Dörfler 62c22d69bfSAxel Dörfler 63c22d69bfSAxel Dörfler /*! 64c22d69bfSAxel Dörfler Gets the domain of the specified family. 65c22d69bfSAxel Dörfler */ 66c22d69bfSAxel Dörfler net_domain * 67c22d69bfSAxel Dörfler get_domain(int family) 68c22d69bfSAxel Dörfler { 692b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 70c22d69bfSAxel Dörfler return lookup_domain(family); 71c22d69bfSAxel Dörfler } 72c22d69bfSAxel Dörfler 73c22d69bfSAxel Dörfler 74c22d69bfSAxel Dörfler uint32 75c22d69bfSAxel Dörfler count_domain_interfaces() 76c22d69bfSAxel Dörfler { 772b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 78c22d69bfSAxel Dörfler 79c22d69bfSAxel Dörfler net_domain_private *domain = NULL; 80c22d69bfSAxel Dörfler uint32 count = 0; 81c22d69bfSAxel Dörfler 82c22d69bfSAxel Dörfler while (true) { 83c22d69bfSAxel Dörfler domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 84c22d69bfSAxel Dörfler if (domain == NULL) 85c22d69bfSAxel Dörfler break; 86c22d69bfSAxel Dörfler 87c22d69bfSAxel Dörfler net_interface *interface = NULL; 88c22d69bfSAxel Dörfler while (true) { 89c22d69bfSAxel Dörfler interface = (net_interface *)list_get_next_item(&domain->interfaces, 90c22d69bfSAxel Dörfler interface); 91c22d69bfSAxel Dörfler if (interface == NULL) 92c22d69bfSAxel Dörfler break; 93c22d69bfSAxel Dörfler 94c22d69bfSAxel Dörfler count++; 95c22d69bfSAxel Dörfler } 96c22d69bfSAxel Dörfler } 97c22d69bfSAxel Dörfler 98c22d69bfSAxel Dörfler return count; 99c22d69bfSAxel Dörfler } 100c22d69bfSAxel Dörfler 101c22d69bfSAxel Dörfler 102c22d69bfSAxel Dörfler /*! 103c22d69bfSAxel Dörfler Dumps a list of all interfaces into the supplied userland buffer. 104c22d69bfSAxel Dörfler If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is 105c22d69bfSAxel Dörfler returned. 106c22d69bfSAxel Dörfler */ 107c22d69bfSAxel Dörfler status_t 108409b1fc0SHugo Santos list_domain_interfaces(void *_buffer, size_t *bufferSize) 109c22d69bfSAxel Dörfler { 1102b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 111c22d69bfSAxel Dörfler 112409b1fc0SHugo Santos UserBuffer buffer(_buffer, *bufferSize); 113c22d69bfSAxel Dörfler net_domain_private *domain = NULL; 114c22d69bfSAxel Dörfler 115c22d69bfSAxel Dörfler while (true) { 116c22d69bfSAxel Dörfler domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 117c22d69bfSAxel Dörfler if (domain == NULL) 118c22d69bfSAxel Dörfler break; 119c22d69bfSAxel Dörfler 1202b07b8e0SIngo Weinhold MutexLocker locker(domain->lock); 1219206bb37SAxel Dörfler 122c22d69bfSAxel Dörfler net_interface *interface = NULL; 123c22d69bfSAxel Dörfler while (true) { 124c22d69bfSAxel Dörfler interface = (net_interface *)list_get_next_item(&domain->interfaces, 125c22d69bfSAxel Dörfler interface); 126c22d69bfSAxel Dörfler if (interface == NULL) 127c22d69bfSAxel Dörfler break; 128c22d69bfSAxel Dörfler 129c22d69bfSAxel Dörfler ifreq request; 130c22d69bfSAxel Dörfler strlcpy(request.ifr_name, interface->name, IF_NAMESIZE); 1319206bb37SAxel Dörfler if (interface->address != NULL) { 1329206bb37SAxel Dörfler memcpy(&request.ifr_addr, interface->address, 1339206bb37SAxel Dörfler interface->address->sa_len); 1349206bb37SAxel Dörfler } else { 135c22d69bfSAxel Dörfler // empty address 136c22d69bfSAxel Dörfler request.ifr_addr.sa_len = 2; 137c22d69bfSAxel Dörfler request.ifr_addr.sa_family = AF_UNSPEC; 138c22d69bfSAxel Dörfler } 139c22d69bfSAxel Dörfler 140409b1fc0SHugo Santos if (buffer.Copy(&request, IF_NAMESIZE 141409b1fc0SHugo Santos + request.ifr_addr.sa_len) == NULL) 142409b1fc0SHugo Santos return buffer.Status(); 143c22d69bfSAxel Dörfler } 144c22d69bfSAxel Dörfler } 145c22d69bfSAxel Dörfler 146409b1fc0SHugo Santos *bufferSize = buffer.ConsumedAmount(); 147c22d69bfSAxel Dörfler return B_OK; 148c22d69bfSAxel Dörfler } 149c22d69bfSAxel Dörfler 150c22d69bfSAxel Dörfler 151c22d69bfSAxel Dörfler status_t 152c22d69bfSAxel Dörfler add_interface_to_domain(net_domain *_domain, 153c22d69bfSAxel Dörfler struct ifreq& request) 154c22d69bfSAxel Dörfler { 155c22d69bfSAxel Dörfler net_domain_private *domain = (net_domain_private *)_domain; 156c22d69bfSAxel Dörfler 157c22d69bfSAxel Dörfler const char *deviceName = request.ifr_parameter.device[0] 158c22d69bfSAxel Dörfler ? request.ifr_parameter.device : request.ifr_name; 15920b534cdSHugo Santos const char *baseName = request.ifr_parameter.base_name[0] 16020b534cdSHugo Santos ? request.ifr_parameter.base_name : request.ifr_name; 16120b534cdSHugo Santos 162c22d69bfSAxel Dörfler net_device_interface *deviceInterface = get_device_interface(deviceName); 163c22d69bfSAxel Dörfler if (deviceInterface == NULL) 164c22d69bfSAxel Dörfler return ENODEV; 165c22d69bfSAxel Dörfler 1662b07b8e0SIngo Weinhold MutexLocker locker(domain->lock); 167c22d69bfSAxel Dörfler 16820b534cdSHugo Santos net_interface_private *interface = NULL; 16920b534cdSHugo Santos status_t status; 17020b534cdSHugo Santos 171a3513e7bSAxel Dörfler if (find_interface(domain, request.ifr_name) == NULL) { 172a3513e7bSAxel Dörfler // We must not hold the domain's link when creating the interface: 173a3513e7bSAxel Dörfler // this will call get_module() which might want to access a network 174a3513e7bSAxel Dörfler // device when booting from network. 175a3513e7bSAxel Dörfler locker.Unlock(); 17620b534cdSHugo Santos status = create_interface(domain, request.ifr_name, 17720b534cdSHugo Santos baseName, deviceInterface, &interface); 178a3513e7bSAxel Dörfler locker.Lock(); 179a3513e7bSAxel Dörfler 180a3513e7bSAxel Dörfler if (find_interface(domain, request.ifr_name) != NULL) { 181a3513e7bSAxel Dörfler delete_interface(interface); 182a3513e7bSAxel Dörfler status = B_NAME_IN_USE; 183a3513e7bSAxel Dörfler } 184a3513e7bSAxel Dörfler } else 185a3513e7bSAxel Dörfler status = B_NAME_IN_USE; 186c22d69bfSAxel Dörfler 187c22d69bfSAxel Dörfler put_device_interface(deviceInterface); 188c22d69bfSAxel Dörfler 189*d68ffdedSAxel Dörfler if (status == B_OK) { 190c22d69bfSAxel Dörfler list_add_item(&domain->interfaces, interface); 191*d68ffdedSAxel Dörfler notify_interface_added(interface); 192*d68ffdedSAxel Dörfler } 19320b534cdSHugo Santos 19420b534cdSHugo Santos return status; 195c22d69bfSAxel Dörfler } 196c22d69bfSAxel Dörfler 197c22d69bfSAxel Dörfler 198c22d69bfSAxel Dörfler /*! 199c22d69bfSAxel Dörfler Removes the interface from its domain, and deletes it. 200c22d69bfSAxel Dörfler You need to hold the domain's lock when calling this function. 201c22d69bfSAxel Dörfler */ 202c22d69bfSAxel Dörfler status_t 203c22d69bfSAxel Dörfler remove_interface_from_domain(net_interface *interface) 204c22d69bfSAxel Dörfler { 205c22d69bfSAxel Dörfler net_domain_private *domain = (net_domain_private *)interface->domain; 206c22d69bfSAxel Dörfler 207c22d69bfSAxel Dörfler list_remove_item(&domain->interfaces, interface); 208*d68ffdedSAxel Dörfler notify_interface_removed(interface); 209c22d69bfSAxel Dörfler delete_interface((net_interface_private *)interface); 210c22d69bfSAxel Dörfler return B_OK; 211c22d69bfSAxel Dörfler } 212c22d69bfSAxel Dörfler 213c22d69bfSAxel Dörfler 214fb300cfdSHugo Santos status_t 215fb300cfdSHugo Santos domain_interface_control(net_domain_private *domain, int32 option, 216fb300cfdSHugo Santos ifreq *request) 217fb300cfdSHugo Santos { 218fb300cfdSHugo Santos const char *name = request->ifr_name; 219fb300cfdSHugo Santos status_t status = B_OK; 220fb300cfdSHugo Santos 221fb300cfdSHugo Santos net_device_interface *device = get_device_interface(name, false); 222fb300cfdSHugo Santos if (device == NULL) 223fb300cfdSHugo Santos return ENODEV; 224fb300cfdSHugo Santos else { 225fb300cfdSHugo Santos // The locking protocol dictates that if both the RX lock 226fb300cfdSHugo Santos // and domain locks are required, we MUST obtain the RX 227fb300cfdSHugo Santos // lock before the domain lock. This order MUST NOT ever 228fb300cfdSHugo Santos // be reversed under the penalty of deadlock. 22964734690SHugo Santos RecursiveLocker _1(device->rx_lock); 2302b07b8e0SIngo Weinhold MutexLocker _2(domain->lock); 231fb300cfdSHugo Santos 232fb300cfdSHugo Santos net_interface *interface = find_interface(domain, name); 233fb300cfdSHugo Santos if (interface != NULL) { 234fb300cfdSHugo Santos switch (option) { 235fb300cfdSHugo Santos case SIOCDIFADDR: 236fb300cfdSHugo Santos remove_interface_from_domain(interface); 237fb300cfdSHugo Santos break; 238fb300cfdSHugo Santos 239fb300cfdSHugo Santos case SIOCSIFFLAGS: 240ae074c5dSHugo Santos { 241ae074c5dSHugo Santos uint32 requestFlags = request->ifr_flags; 242ae074c5dSHugo Santos request->ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST); 243ae074c5dSHugo Santos 244ae074c5dSHugo Santos if ((requestFlags & IFF_UP) != (interface->flags & IFF_UP)) { 245ae074c5dSHugo Santos if (requestFlags & IFF_UP) { 246fb300cfdSHugo Santos status = interface->first_info->interface_up( 247fb300cfdSHugo Santos interface->first_protocol); 248ae074c5dSHugo Santos if (status == B_OK) 249fb300cfdSHugo Santos interface->flags |= IFF_UP; 250ae074c5dSHugo Santos } else { 251ae074c5dSHugo Santos interface_set_down(interface); 252fb300cfdSHugo Santos } 253fb300cfdSHugo Santos } 254fb300cfdSHugo Santos 255fb300cfdSHugo Santos if (status == B_OK) 256ae074c5dSHugo Santos interface->flags |= request->ifr_flags; 257fb300cfdSHugo Santos break; 258fb300cfdSHugo Santos } 259fb300cfdSHugo Santos } 260fb300cfdSHugo Santos } 261ae074c5dSHugo Santos } 262fb300cfdSHugo Santos 263fb300cfdSHugo Santos // If the SIOCDIFADDR call above removed the last interface 264fb300cfdSHugo Santos // associated with the device interface, this put_() will 265fb300cfdSHugo Santos // effectively remove the interface 266fb300cfdSHugo Santos put_device_interface(device); 267fb300cfdSHugo Santos 268fb300cfdSHugo Santos return status; 269fb300cfdSHugo Santos } 270fb300cfdSHugo Santos 271fb300cfdSHugo Santos 2729206bb37SAxel Dörfler void 273c64feccaSHugo Santos domain_interface_went_down(net_interface *interface) 274c64feccaSHugo Santos { 275c64feccaSHugo Santos // the domain should be locked here. always check 276c64feccaSHugo Santos // all callers to be sure. We get here via 277c64feccaSHugo Santos // interface_set_down(). 278c64feccaSHugo Santos 279c64feccaSHugo Santos dprintf("domain_interface_went_down(%i, %s)\n", 280c64feccaSHugo Santos interface->domain->family, interface->name); 281c64feccaSHugo Santos 282c64feccaSHugo Santos // domain might have been locked by: 283c64feccaSHugo Santos // - domain_removed_device_interface() <--- here 284c64feccaSHugo Santos // remove_interface_from_domain() 285c64feccaSHugo Santos // delete_interface() 286c64feccaSHugo Santos // interface_set_down() 287c64feccaSHugo Santos // - datalink_control() <--- here 288c64feccaSHugo Santos // interface_set_down() 289c64feccaSHugo Santos invalidate_routes(interface->domain, interface); 290c64feccaSHugo Santos } 291c64feccaSHugo Santos 292c64feccaSHugo Santos 293c64feccaSHugo Santos void 294c64feccaSHugo Santos domain_removed_device_interface(net_device_interface *interface) 295c64feccaSHugo Santos { 2962b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 297c64feccaSHugo Santos 298c64feccaSHugo Santos net_domain_private *domain = NULL; 299c64feccaSHugo Santos while (true) { 300c64feccaSHugo Santos domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 301c64feccaSHugo Santos if (domain == NULL) 302c64feccaSHugo Santos break; 303c64feccaSHugo Santos 3042b07b8e0SIngo Weinhold MutexLocker locker(domain->lock); 305c64feccaSHugo Santos 306be2f6ac3SHugo Santos net_interface_private *priv = find_interface(domain, 307be2f6ac3SHugo Santos interface->device->name); 308c64feccaSHugo Santos if (priv == NULL) 309c64feccaSHugo Santos continue; 310c64feccaSHugo Santos 311c64feccaSHugo Santos remove_interface_from_domain(priv); 312c64feccaSHugo Santos } 313c64feccaSHugo Santos } 314c64feccaSHugo Santos 315c64feccaSHugo Santos 316c22d69bfSAxel Dörfler status_t 317c22d69bfSAxel Dörfler register_domain(int family, const char *name, 318c22d69bfSAxel Dörfler struct net_protocol_module_info *module, 319c22d69bfSAxel Dörfler struct net_address_module_info *addressModule, 320c22d69bfSAxel Dörfler net_domain **_domain) 321c22d69bfSAxel Dörfler { 322c22d69bfSAxel Dörfler TRACE(("register_domain(%d, %s)\n", family, name)); 3232b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 324c22d69bfSAxel Dörfler 325c22d69bfSAxel Dörfler struct net_domain_private *domain = lookup_domain(family); 326c22d69bfSAxel Dörfler if (domain != NULL) 327c22d69bfSAxel Dörfler return B_NAME_IN_USE; 328c22d69bfSAxel Dörfler 329c22d69bfSAxel Dörfler domain = new (std::nothrow) net_domain_private; 330c22d69bfSAxel Dörfler if (domain == NULL) 331c22d69bfSAxel Dörfler return B_NO_MEMORY; 332c22d69bfSAxel Dörfler 3332b07b8e0SIngo Weinhold mutex_init_etc(&domain->lock, name, MUTEX_FLAG_CLONE_NAME); 334c22d69bfSAxel Dörfler 335c22d69bfSAxel Dörfler domain->family = family; 336c22d69bfSAxel Dörfler domain->name = name; 337c22d69bfSAxel Dörfler domain->module = module; 338c22d69bfSAxel Dörfler domain->address_module = addressModule; 339c22d69bfSAxel Dörfler 340c22d69bfSAxel Dörfler list_init(&domain->interfaces); 341c22d69bfSAxel Dörfler 342c22d69bfSAxel Dörfler list_add_item(&sDomains, domain); 343c22d69bfSAxel Dörfler 344c22d69bfSAxel Dörfler *_domain = domain; 345c22d69bfSAxel Dörfler return B_OK; 346c22d69bfSAxel Dörfler } 347c22d69bfSAxel Dörfler 348c22d69bfSAxel Dörfler 349c22d69bfSAxel Dörfler status_t 350c22d69bfSAxel Dörfler unregister_domain(net_domain *_domain) 351c22d69bfSAxel Dörfler { 352c22d69bfSAxel Dörfler TRACE(("unregister_domain(%p, %d, %s)\n", _domain, _domain->family, _domain->name)); 353c22d69bfSAxel Dörfler 354c22d69bfSAxel Dörfler net_domain_private *domain = (net_domain_private *)_domain; 3552b07b8e0SIngo Weinhold MutexLocker locker(sDomainLock); 356c22d69bfSAxel Dörfler 357c22d69bfSAxel Dörfler list_remove_item(&sDomains, domain); 358c22d69bfSAxel Dörfler 359c22d69bfSAxel Dörfler net_interface_private *interface = NULL; 360c22d69bfSAxel Dörfler while (true) { 361c22d69bfSAxel Dörfler interface = (net_interface_private *)list_remove_head_item(&domain->interfaces); 362c22d69bfSAxel Dörfler if (interface == NULL) 363c22d69bfSAxel Dörfler break; 364c22d69bfSAxel Dörfler 365c22d69bfSAxel Dörfler delete_interface(interface); 366c22d69bfSAxel Dörfler } 367c22d69bfSAxel Dörfler 3682b07b8e0SIngo Weinhold mutex_destroy(&domain->lock); 369c22d69bfSAxel Dörfler delete domain; 370c22d69bfSAxel Dörfler return B_OK; 371c22d69bfSAxel Dörfler } 372c22d69bfSAxel Dörfler 373c22d69bfSAxel Dörfler 374c22d69bfSAxel Dörfler status_t 375c22d69bfSAxel Dörfler init_domains() 376c22d69bfSAxel Dörfler { 3772b07b8e0SIngo Weinhold mutex_init(&sDomainLock, "net domains"); 378c22d69bfSAxel Dörfler 379c22d69bfSAxel Dörfler list_init_etc(&sDomains, offsetof(struct net_domain_private, link)); 380c22d69bfSAxel Dörfler return B_OK; 381c22d69bfSAxel Dörfler } 382c22d69bfSAxel Dörfler 383c22d69bfSAxel Dörfler 384c22d69bfSAxel Dörfler status_t 385c22d69bfSAxel Dörfler uninit_domains() 386c22d69bfSAxel Dörfler { 3872b07b8e0SIngo Weinhold mutex_destroy(&sDomainLock); 388c22d69bfSAxel Dörfler return B_OK; 389c22d69bfSAxel Dörfler } 390c22d69bfSAxel Dörfler 391