1 /* 2 * Copyright 2006-2007, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "domains.h" 11 #include "interfaces.h" 12 #include "utility.h" 13 #include "stack_private.h" 14 15 #include <net_device.h> 16 17 #include <lock.h> 18 #include <util/AutoLock.h> 19 20 #include <KernelExport.h> 21 22 #include <net/if_media.h> 23 #include <new> 24 #include <string.h> 25 #include <sys/sockio.h> 26 27 28 #define TRACE_DOMAINS 29 #ifdef TRACE_DOMAINS 30 # define TRACE(x) dprintf x 31 #else 32 # define TRACE(x) ; 33 #endif 34 35 static mutex sDomainLock; 36 static list sDomains; 37 38 39 /*! 40 Scans the domain list for the specified family. 41 You need to hold the sDomainLock when calling this function. 42 */ 43 static net_domain_private * 44 lookup_domain(int family) 45 { 46 net_domain_private *domain = NULL; 47 while (true) { 48 domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 49 if (domain == NULL) 50 break; 51 52 if (domain->family == family) 53 return domain; 54 } 55 56 return NULL; 57 } 58 59 60 // #pragma mark - 61 62 63 /*! 64 Gets the domain of the specified family. 65 */ 66 net_domain * 67 get_domain(int family) 68 { 69 MutexLocker locker(sDomainLock); 70 return lookup_domain(family); 71 } 72 73 74 uint32 75 count_domain_interfaces() 76 { 77 MutexLocker locker(sDomainLock); 78 79 net_domain_private *domain = NULL; 80 uint32 count = 0; 81 82 while (true) { 83 domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 84 if (domain == NULL) 85 break; 86 87 net_interface *interface = NULL; 88 while (true) { 89 interface = (net_interface *)list_get_next_item(&domain->interfaces, 90 interface); 91 if (interface == NULL) 92 break; 93 94 count++; 95 } 96 } 97 98 return count; 99 } 100 101 102 /*! 103 Dumps a list of all interfaces into the supplied userland buffer. 104 If the interfaces don't fit into the buffer, an error (\c ENOBUFS) is 105 returned. 106 */ 107 status_t 108 list_domain_interfaces(void *_buffer, size_t *bufferSize) 109 { 110 MutexLocker locker(sDomainLock); 111 112 UserBuffer buffer(_buffer, *bufferSize); 113 net_domain_private *domain = NULL; 114 115 while (true) { 116 domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 117 if (domain == NULL) 118 break; 119 120 MutexLocker locker(domain->lock); 121 122 net_interface *interface = NULL; 123 while (true) { 124 interface = (net_interface *)list_get_next_item(&domain->interfaces, 125 interface); 126 if (interface == NULL) 127 break; 128 129 ifreq request; 130 strlcpy(request.ifr_name, interface->name, IF_NAMESIZE); 131 if (interface->address != NULL) { 132 memcpy(&request.ifr_addr, interface->address, 133 interface->address->sa_len); 134 } else { 135 // empty address 136 request.ifr_addr.sa_len = 2; 137 request.ifr_addr.sa_family = AF_UNSPEC; 138 } 139 140 if (buffer.Copy(&request, IF_NAMESIZE 141 + request.ifr_addr.sa_len) == NULL) 142 return buffer.Status(); 143 } 144 } 145 146 *bufferSize = buffer.ConsumedAmount(); 147 return B_OK; 148 } 149 150 151 status_t 152 add_interface_to_domain(net_domain *_domain, 153 struct ifreq& request) 154 { 155 net_domain_private *domain = (net_domain_private *)_domain; 156 157 const char *deviceName = request.ifr_parameter.device[0] 158 ? request.ifr_parameter.device : request.ifr_name; 159 const char *baseName = request.ifr_parameter.base_name[0] 160 ? request.ifr_parameter.base_name : request.ifr_name; 161 162 net_device_interface *deviceInterface = get_device_interface(deviceName); 163 if (deviceInterface == NULL) 164 return ENODEV; 165 166 MutexLocker locker(domain->lock); 167 168 net_interface_private *interface = NULL; 169 status_t status; 170 171 if (find_interface(domain, request.ifr_name) != NULL) 172 status = B_NAME_IN_USE; 173 else 174 status = create_interface(domain, request.ifr_name, 175 baseName, deviceInterface, &interface); 176 177 put_device_interface(deviceInterface); 178 179 if (status == B_OK) 180 list_add_item(&domain->interfaces, interface); 181 182 return status; 183 } 184 185 186 /*! 187 Removes the interface from its domain, and deletes it. 188 You need to hold the domain's lock when calling this function. 189 */ 190 status_t 191 remove_interface_from_domain(net_interface *interface) 192 { 193 net_domain_private *domain = (net_domain_private *)interface->domain; 194 195 list_remove_item(&domain->interfaces, interface); 196 delete_interface((net_interface_private *)interface); 197 return B_OK; 198 } 199 200 201 status_t 202 domain_interface_control(net_domain_private *domain, int32 option, 203 ifreq *request) 204 { 205 const char *name = request->ifr_name; 206 status_t status = B_OK; 207 208 net_device_interface *device = get_device_interface(name, false); 209 if (device == NULL) 210 return ENODEV; 211 else { 212 // The locking protocol dictates that if both the RX lock 213 // and domain locks are required, we MUST obtain the RX 214 // lock before the domain lock. This order MUST NOT ever 215 // be reversed under the penalty of deadlock. 216 RecursiveLocker _1(device->rx_lock); 217 MutexLocker _2(domain->lock); 218 219 net_interface *interface = find_interface(domain, name); 220 if (interface != NULL) { 221 switch (option) { 222 case SIOCDIFADDR: 223 remove_interface_from_domain(interface); 224 break; 225 226 case SIOCSIFFLAGS: 227 { 228 uint32 requestFlags = request->ifr_flags; 229 request->ifr_flags &= ~(IFF_UP | IFF_LINK | IFF_BROADCAST); 230 231 if ((requestFlags & IFF_UP) != (interface->flags & IFF_UP)) { 232 if (requestFlags & IFF_UP) { 233 status = interface->first_info->interface_up( 234 interface->first_protocol); 235 if (status == B_OK) 236 interface->flags |= IFF_UP; 237 } else { 238 interface_set_down(interface); 239 } 240 } 241 242 if (status == B_OK) 243 interface->flags |= request->ifr_flags; 244 break; 245 } 246 } 247 } 248 } 249 250 // If the SIOCDIFADDR call above removed the last interface 251 // associated with the device interface, this put_() will 252 // effectively remove the interface 253 put_device_interface(device); 254 255 return status; 256 } 257 258 259 void 260 domain_interface_went_down(net_interface *interface) 261 { 262 // the domain should be locked here. always check 263 // all callers to be sure. We get here via 264 // interface_set_down(). 265 266 dprintf("domain_interface_went_down(%i, %s)\n", 267 interface->domain->family, interface->name); 268 269 // domain might have been locked by: 270 // - domain_removed_device_interface() <--- here 271 // remove_interface_from_domain() 272 // delete_interface() 273 // interface_set_down() 274 // - datalink_control() <--- here 275 // interface_set_down() 276 invalidate_routes(interface->domain, interface); 277 } 278 279 280 void 281 domain_removed_device_interface(net_device_interface *interface) 282 { 283 MutexLocker locker(sDomainLock); 284 285 net_domain_private *domain = NULL; 286 while (true) { 287 domain = (net_domain_private *)list_get_next_item(&sDomains, domain); 288 if (domain == NULL) 289 break; 290 291 MutexLocker locker(domain->lock); 292 293 net_interface_private *priv = find_interface(domain, 294 interface->device->name); 295 if (priv == NULL) 296 continue; 297 298 remove_interface_from_domain(priv); 299 } 300 } 301 302 303 status_t 304 register_domain(int family, const char *name, 305 struct net_protocol_module_info *module, 306 struct net_address_module_info *addressModule, 307 net_domain **_domain) 308 { 309 TRACE(("register_domain(%d, %s)\n", family, name)); 310 MutexLocker locker(sDomainLock); 311 312 struct net_domain_private *domain = lookup_domain(family); 313 if (domain != NULL) 314 return B_NAME_IN_USE; 315 316 domain = new (std::nothrow) net_domain_private; 317 if (domain == NULL) 318 return B_NO_MEMORY; 319 320 mutex_init_etc(&domain->lock, name, MUTEX_FLAG_CLONE_NAME); 321 322 domain->family = family; 323 domain->name = name; 324 domain->module = module; 325 domain->address_module = addressModule; 326 327 list_init(&domain->interfaces); 328 329 list_add_item(&sDomains, domain); 330 331 *_domain = domain; 332 return B_OK; 333 } 334 335 336 status_t 337 unregister_domain(net_domain *_domain) 338 { 339 TRACE(("unregister_domain(%p, %d, %s)\n", _domain, _domain->family, _domain->name)); 340 341 net_domain_private *domain = (net_domain_private *)_domain; 342 MutexLocker locker(sDomainLock); 343 344 list_remove_item(&sDomains, domain); 345 346 net_interface_private *interface = NULL; 347 while (true) { 348 interface = (net_interface_private *)list_remove_head_item(&domain->interfaces); 349 if (interface == NULL) 350 break; 351 352 delete_interface(interface); 353 } 354 355 mutex_destroy(&domain->lock); 356 delete domain; 357 return B_OK; 358 } 359 360 361 status_t 362 init_domains() 363 { 364 mutex_init(&sDomainLock, "net domains"); 365 366 list_init_etc(&sDomains, offsetof(struct net_domain_private, link)); 367 return B_OK; 368 } 369 370 371 status_t 372 uninit_domains() 373 { 374 mutex_destroy(&sDomainLock); 375 return B_OK; 376 } 377 378