1c22d69bfSAxel Dörfler /* 29c4477d3SAxel Dörfler * Copyright 2006-2007, 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" 13c22d69bfSAxel Dörfler 149206bb37SAxel Dörfler #include <net_device.h> 15c22d69bfSAxel Dörfler 16c22d69bfSAxel Dörfler #include <lock.h> 17c22d69bfSAxel Dörfler #include <util/AutoLock.h> 18c22d69bfSAxel Dörfler 199206bb37SAxel Dörfler #include <KernelExport.h> 209206bb37SAxel Dörfler 219206bb37SAxel Dörfler #include <net/if_media.h> 22c22d69bfSAxel Dörfler #include <new> 23c22d69bfSAxel Dörfler #include <string.h> 24c22d69bfSAxel Dörfler 25c22d69bfSAxel Dörfler 26c22d69bfSAxel Dörfler #define TRACE_DOMAINS 27c22d69bfSAxel Dörfler #ifdef TRACE_DOMAINS 28c22d69bfSAxel Dörfler # define TRACE(x) dprintf x 29c22d69bfSAxel Dörfler #else 30c22d69bfSAxel Dörfler # define TRACE(x) ; 31c22d69bfSAxel Dörfler #endif 32c22d69bfSAxel Dörfler 33c22d69bfSAxel Dörfler static benaphore sDomainLock; 34c22d69bfSAxel Dörfler static list sDomains; 35c22d69bfSAxel Dörfler 36c22d69bfSAxel Dörfler 37c22d69bfSAxel Dörfler /*! 38c22d69bfSAxel Dörfler Scans the domain list for the specified family. 39c22d69bfSAxel Dörfler You need to hold the sDomainLock when calling this function. 40c22d69bfSAxel Dörfler */ 41c22d69bfSAxel Dörfler static net_domain_private * 42c22d69bfSAxel Dörfler lookup_domain(int family) 43c22d69bfSAxel Dörfler { 44c22d69bfSAxel Dörfler net_domain_private *domain = NULL; 45c22d69bfSAxel Dörfler while (true) { 46c22d69bfSAxel Dörfler domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 47c22d69bfSAxel Dörfler if (domain == NULL) 48c22d69bfSAxel Dörfler break; 49c22d69bfSAxel Dörfler 50c22d69bfSAxel Dörfler if (domain->family == family) 51c22d69bfSAxel Dörfler return domain; 52c22d69bfSAxel Dörfler } 53c22d69bfSAxel Dörfler 54c22d69bfSAxel Dörfler return NULL; 55c22d69bfSAxel Dörfler } 56c22d69bfSAxel Dörfler 57c22d69bfSAxel Dörfler 58c22d69bfSAxel Dörfler // #pragma mark - 59c22d69bfSAxel Dörfler 60c22d69bfSAxel Dörfler 61c22d69bfSAxel Dörfler /*! 62c22d69bfSAxel 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 { 67c22d69bfSAxel Dörfler BenaphoreLocker 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 { 75c22d69bfSAxel Dörfler BenaphoreLocker 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 { 108c22d69bfSAxel Dörfler BenaphoreLocker 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 1189206bb37SAxel Dörfler BenaphoreLocker 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; 157c22d69bfSAxel Dörfler net_device_interface *deviceInterface = get_device_interface(deviceName); 158c22d69bfSAxel Dörfler if (deviceInterface == NULL) 159c22d69bfSAxel Dörfler return ENODEV; 160c22d69bfSAxel Dörfler 161c22d69bfSAxel Dörfler BenaphoreLocker locker(domain->lock); 162c22d69bfSAxel Dörfler 163c22d69bfSAxel Dörfler if (find_interface(domain, request.ifr_name) != NULL) 164c22d69bfSAxel Dörfler return B_NAME_IN_USE; 165c22d69bfSAxel Dörfler 166c22d69bfSAxel Dörfler net_interface_private *interface; 167c22d69bfSAxel Dörfler status_t status = create_interface(domain, 168c22d69bfSAxel Dörfler request.ifr_name, request.ifr_parameter.base_name[0] 169c22d69bfSAxel Dörfler ? request.ifr_parameter.base_name : request.ifr_name, 170c22d69bfSAxel Dörfler deviceInterface, &interface); 171c22d69bfSAxel Dörfler if (status < B_OK) { 172c22d69bfSAxel Dörfler put_device_interface(deviceInterface); 173c22d69bfSAxel Dörfler return status; 174c22d69bfSAxel Dörfler } 175c22d69bfSAxel Dörfler 176c22d69bfSAxel Dörfler list_add_item(&domain->interfaces, interface); 177c22d69bfSAxel Dörfler return B_OK; 178c22d69bfSAxel Dörfler } 179c22d69bfSAxel Dörfler 180c22d69bfSAxel Dörfler 181c22d69bfSAxel Dörfler /*! 182c22d69bfSAxel Dörfler Removes the interface from its domain, and deletes it. 183c22d69bfSAxel Dörfler You need to hold the domain's lock when calling this function. 184c22d69bfSAxel Dörfler */ 185c22d69bfSAxel Dörfler status_t 186c22d69bfSAxel Dörfler remove_interface_from_domain(net_interface *interface) 187c22d69bfSAxel Dörfler { 188c22d69bfSAxel Dörfler net_domain_private *domain = (net_domain_private *)interface->domain; 189c22d69bfSAxel Dörfler 190c22d69bfSAxel Dörfler list_remove_item(&domain->interfaces, interface); 191c22d69bfSAxel Dörfler delete_interface((net_interface_private *)interface); 192c22d69bfSAxel Dörfler return B_OK; 193c22d69bfSAxel Dörfler } 194c22d69bfSAxel Dörfler 195c22d69bfSAxel Dörfler 1969206bb37SAxel Dörfler void 1979206bb37SAxel Dörfler domain_interfaces_link_changed(net_device *device) 1989206bb37SAxel Dörfler { 1999206bb37SAxel Dörfler // TODO: notify listeners about this! 2009206bb37SAxel Dörfler 2019206bb37SAxel Dörfler BenaphoreLocker locker(sDomainLock); 2029206bb37SAxel Dörfler 2039206bb37SAxel Dörfler net_domain_private *domain = NULL; 2049206bb37SAxel Dörfler while (true) { 2059206bb37SAxel Dörfler domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 2069206bb37SAxel Dörfler if (domain == NULL) 2079206bb37SAxel Dörfler break; 2089206bb37SAxel Dörfler 2099206bb37SAxel Dörfler BenaphoreLocker locker(domain->lock); 2109206bb37SAxel Dörfler 2119206bb37SAxel Dörfler net_interface *interface = NULL; 2129206bb37SAxel Dörfler while (true) { 2139206bb37SAxel Dörfler interface = (net_interface *)list_get_next_item(&domain->interfaces, 2149206bb37SAxel Dörfler interface); 2159206bb37SAxel Dörfler if (interface == NULL) 2169206bb37SAxel Dörfler break; 2179206bb37SAxel Dörfler 2189206bb37SAxel Dörfler if (interface->device == device) { 2199206bb37SAxel Dörfler // update IFF_LINK flag 2209206bb37SAxel Dörfler interface->flags = (interface->flags & ~IFF_LINK) 2219206bb37SAxel Dörfler | (device->media & IFM_ACTIVE ? IFF_LINK : 0); 2229206bb37SAxel Dörfler } 2239206bb37SAxel Dörfler } 2249206bb37SAxel Dörfler } 2259206bb37SAxel Dörfler } 2269206bb37SAxel Dörfler 2279206bb37SAxel Dörfler 228*c64feccaSHugo Santos void 229*c64feccaSHugo Santos domain_interface_went_down(net_interface *interface) 230*c64feccaSHugo Santos { 231*c64feccaSHugo Santos // the domain should be locked here. always check 232*c64feccaSHugo Santos // all callers to be sure. We get here via 233*c64feccaSHugo Santos // interface_set_down(). 234*c64feccaSHugo Santos 235*c64feccaSHugo Santos dprintf("domain_interface_went_down(%i, %s)\n", 236*c64feccaSHugo Santos interface->domain->family, interface->name); 237*c64feccaSHugo Santos 238*c64feccaSHugo Santos // domain might have been locked by: 239*c64feccaSHugo Santos // - domain_removed_device_interface() <--- here 240*c64feccaSHugo Santos // remove_interface_from_domain() 241*c64feccaSHugo Santos // delete_interface() 242*c64feccaSHugo Santos // interface_set_down() 243*c64feccaSHugo Santos // - datalink_control() <--- here 244*c64feccaSHugo Santos // interface_set_down() 245*c64feccaSHugo Santos invalidate_routes(interface->domain, interface); 246*c64feccaSHugo Santos } 247*c64feccaSHugo Santos 248*c64feccaSHugo Santos 249*c64feccaSHugo Santos void 250*c64feccaSHugo Santos domain_removed_device_interface(net_device_interface *interface) 251*c64feccaSHugo Santos { 252*c64feccaSHugo Santos BenaphoreLocker locker(sDomainLock); 253*c64feccaSHugo Santos 254*c64feccaSHugo Santos net_domain_private *domain = NULL; 255*c64feccaSHugo Santos while (true) { 256*c64feccaSHugo Santos domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 257*c64feccaSHugo Santos if (domain == NULL) 258*c64feccaSHugo Santos break; 259*c64feccaSHugo Santos 260*c64feccaSHugo Santos BenaphoreLocker locker(domain->lock); 261*c64feccaSHugo Santos 262*c64feccaSHugo Santos net_interface_private *priv = find_interface(domain, interface->name); 263*c64feccaSHugo Santos if (priv == NULL) 264*c64feccaSHugo Santos continue; 265*c64feccaSHugo Santos 266*c64feccaSHugo Santos remove_interface_from_domain(priv); 267*c64feccaSHugo Santos } 268*c64feccaSHugo Santos } 269*c64feccaSHugo Santos 270*c64feccaSHugo Santos 271c22d69bfSAxel Dörfler status_t 272c22d69bfSAxel Dörfler register_domain(int family, const char *name, 273c22d69bfSAxel Dörfler struct net_protocol_module_info *module, 274c22d69bfSAxel Dörfler struct net_address_module_info *addressModule, 275c22d69bfSAxel Dörfler net_domain **_domain) 276c22d69bfSAxel Dörfler { 277c22d69bfSAxel Dörfler TRACE(("register_domain(%d, %s)\n", family, name)); 278c22d69bfSAxel Dörfler BenaphoreLocker locker(sDomainLock); 279c22d69bfSAxel Dörfler 280c22d69bfSAxel Dörfler struct net_domain_private *domain = lookup_domain(family); 281c22d69bfSAxel Dörfler if (domain != NULL) 282c22d69bfSAxel Dörfler return B_NAME_IN_USE; 283c22d69bfSAxel Dörfler 284c22d69bfSAxel Dörfler domain = new (std::nothrow) net_domain_private; 285c22d69bfSAxel Dörfler if (domain == NULL) 286c22d69bfSAxel Dörfler return B_NO_MEMORY; 287c22d69bfSAxel Dörfler 288c22d69bfSAxel Dörfler status_t status = benaphore_init(&domain->lock, name); 289c22d69bfSAxel Dörfler if (status < B_OK) { 290c22d69bfSAxel Dörfler delete domain; 291c22d69bfSAxel Dörfler return status; 292c22d69bfSAxel Dörfler } 293c22d69bfSAxel Dörfler 294c22d69bfSAxel Dörfler domain->family = family; 295c22d69bfSAxel Dörfler domain->name = name; 296c22d69bfSAxel Dörfler domain->module = module; 297c22d69bfSAxel Dörfler domain->address_module = addressModule; 298c22d69bfSAxel Dörfler 299c22d69bfSAxel Dörfler list_init(&domain->interfaces); 300c22d69bfSAxel Dörfler 301c22d69bfSAxel Dörfler list_add_item(&sDomains, domain); 302c22d69bfSAxel Dörfler 303c22d69bfSAxel Dörfler *_domain = domain; 304c22d69bfSAxel Dörfler return B_OK; 305c22d69bfSAxel Dörfler } 306c22d69bfSAxel Dörfler 307c22d69bfSAxel Dörfler 308c22d69bfSAxel Dörfler status_t 309c22d69bfSAxel Dörfler unregister_domain(net_domain *_domain) 310c22d69bfSAxel Dörfler { 311c22d69bfSAxel Dörfler TRACE(("unregister_domain(%p, %d, %s)\n", _domain, _domain->family, _domain->name)); 312c22d69bfSAxel Dörfler 313c22d69bfSAxel Dörfler net_domain_private *domain = (net_domain_private *)_domain; 314c22d69bfSAxel Dörfler BenaphoreLocker locker(sDomainLock); 315c22d69bfSAxel Dörfler 316c22d69bfSAxel Dörfler list_remove_item(&sDomains, domain); 317c22d69bfSAxel Dörfler 318c22d69bfSAxel Dörfler net_interface_private *interface = NULL; 319c22d69bfSAxel Dörfler while (true) { 320c22d69bfSAxel Dörfler interface = (net_interface_private *)list_remove_head_item(&domain->interfaces); 321c22d69bfSAxel Dörfler if (interface == NULL) 322c22d69bfSAxel Dörfler break; 323c22d69bfSAxel Dörfler 324c22d69bfSAxel Dörfler delete_interface(interface); 325c22d69bfSAxel Dörfler } 326c22d69bfSAxel Dörfler 327c22d69bfSAxel Dörfler benaphore_destroy(&domain->lock); 328c22d69bfSAxel Dörfler delete domain; 329c22d69bfSAxel Dörfler return B_OK; 330c22d69bfSAxel Dörfler } 331c22d69bfSAxel Dörfler 332c22d69bfSAxel Dörfler 333c22d69bfSAxel Dörfler status_t 334c22d69bfSAxel Dörfler init_domains() 335c22d69bfSAxel Dörfler { 336c22d69bfSAxel Dörfler if (benaphore_init(&sDomainLock, "net domains") < B_OK) 337c22d69bfSAxel Dörfler return B_ERROR; 338c22d69bfSAxel Dörfler 339c22d69bfSAxel Dörfler list_init_etc(&sDomains, offsetof(struct net_domain_private, link)); 340c22d69bfSAxel Dörfler return B_OK; 341c22d69bfSAxel Dörfler } 342c22d69bfSAxel Dörfler 343c22d69bfSAxel Dörfler 344c22d69bfSAxel Dörfler status_t 345c22d69bfSAxel Dörfler uninit_domains() 346c22d69bfSAxel Dörfler { 347c22d69bfSAxel Dörfler benaphore_destroy(&sDomainLock); 348c22d69bfSAxel Dörfler return B_OK; 349c22d69bfSAxel Dörfler } 350c22d69bfSAxel Dörfler 351