1 /* 2 * Copyright 2010, Axel Dörfler, axeld@pinc-software.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include <NetworkInterface.h> 8 9 #include <errno.h> 10 #include <net/if.h> 11 #include <sys/sockio.h> 12 13 #include <AutoDeleter.h> 14 15 16 static int 17 family_from_interface_address(const BNetworkInterfaceAddress& address) 18 { 19 if (address.Address().Family() != AF_UNSPEC) 20 return address.Address().Family(); 21 if (address.Mask().Family() != AF_UNSPEC) 22 return address.Mask().Family(); 23 if (address.Destination().Family() != AF_UNSPEC) 24 return address.Destination().Family(); 25 26 return AF_INET; 27 } 28 29 30 static status_t 31 do_ifaliasreq(const char* name, int32 option, BNetworkInterfaceAddress& address, 32 bool readBack = false) 33 { 34 int family = AF_INET; 35 if (!readBack) 36 family = family_from_interface_address(address); 37 38 int socket = ::socket(family, SOCK_DGRAM, 0); 39 if (socket < 0) 40 return errno; 41 42 FileDescriptorCloser closer(socket); 43 44 ifaliasreq request; 45 strlcpy(request.ifra_name, name, IF_NAMESIZE); 46 request.ifra_index = address.Index(); 47 request.ifra_flags = address.Flags(); 48 49 memcpy(&request.ifra_addr, &address.Address().SockAddr(), 50 address.Address().Length()); 51 memcpy(&request.ifra_mask, &address.Mask().SockAddr(), 52 address.Mask().Length()); 53 memcpy(&request.ifra_broadaddr, &address.Broadcast().SockAddr(), 54 address.Broadcast().Length()); 55 56 if (ioctl(socket, option, &request, sizeof(struct ifaliasreq)) < 0) 57 return errno; 58 59 if (readBack) { 60 address.SetFlags(request.ifra_flags); 61 address.Address().SetTo(request.ifra_addr); 62 address.Mask().SetTo(request.ifra_mask); 63 address.Broadcast().SetTo(request.ifra_broadaddr); 64 } 65 66 return B_OK; 67 } 68 69 70 static status_t 71 do_ifaliasreq(const char* name, int32 option, 72 const BNetworkInterfaceAddress& address) 73 { 74 return do_ifaliasreq(name, option, 75 const_cast<BNetworkInterfaceAddress&>(address)); 76 } 77 78 79 static status_t 80 do_request(int family, ifreq& request, const char* name, int option) 81 { 82 int socket = ::socket(family, SOCK_DGRAM, 0); 83 if (socket < 0) 84 return errno; 85 86 FileDescriptorCloser closer(socket); 87 88 strlcpy(request.ifr_name, name, IF_NAMESIZE); 89 90 if (ioctl(socket, option, &request, sizeof(struct ifreq)) < 0) 91 return errno; 92 93 return B_OK; 94 } 95 96 97 // #pragma mark - 98 99 100 BNetworkInterfaceAddress::BNetworkInterfaceAddress() 101 : 102 fIndex(-1), 103 fFlags(0) 104 { 105 } 106 107 108 BNetworkInterfaceAddress::~BNetworkInterfaceAddress() 109 { 110 } 111 112 113 status_t 114 BNetworkInterfaceAddress::SetTo(const BNetworkInterface& interface, int32 index) 115 { 116 fIndex = index; 117 return do_ifaliasreq(interface.Name(), B_SOCKET_GET_ALIAS, *this, true); 118 } 119 120 121 void 122 BNetworkInterfaceAddress::SetAddress(const BNetworkAddress& address) 123 { 124 fAddress = address; 125 } 126 127 128 void 129 BNetworkInterfaceAddress::SetMask(const BNetworkAddress& mask) 130 { 131 fMask = mask; 132 } 133 134 135 void 136 BNetworkInterfaceAddress::SetBroadcast(const BNetworkAddress& broadcast) 137 { 138 fBroadcast = broadcast; 139 } 140 141 142 void 143 BNetworkInterfaceAddress::SetDestination(const BNetworkAddress& destination) 144 { 145 fBroadcast = destination; 146 } 147 148 149 void 150 BNetworkInterfaceAddress::SetFlags(uint32 flags) 151 { 152 fFlags = flags; 153 } 154 155 156 // #pragma mark - 157 158 159 BNetworkInterface::BNetworkInterface() 160 { 161 Unset(); 162 } 163 164 165 BNetworkInterface::BNetworkInterface(const char* name) 166 { 167 SetTo(name); 168 } 169 170 171 BNetworkInterface::BNetworkInterface(uint32 index) 172 { 173 SetTo(index); 174 } 175 176 177 BNetworkInterface::~BNetworkInterface() 178 { 179 } 180 181 182 void 183 BNetworkInterface::Unset() 184 { 185 fName[0] = '\0'; 186 } 187 188 189 void 190 BNetworkInterface::SetTo(const char* name) 191 { 192 strlcpy(fName, name, IF_NAMESIZE); 193 } 194 195 196 status_t 197 BNetworkInterface::SetTo(uint32 index) 198 { 199 ifreq request; 200 request.ifr_index = index; 201 202 status_t status = do_request(AF_INET, request, "", SIOCGIFNAME); 203 if (status != B_OK) 204 return status; 205 206 strlcpy(fName, request.ifr_name, IF_NAMESIZE); 207 return B_OK; 208 } 209 210 211 bool 212 BNetworkInterface::Exists() const 213 { 214 ifreq request; 215 return do_request(AF_INET, request, Name(), SIOCGIFINDEX) == B_OK; 216 } 217 218 219 const char* 220 BNetworkInterface::Name() const 221 { 222 return fName; 223 } 224 225 226 uint32 227 BNetworkInterface::Flags() const 228 { 229 ifreq request; 230 if (do_request(AF_INET, request, Name(), SIOCGIFFLAGS) != B_OK) 231 return 0; 232 233 return request.ifr_flags; 234 } 235 236 237 uint32 238 BNetworkInterface::MTU() const 239 { 240 ifreq request; 241 if (do_request(AF_INET, request, Name(), SIOCGIFMTU) != B_OK) 242 return 0; 243 244 return request.ifr_mtu; 245 } 246 247 248 int32 249 BNetworkInterface::Media() const 250 { 251 ifreq request; 252 if (do_request(AF_INET, request, Name(), SIOCGIFMEDIA) != B_OK) 253 return -1; 254 255 return request.ifr_media; 256 } 257 258 259 uint32 260 BNetworkInterface::Metric() const 261 { 262 ifreq request; 263 if (do_request(AF_INET, request, Name(), SIOCGIFMETRIC) != B_OK) 264 return 0; 265 266 return request.ifr_metric; 267 } 268 269 270 uint32 271 BNetworkInterface::Type() const 272 { 273 ifreq request; 274 if (do_request(AF_INET, request, Name(), SIOCGIFTYPE) != B_OK) 275 return 0; 276 277 return request.ifr_type; 278 } 279 280 281 status_t 282 BNetworkInterface::GetStats(ifreq_stats& stats) 283 { 284 ifreq request; 285 status_t status = do_request(AF_INET, request, Name(), SIOCGIFSTATS); 286 if (status != B_OK) 287 return status; 288 289 memcpy(&stats, &request.ifr_stats, sizeof(ifreq_stats)); 290 return B_OK; 291 } 292 293 294 bool 295 BNetworkInterface::HasLink() const 296 { 297 return (Flags() & IFF_LINK) != 0; 298 } 299 300 301 status_t 302 BNetworkInterface::SetFlags(uint32 flags) 303 { 304 ifreq request; 305 request.ifr_flags = flags; 306 return do_request(AF_INET, request, Name(), SIOCSIFFLAGS); 307 } 308 309 310 status_t 311 BNetworkInterface::SetMTU(uint32 mtu) 312 { 313 ifreq request; 314 request.ifr_mtu = mtu; 315 return do_request(AF_INET, request, Name(), SIOCSIFMTU); 316 } 317 318 319 status_t 320 BNetworkInterface::SetMedia(int32 media) 321 { 322 ifreq request; 323 request.ifr_media = media; 324 return do_request(AF_INET, request, Name(), SIOCSIFMEDIA); 325 } 326 327 328 status_t 329 BNetworkInterface::SetMetric(uint32 metric) 330 { 331 ifreq request; 332 request.ifr_metric = metric; 333 return do_request(AF_INET, request, Name(), SIOCSIFMETRIC); 334 } 335 336 337 int32 338 BNetworkInterface::CountAddresses() const 339 { 340 ifreq request; 341 if (do_request(AF_INET, request, Name(), B_SOCKET_COUNT_ALIASES) != B_OK) 342 return 0; 343 344 return request.ifr_count; 345 } 346 347 348 status_t 349 BNetworkInterface::GetAddressAt(int32 index, BNetworkInterfaceAddress& address) 350 { 351 return address.SetTo(*this, index); 352 } 353 354 355 int32 356 BNetworkInterface::FindAddress(const BNetworkAddress& address) 357 { 358 int socket = ::socket(address.Family(), SOCK_DGRAM, 0); 359 if (socket < 0) 360 return errno; 361 362 FileDescriptorCloser closer(socket); 363 364 ifaliasreq request; 365 memset(&request, 0, sizeof(ifaliasreq)); 366 367 strlcpy(request.ifra_name, Name(), IF_NAMESIZE); 368 request.ifra_index = -1; 369 memcpy(&request.ifra_addr, &address.SockAddr(), address.Length()); 370 371 if (ioctl(socket, B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq)) 372 < 0) 373 return errno; 374 375 return request.ifra_index; 376 } 377 378 379 int32 380 BNetworkInterface::FindFirstAddress(int family) 381 { 382 int socket = ::socket(family, SOCK_DGRAM, 0); 383 if (socket < 0) 384 return errno; 385 386 FileDescriptorCloser closer(socket); 387 388 ifaliasreq request; 389 memset(&request, 0, sizeof(ifaliasreq)); 390 391 strlcpy(request.ifra_name, Name(), IF_NAMESIZE); 392 request.ifra_index = -1; 393 request.ifra_addr.ss_family = AF_UNSPEC; 394 395 if (ioctl(socket, B_SOCKET_GET_ALIAS, &request, sizeof(struct ifaliasreq)) 396 < 0) 397 return errno; 398 399 return request.ifra_index; 400 } 401 402 403 status_t 404 BNetworkInterface::AddAddress(const BNetworkInterfaceAddress& address) 405 { 406 return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address); 407 } 408 409 410 status_t 411 BNetworkInterface::AddAddress(const BNetworkAddress& local) 412 { 413 BNetworkInterfaceAddress address; 414 address.SetAddress(local); 415 416 return do_ifaliasreq(Name(), B_SOCKET_ADD_ALIAS, address); 417 } 418 419 420 status_t 421 BNetworkInterface::SetAddress(const BNetworkInterfaceAddress& address) 422 { 423 return do_ifaliasreq(Name(), B_SOCKET_SET_ALIAS, address); 424 } 425 426 427 status_t 428 BNetworkInterface::RemoveAddress(const BNetworkInterfaceAddress& address) 429 { 430 ifreq request; 431 memcpy(&request.ifr_addr, &address.Address().SockAddr(), 432 address.Address().Length()); 433 434 return do_request(family_from_interface_address(address), request, Name(), 435 B_SOCKET_REMOVE_ALIAS); 436 } 437 438 439 status_t 440 BNetworkInterface::RemoveAddress(const BNetworkAddress& address) 441 { 442 ifreq request; 443 memcpy(&request.ifr_addr, &address.SockAddr(), address.Length()); 444 445 return do_request(address.Family(), request, Name(), B_SOCKET_REMOVE_ALIAS); 446 } 447 448 449 status_t 450 BNetworkInterface::RemoveAddressAt(int32 index) 451 { 452 BNetworkInterfaceAddress address; 453 status_t status = GetAddressAt(index, address); 454 if (status != B_OK) 455 return status; 456 457 return RemoveAddress(address); 458 } 459 460 461 status_t 462 BNetworkInterface::GetHardwareAddress(BNetworkAddress& address) 463 { 464 int socket = ::socket(AF_LINK, SOCK_DGRAM, 0); 465 if (socket < 0) 466 return errno; 467 468 FileDescriptorCloser closer(socket); 469 470 ifreq request; 471 strlcpy(request.ifr_name, Name(), IF_NAMESIZE); 472 473 if (ioctl(socket, SIOCGIFADDR, &request, sizeof(struct ifreq)) < 0) 474 return errno; 475 476 address.SetTo(request.ifr_addr); 477 return B_OK; 478 } 479