1 /* 2 * Copyright 2006-2018, 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 * Vegard Wærp, vegarwa@online.no 8 * Alexander von Gluck, kallisti5@unixzen.com 9 */ 10 11 12 #include "NetServer.h" 13 14 #include <errno.h> 15 #include <map> 16 #include <stdio.h> 17 #include <stdlib.h> 18 #include <string> 19 #include <strings.h> 20 #include <syslog.h> 21 #include <unistd.h> 22 23 #include <arpa/inet.h> 24 #include <net/if_dl.h> 25 #include <net/if_types.h> 26 #include <netinet/in.h> 27 #include <sys/socket.h> 28 #include <sys/sockio.h> 29 30 #include <Alert.h> 31 #include <Deskbar.h> 32 #include <Directory.h> 33 #include <Entry.h> 34 #include <NetworkDevice.h> 35 #include <NetworkInterface.h> 36 #include <NetworkRoster.h> 37 #include <NetworkSettings.h> 38 #include <Path.h> 39 #include <PathMonitor.h> 40 #include <Roster.h> 41 #include <Server.h> 42 #include <TextView.h> 43 #include <FindDirectory.h> 44 45 #include <AutoDeleter.h> 46 #include <WPASupplicant.h> 47 48 #include "AutoconfigLooper.h" 49 #include "Services.h" 50 51 extern "C" { 52 # include <freebsd_network/compat/sys/cdefs.h> 53 # include <freebsd_network/compat/sys/ioccom.h> 54 # include <net80211/ieee80211_ioctl.h> 55 } 56 57 58 using namespace BNetworkKit; 59 60 61 typedef std::map<std::string, AutoconfigLooper*> LooperMap; 62 63 64 class NetServer : public BServer { 65 public: 66 NetServer(status_t& status); 67 virtual ~NetServer(); 68 69 virtual void AboutRequested(); 70 virtual void ReadyToRun(); 71 virtual void MessageReceived(BMessage* message); 72 73 private: 74 bool _IsValidFamily(uint32 family); 75 bool _IsValidInterface(BNetworkInterface& interface); 76 void _RemoveInvalidInterfaces(); 77 status_t _RemoveInterface(const char* name); 78 status_t _DisableInterface(const char* name); 79 bool _TestForInterface(const char* name); 80 status_t _ConfigureInterface(BMessage& interface); 81 status_t _ConfigureResolver( 82 BMessage& resolverConfiguration); 83 bool _QuitLooperForDevice(const char* device); 84 AutoconfigLooper* _LooperForDevice(const char* device); 85 status_t _ConfigureDevice(const char* path); 86 void _ConfigureDevices(const char* path, 87 BStringList& devicesAlreadyConfigured, 88 BMessage* suggestedInterface = NULL); 89 void _ConfigureInterfacesFromSettings( 90 BStringList& devicesSet, 91 BMessage* _missingDevice = NULL); 92 void _ConfigureIPv6LinkLocal(const char* name); 93 94 void _BringUpInterfaces(); 95 void _StartServices(); 96 status_t _HandleDeviceMonitor(BMessage* message); 97 98 status_t _AutoJoinNetwork(const BMessage& message); 99 status_t _JoinNetwork(const BMessage& message, 100 const BNetworkAddress* address = NULL, 101 const char* name = NULL); 102 status_t _LeaveNetwork(const BMessage& message); 103 104 status_t _ConvertNetworkToSettings(BMessage& message); 105 status_t _ConvertNetworkFromSettings(BMessage& message); 106 107 private: 108 BNetworkSettings fSettings; 109 LooperMap fDeviceMap; 110 BMessenger fServices; 111 }; 112 113 114 // #pragma mark - private functions 115 116 117 static status_t 118 set_80211(const char* name, int32 type, void* data, 119 int32 length = 0, int32 value = 0) 120 { 121 int socket = ::socket(AF_INET, SOCK_DGRAM, 0); 122 if (socket < 0) 123 return errno; 124 125 FileDescriptorCloser closer(socket); 126 127 struct ieee80211req ireq; 128 strlcpy(ireq.i_name, name, IF_NAMESIZE); 129 ireq.i_type = type; 130 ireq.i_val = value; 131 ireq.i_len = length; 132 ireq.i_data = data; 133 134 if (ioctl(socket, SIOCS80211, &ireq, sizeof(struct ieee80211req)) < 0) 135 return errno; 136 137 return B_OK; 138 } 139 140 141 // #pragma mark - 142 143 144 NetServer::NetServer(status_t& error) 145 : 146 BServer(kNetServerSignature, false, &error) 147 { 148 } 149 150 151 NetServer::~NetServer() 152 { 153 BPrivate::BPathMonitor::StopWatching("/dev/net", this); 154 } 155 156 157 void 158 NetServer::AboutRequested() 159 { 160 BAlert *alert = new BAlert("about", "Networking Server\n" 161 "\tCopyright " B_UTF8_COPYRIGHT "2006, Haiku.\n", "OK"); 162 BTextView *view = alert->TextView(); 163 BFont font; 164 165 view->SetStylable(true); 166 167 view->GetFont(&font); 168 font.SetSize(18); 169 font.SetFace(B_BOLD_FACE); 170 view->SetFontAndColor(0, 17, &font); 171 172 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 173 alert->Go(NULL); 174 } 175 176 177 void 178 NetServer::ReadyToRun() 179 { 180 fSettings.StartMonitoring(this); 181 _BringUpInterfaces(); 182 _StartServices(); 183 184 BPrivate::BPathMonitor::StartWatching("/dev/net", 185 B_WATCH_FILES_ONLY | B_WATCH_RECURSIVELY, this); 186 } 187 188 189 void 190 NetServer::MessageReceived(BMessage* message) 191 { 192 switch (message->what) { 193 case B_PATH_MONITOR: 194 { 195 fSettings.Update(message); 196 _HandleDeviceMonitor(message); 197 break; 198 } 199 200 case BNetworkSettings::kMsgInterfaceSettingsUpdated: 201 { 202 BStringList devicesSet; 203 _ConfigureInterfacesFromSettings(devicesSet); 204 break; 205 } 206 207 case BNetworkSettings::kMsgServiceSettingsUpdated: 208 { 209 BMessage update = fSettings.Services(); 210 update.what = kMsgUpdateServices; 211 212 fServices.SendMessage(&update); 213 break; 214 } 215 216 case kMsgConfigureInterface: 217 { 218 status_t status = _ConfigureInterface(*message); 219 220 BMessage reply(B_REPLY); 221 reply.AddInt32("status", status); 222 message->SendReply(&reply); 223 break; 224 } 225 226 case kMsgConfigureResolver: 227 { 228 status_t status = _ConfigureResolver(*message); 229 230 BMessage reply(B_REPLY); 231 reply.AddInt32("status", status); 232 message->SendReply(&reply); 233 break; 234 } 235 236 case kMsgJoinNetwork: 237 { 238 status_t status = _JoinNetwork(*message); 239 240 BMessage reply(B_REPLY); 241 reply.AddInt32("status", status); 242 message->SendReply(&reply); 243 break; 244 } 245 246 case kMsgLeaveNetwork: 247 { 248 status_t status = _LeaveNetwork(*message); 249 250 BMessage reply(B_REPLY); 251 reply.AddInt32("status", status); 252 message->SendReply(&reply); 253 break; 254 } 255 256 case kMsgAutoJoinNetwork: 257 { 258 _AutoJoinNetwork(*message); 259 break; 260 } 261 262 case kMsgCountPersistentNetworks: 263 { 264 BMessage reply(B_REPLY); 265 reply.AddInt32("count", fSettings.CountNetworks()); 266 message->SendReply(&reply); 267 break; 268 } 269 270 case kMsgGetPersistentNetwork: 271 { 272 uint32 index = 0; 273 status_t result = message->FindInt32("index", (int32*)&index); 274 275 BMessage reply(B_REPLY); 276 if (result == B_OK) { 277 BMessage network; 278 result = fSettings.GetNextNetwork(index, network); 279 if (result == B_OK) 280 result = reply.AddMessage("network", &network); 281 } 282 283 reply.AddInt32("status", result); 284 message->SendReply(&reply); 285 break; 286 } 287 288 case kMsgAddPersistentNetwork: 289 { 290 BMessage network = *message; 291 status_t result = fSettings.AddNetwork(network); 292 293 BMessage reply(B_REPLY); 294 reply.AddInt32("status", result); 295 message->SendReply(&reply); 296 break; 297 } 298 299 case kMsgRemovePersistentNetwork: 300 { 301 const char* networkName = NULL; 302 status_t result = message->FindString("name", &networkName); 303 if (result == B_OK) 304 result = fSettings.RemoveNetwork(networkName); 305 306 BMessage reply(B_REPLY); 307 reply.AddInt32("status", result); 308 message->SendReply(&reply); 309 break; 310 } 311 312 case kMsgIsServiceRunning: 313 { 314 // Forward the message to the handler that can answer it 315 BHandler* handler = fServices.Target(NULL); 316 if (handler != NULL) 317 handler->MessageReceived(message); 318 break; 319 } 320 321 default: 322 BApplication::MessageReceived(message); 323 return; 324 } 325 } 326 327 328 /*! Checks if provided address family is valid. 329 Families include AF_INET, AF_INET6, AF_APPLETALK, etc 330 */ 331 bool 332 NetServer::_IsValidFamily(uint32 family) 333 { 334 // Mostly verifies add-on is present 335 int socket = ::socket(family, SOCK_DGRAM, 0); 336 if (socket < 0) 337 return false; 338 339 close(socket); 340 return true; 341 } 342 343 344 /*! Checks if an interface is valid, that is, if it has an address in any 345 family, and, in case of ethernet, a hardware MAC address. 346 */ 347 bool 348 NetServer::_IsValidInterface(BNetworkInterface& interface) 349 { 350 // check if it has an address 351 352 if (interface.CountAddresses() == 0) 353 return false; 354 355 // check if it has a hardware address, too, in case of ethernet 356 357 BNetworkAddress link; 358 if (interface.GetHardwareAddress(link) != B_OK) 359 return false; 360 361 if (link.LinkLevelType() == IFT_ETHER && link.LinkLevelAddressLength() != 6) 362 return false; 363 364 return true; 365 } 366 367 368 void 369 NetServer::_RemoveInvalidInterfaces() 370 { 371 BNetworkRoster& roster = BNetworkRoster::Default(); 372 BNetworkInterface interface; 373 uint32 cookie = 0; 374 375 while (roster.GetNextInterface(&cookie, interface) == B_OK) { 376 if (!_IsValidInterface(interface)) { 377 // remove invalid interface 378 _RemoveInterface(interface.Name()); 379 } 380 } 381 } 382 383 384 bool 385 NetServer::_TestForInterface(const char* name) 386 { 387 388 BNetworkRoster& roster = BNetworkRoster::Default(); 389 int32 nameLength = strlen(name); 390 BNetworkInterface interface; 391 uint32 cookie = 0; 392 393 while (roster.GetNextInterface(&cookie, interface) == B_OK) { 394 if (!strncmp(interface.Name(), name, nameLength)) 395 return true; 396 } 397 398 return false; 399 } 400 401 402 status_t 403 NetServer::_RemoveInterface(const char* name) 404 { 405 BNetworkRoster& roster = BNetworkRoster::Default(); 406 status_t status = roster.RemoveInterface(name); 407 if (status != B_OK) { 408 fprintf(stderr, "%s: Could not delete interface %s: %s\n", 409 Name(), name, strerror(status)); 410 return status; 411 } 412 413 return B_OK; 414 } 415 416 417 status_t 418 NetServer::_DisableInterface(const char* name) 419 { 420 BNetworkInterface interface(name); 421 int32 flags = interface.Flags(); 422 423 // Set interface down 424 flags &= ~(IFF_UP | IFF_AUTO_CONFIGURED | IFF_CONFIGURING); 425 426 status_t status = interface.SetFlags(flags); 427 if (status != B_OK) { 428 fprintf(stderr, "%s: Setting flags failed: %s\n", Name(), 429 strerror(status)); 430 return status; 431 } 432 433 fprintf(stderr, "%s: set %s interface down...\n", Name(), name); 434 return B_OK; 435 } 436 437 438 status_t 439 NetServer::_ConfigureInterface(BMessage& message) 440 { 441 const char* name; 442 if (message.FindString("device", &name) != B_OK) 443 return B_BAD_VALUE; 444 445 bool startAutoConfig = false; 446 447 int32 flags; 448 if (message.FindInt32("flags", &flags) != B_OK) 449 flags = IFF_UP; 450 451 bool autoConfigured; 452 if (message.FindBool("auto_configured", &autoConfigured) == B_OK 453 && autoConfigured) { 454 flags |= IFF_AUTO_CONFIGURED; 455 } 456 457 int32 mtu; 458 if (message.FindInt32("mtu", &mtu) != B_OK) 459 mtu = -1; 460 461 int32 metric; 462 if (message.FindInt32("metric", &metric) != B_OK) 463 metric = -1; 464 465 BNetworkInterface interface(name); 466 if (!interface.Exists()) { 467 // the interface does not exist yet, we have to add it first 468 BNetworkRoster& roster = BNetworkRoster::Default(); 469 470 status_t status = roster.AddInterface(interface); 471 if (status != B_OK) { 472 fprintf(stderr, "%s: Could not add interface: %s\n", 473 interface.Name(), strerror(status)); 474 return status; 475 } 476 } 477 478 // Set up IPv6 Link Local address (based on MAC, if not loopback) 479 480 // TODO: our IPv6 stack is still fairly fragile. We need more v6 work 481 // (including IPv6 address scope flags before we start attaching link 482 // local addresses by default. 483 //_ConfigureIPv6LinkLocal(name); 484 485 BMessage addressMessage; 486 for (int32 index = 0; message.FindMessage("address", index, 487 &addressMessage) == B_OK; index++) { 488 BNetworkInterfaceAddressSettings addressSettings(addressMessage); 489 490 if (addressSettings.IsAutoConfigure()) { 491 _QuitLooperForDevice(name); 492 startAutoConfig = true; 493 } else if (!addressSettings.Gateway().IsEmpty()) { 494 // add gateway route, if we're asked for it 495 interface.RemoveDefaultRoute(addressSettings.Family()); 496 // Try to remove a previous default route, doesn't matter 497 // if it fails. 498 499 status_t status = interface.AddDefaultRoute( 500 addressSettings.Gateway()); 501 if (status != B_OK) { 502 fprintf(stderr, "%s: Could not add route for %s: %s\n", 503 Name(), name, strerror(errno)); 504 } 505 } 506 507 // set address/mask/broadcast/peer 508 509 if (!addressSettings.Address().IsEmpty() 510 || !addressSettings.Mask().IsEmpty() 511 || !addressSettings.Broadcast().IsEmpty() 512 || !addressSettings.Peer().IsEmpty() 513 || !addressSettings.IsAutoConfigure()) { 514 BNetworkInterfaceAddress interfaceAddress; 515 interfaceAddress.SetAddress(addressSettings.Address()); 516 interfaceAddress.SetMask(addressSettings.Mask()); 517 if (!addressSettings.Broadcast().IsEmpty()) 518 interfaceAddress.SetBroadcast(addressSettings.Broadcast()); 519 else if (!addressSettings.Peer().IsEmpty()) 520 interfaceAddress.SetDestination(addressSettings.Peer()); 521 522 status_t status = interface.SetAddress(interfaceAddress); 523 if (status != B_OK) { 524 fprintf(stderr, "%s: Setting address failed: %s\n", Name(), 525 strerror(status)); 526 return status; 527 } 528 } 529 530 // set flags 531 532 if (flags != 0) { 533 int32 newFlags = interface.Flags(); 534 newFlags = (newFlags & ~IFF_CONFIGURING) | flags; 535 if (!autoConfigured) 536 newFlags &= ~IFF_AUTO_CONFIGURED; 537 538 status_t status = interface.SetFlags(newFlags); 539 if (status != B_OK) { 540 fprintf(stderr, "%s: Setting flags failed: %s\n", Name(), 541 strerror(status)); 542 } 543 } 544 545 // set options 546 547 if (mtu != -1) { 548 status_t status = interface.SetMTU(mtu); 549 if (status != B_OK) { 550 fprintf(stderr, "%s: Setting MTU failed: %s\n", Name(), 551 strerror(status)); 552 } 553 } 554 555 if (metric != -1) { 556 status_t status = interface.SetMetric(metric); 557 if (status != B_OK) { 558 fprintf(stderr, "%s: Setting metric failed: %s\n", Name(), 559 strerror(status)); 560 } 561 } 562 } 563 564 // Join the specified networks 565 BMessage networkMessage; 566 for (int32 index = 0; message.FindMessage("network", index, 567 &networkMessage) == B_OK; index++) { 568 const char* networkName = message.GetString("name", NULL); 569 const char* addressString = message.GetString("mac", NULL); 570 571 BNetworkAddress address; 572 status_t addressStatus = address.SetTo(AF_LINK, addressString); 573 574 BNetworkDevice device(name); 575 if (device.IsWireless() && !device.HasLink()) { 576 status_t status = _JoinNetwork(message, 577 addressStatus == B_OK ? &address : NULL, networkName); 578 if (status != B_OK) { 579 fprintf(stderr, "%s: joining network \"%s\" failed: %s\n", 580 interface.Name(), networkName, strerror(status)); 581 } 582 } 583 } 584 585 if (startAutoConfig) { 586 // start auto configuration 587 AutoconfigLooper* looper = new AutoconfigLooper(this, name); 588 looper->Run(); 589 590 fDeviceMap[name] = looper; 591 } else if (!autoConfigured) 592 _QuitLooperForDevice(name); 593 594 return B_OK; 595 } 596 597 598 status_t 599 NetServer::_ConfigureResolver(BMessage& resolverConfiguration) 600 { 601 // TODO: resolv.conf should be parsed, all information should be 602 // maintained and it should be distinguished between user entered 603 // and auto-generated parts of the file, with this method only re-writing 604 // the auto-generated parts of course. 605 606 BPath path; 607 if (find_directory(B_SYSTEM_SETTINGS_DIRECTORY, &path) != B_OK 608 || path.Append("network/resolv.conf") != B_OK) 609 return B_ERROR; 610 611 FILE* file = fopen(path.Path(), "w"); 612 if (file != NULL) { 613 const char* nameserver; 614 for (int32 i = 0; resolverConfiguration.FindString("nameserver", i, 615 &nameserver) == B_OK; i++) { 616 fprintf(file, "nameserver %s\n", nameserver); 617 } 618 619 const char* domain; 620 if (resolverConfiguration.FindString("domain", &domain) == B_OK) 621 fprintf(file, "domain %s\n", domain); 622 623 fclose(file); 624 } 625 return B_OK; 626 } 627 628 629 bool 630 NetServer::_QuitLooperForDevice(const char* device) 631 { 632 LooperMap::iterator iterator = fDeviceMap.find(device); 633 if (iterator == fDeviceMap.end()) 634 return false; 635 636 // there is a looper for this device - quit it 637 if (iterator->second->Lock()) 638 iterator->second->Quit(); 639 640 fDeviceMap.erase(iterator); 641 return true; 642 } 643 644 645 AutoconfigLooper* 646 NetServer::_LooperForDevice(const char* device) 647 { 648 LooperMap::const_iterator iterator = fDeviceMap.find(device); 649 if (iterator == fDeviceMap.end()) 650 return NULL; 651 652 return iterator->second; 653 } 654 655 656 status_t 657 NetServer::_ConfigureDevice(const char* device) 658 { 659 // bring interface up, but don't configure it just yet 660 BMessage interface; 661 interface.AddString("device", device); 662 BMessage address; 663 address.AddString("family", "inet"); 664 address.AddBool("auto_config", true); 665 interface.AddMessage("address", &address); 666 667 return _ConfigureInterface(interface); 668 } 669 670 671 /*! \brief Traverses the device tree starting from \a startPath, and configures 672 everything that has not yet been configured via settings before. 673 674 \param suggestedInterface Contains the configuration of an interface that 675 does not have any hardware left. It is used to configure the first 676 unconfigured device. This allows to move a Haiku configuration around 677 without losing the network configuration. 678 */ 679 void 680 NetServer::_ConfigureDevices(const char* startPath, 681 BStringList& devicesAlreadyConfigured, BMessage* suggestedInterface) 682 { 683 BDirectory directory(startPath); 684 BEntry entry; 685 while (directory.GetNextEntry(&entry) == B_OK) { 686 char name[B_FILE_NAME_LENGTH]; 687 struct stat stat; 688 BPath path; 689 if (entry.GetName(name) != B_OK 690 || entry.GetPath(&path) != B_OK 691 || entry.GetStat(&stat) != B_OK) 692 continue; 693 694 if (S_ISBLK(stat.st_mode) || S_ISCHR(stat.st_mode)) { 695 if (suggestedInterface != NULL 696 && suggestedInterface->SetString("device", path.Path()) == B_OK 697 && _ConfigureInterface(*suggestedInterface) == B_OK) 698 suggestedInterface = NULL; 699 else if (!devicesAlreadyConfigured.HasString(path.Path())) 700 _ConfigureDevice(path.Path()); 701 } else if (entry.IsDirectory()) { 702 _ConfigureDevices(path.Path(), devicesAlreadyConfigured, 703 suggestedInterface); 704 } 705 } 706 } 707 708 709 void 710 NetServer::_ConfigureInterfacesFromSettings(BStringList& devicesSet, 711 BMessage* _missingDevice) 712 { 713 BMessage interface; 714 uint32 cookie = 0; 715 bool missing = false; 716 while (fSettings.GetNextInterface(cookie, interface) == B_OK) { 717 const char *device; 718 if (interface.FindString("device", &device) != B_OK) 719 continue; 720 721 bool disabled = false; 722 if (interface.FindBool("disabled", &disabled) == B_OK && disabled) { 723 // disabled by user request 724 _DisableInterface(device); 725 continue; 726 } 727 728 if (!strncmp(device, "/dev/net/", 9)) { 729 // it's a kernel device, check if it's present 730 BEntry entry(device); 731 if (!entry.Exists()) { 732 if (!missing && _missingDevice != NULL) { 733 *_missingDevice = interface; 734 missing = true; 735 } 736 continue; 737 } 738 } 739 740 if (_ConfigureInterface(interface) == B_OK) 741 devicesSet.Add(device); 742 } 743 } 744 745 746 void 747 NetServer::_BringUpInterfaces() 748 { 749 // we need a socket to talk to the networking stack 750 if (!_IsValidFamily(AF_LINK)) { 751 fprintf(stderr, "%s: The networking stack doesn't seem to be " 752 "available.\n", Name()); 753 Quit(); 754 return; 755 } 756 757 _RemoveInvalidInterfaces(); 758 759 // First, we look into the settings, and try to bring everything up from 760 // there 761 762 BStringList devicesAlreadyConfigured; 763 BMessage missingDevice; 764 _ConfigureInterfacesFromSettings(devicesAlreadyConfigured, &missingDevice); 765 766 // Check configuration 767 768 if (!_TestForInterface("loop")) { 769 // there is no loopback interface, create one 770 BMessage interface; 771 interface.AddString("device", "loop"); 772 BMessage v4address; 773 v4address.AddString("family", "inet"); 774 v4address.AddString("address", "127.0.0.1"); 775 interface.AddMessage("address", &v4address); 776 777 // Check for IPv6 support and add ::1 778 if (_IsValidFamily(AF_INET6)) { 779 BMessage v6address; 780 v6address.AddString("family", "inet6"); 781 v6address.AddString("address", "::1"); 782 interface.AddMessage("address", &v6address); 783 } 784 _ConfigureInterface(interface); 785 } 786 787 // TODO: also check if the networking driver is correctly initialized! 788 // (and check for other devices to take over its configuration) 789 790 // There is no driver configured - see if there is one and try to use it 791 _ConfigureDevices("/dev/net", devicesAlreadyConfigured, 792 missingDevice.HasString("device") ? &missingDevice : NULL); 793 } 794 795 796 /*! Configure the link local address based on the network card's MAC address 797 if this isn't a loopback device. 798 */ 799 void 800 NetServer::_ConfigureIPv6LinkLocal(const char* name) 801 { 802 // Check for IPv6 support 803 if (!_IsValidFamily(AF_INET6)) 804 return; 805 806 BNetworkInterface interface(name); 807 808 // Lets make sure this is *not* the loopback interface 809 if ((interface.Flags() & IFF_LOOPBACK) != 0) 810 return; 811 812 BNetworkAddress link; 813 status_t result = interface.GetHardwareAddress(link); 814 815 if (result != B_OK || link.LinkLevelAddressLength() != 6) 816 return; 817 818 const uint8* mac = link.LinkLevelAddress(); 819 820 // Check for a few failure situations 821 static const uint8 zeroMac[6] = {0, 0, 0, 0, 0, 0}; 822 static const uint8 fullMac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; 823 if (memcmp(mac, zeroMac, 6) == 0 824 || memcmp(mac, fullMac, 6) == 0) { 825 // Mac address is all 0 or all FF's 826 syslog(LOG_DEBUG, "%s: MacAddress for interface '%s' is invalid.", 827 __func__, name); 828 return; 829 } 830 831 // Generate a Link Local Scope address 832 // (IPv6 address based on Mac address) 833 in6_addr addressRaw; 834 memset(addressRaw.s6_addr, 0, sizeof(addressRaw.s6_addr)); 835 addressRaw.s6_addr[0] = 0xfe; 836 addressRaw.s6_addr[1] = 0x80; 837 addressRaw.s6_addr[8] = mac[0] ^ 0x02; 838 addressRaw.s6_addr[9] = mac[1]; 839 addressRaw.s6_addr[10] = mac[2]; 840 addressRaw.s6_addr[11] = 0xff; 841 addressRaw.s6_addr[12] = 0xfe; 842 addressRaw.s6_addr[13] = mac[3]; 843 addressRaw.s6_addr[14] = mac[4]; 844 addressRaw.s6_addr[15] = mac[5]; 845 846 BNetworkAddress localLinkAddress(addressRaw, 0); 847 BNetworkAddress localLinkMask("ffff:ffff:ffff:ffff::"); // 64 848 BNetworkAddress localLinkBroadcast("fe80::ffff:ffff:ffff:ffff"); 849 850 if (interface.FindAddress(localLinkAddress) >= 0) { 851 // uhoh... already has a local link address 852 853 /* TODO: Check for any local link scope addresses assigned to card 854 There isn't any flag at the moment though for address scope 855 */ 856 syslog(LOG_DEBUG, "%s: Local Link address already assigned to %s\n", 857 __func__, name); 858 return; 859 } 860 861 BNetworkInterfaceAddress interfaceAddress; 862 interfaceAddress.SetAddress(localLinkAddress); 863 interfaceAddress.SetMask(localLinkMask); 864 interfaceAddress.SetBroadcast(localLinkMask); 865 866 /* TODO: Duplicate Address Detection. (DAD) 867 Need to blast an icmp packet over the IPv6 network from :: to ensure 868 there aren't duplicate MAC addresses on the network. (definitely an 869 edge case, but a possible issue) 870 */ 871 872 interface.AddAddress(interfaceAddress); 873 } 874 875 876 void 877 NetServer::_StartServices() 878 { 879 BHandler* services = new (std::nothrow) Services(fSettings.Services()); 880 if (services != NULL) { 881 AddHandler(services); 882 fServices = BMessenger(services); 883 } 884 } 885 886 887 status_t 888 NetServer::_HandleDeviceMonitor(BMessage* message) 889 { 890 int32 opcode; 891 const char* path; 892 if (message->FindInt32("opcode", &opcode) != B_OK 893 || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED) 894 || message->FindString("path", &path) != B_OK) 895 return B_BAD_VALUE; 896 897 if (strncmp(path, "/dev/net/", 9)) { 898 // not a valid device entry, ignore 899 return B_NAME_NOT_FOUND; 900 } 901 902 if (opcode == B_ENTRY_CREATED) 903 _ConfigureDevice(path); 904 else 905 _RemoveInterface(path); 906 907 return B_OK; 908 } 909 910 911 status_t 912 NetServer::_AutoJoinNetwork(const BMessage& message) 913 { 914 const char* name = NULL; 915 if (message.FindString("device", &name) != B_OK) 916 return B_BAD_VALUE; 917 918 BNetworkDevice device(name); 919 920 // Choose among configured networks 921 922 uint32 cookie = 0; 923 BMessage networkMessage; 924 while (fSettings.GetNextNetwork(cookie, networkMessage) == B_OK) { 925 status_t status = B_ERROR; 926 wireless_network network; 927 const char* networkName; 928 BNetworkAddress link; 929 930 const char* mac = NULL; 931 if (networkMessage.FindString("mac", &mac) == B_OK) { 932 link.SetTo(AF_LINK, mac); 933 status = device.GetNetwork(link, network); 934 } else if (networkMessage.FindString("name", &networkName) == B_OK) 935 status = device.GetNetwork(networkName, network); 936 937 if (status == B_OK) { 938 status = _JoinNetwork(message, mac != NULL ? &link : NULL, 939 network.name); 940 printf("auto join network \"%s\": %s\n", network.name, 941 strerror(status)); 942 if (status == B_OK) 943 return B_OK; 944 } 945 } 946 947 return B_NO_INIT; 948 } 949 950 951 status_t 952 NetServer::_JoinNetwork(const BMessage& message, const BNetworkAddress* address, 953 const char* name) 954 { 955 const char* deviceName; 956 if (message.FindString("device", &deviceName) != B_OK) 957 return B_BAD_VALUE; 958 959 BNetworkAddress deviceAddress; 960 message.FindFlat("address", &deviceAddress); 961 if (address == NULL) 962 address = &deviceAddress; 963 964 if (name == NULL) 965 message.FindString("name", &name); 966 if (name == NULL) { 967 // No name specified, we need a network address 968 if (address->Family() != AF_LINK) 969 return B_BAD_VALUE; 970 } 971 972 // Search for a network configuration that may override the defaults 973 974 bool found = false; 975 uint32 cookie = 0; 976 BMessage networkMessage; 977 while (fSettings.GetNextNetwork(cookie, networkMessage) == B_OK) { 978 const char* networkName; 979 if (networkMessage.FindString("name", &networkName) == B_OK 980 && name != NULL && address->Family() != AF_LINK 981 && !strcmp(name, networkName)) { 982 found = true; 983 break; 984 } 985 986 const char* mac; 987 if (networkMessage.FindString("mac", &mac) == B_OK 988 && address->Family() == AF_LINK) { 989 BNetworkAddress link(AF_LINK, mac); 990 if (link == *address) { 991 found = true; 992 break; 993 } 994 } 995 } 996 997 const char* password; 998 if (message.FindString("password", &password) != B_OK && found) 999 password = networkMessage.FindString("password"); 1000 1001 // Get network 1002 BNetworkDevice device(deviceName); 1003 wireless_network network; 1004 1005 bool askForConfig = false; 1006 if ((address->Family() != AF_LINK 1007 || device.GetNetwork(*address, network) != B_OK) 1008 && device.GetNetwork(name, network) != B_OK) { 1009 // We did not find a network - just ignore that, and continue 1010 // with some defaults 1011 strlcpy(network.name, name != NULL ? name : "", sizeof(network.name)); 1012 network.address = *address; 1013 network.authentication_mode = B_NETWORK_AUTHENTICATION_NONE; 1014 network.cipher = 0; 1015 network.group_cipher = 0; 1016 network.key_mode = 0; 1017 askForConfig = true; 1018 } 1019 1020 const char* string; 1021 if (message.FindString("authentication", &string) == B_OK 1022 || (found && networkMessage.FindString("authentication", &string) 1023 == B_OK)) { 1024 askForConfig = false; 1025 if (!strcasecmp(string, "wpa2")) { 1026 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2; 1027 network.key_mode = B_KEY_MODE_IEEE802_1X; 1028 network.cipher = network.group_cipher = B_NETWORK_CIPHER_CCMP; 1029 } else if (!strcasecmp(string, "wpa")) { 1030 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA; 1031 network.key_mode = B_KEY_MODE_IEEE802_1X; 1032 network.cipher = network.group_cipher = B_NETWORK_CIPHER_TKIP; 1033 } else if (!strcasecmp(string, "wep")) { 1034 network.authentication_mode = B_NETWORK_AUTHENTICATION_WEP; 1035 network.key_mode = B_KEY_MODE_NONE; 1036 network.cipher = network.group_cipher = B_NETWORK_CIPHER_WEP_40; 1037 } else if (strcasecmp(string, "none") && strcasecmp(string, "open")) { 1038 fprintf(stderr, "%s: invalid authentication mode.\n", name); 1039 askForConfig = true; 1040 } 1041 } 1042 1043 // We always try to join via the wpa_supplicant. Even if we could join 1044 // ourselves, we need to make sure that the wpa_supplicant knows about 1045 // our intention, as otherwise it would interfere with it. 1046 1047 BMessenger wpaSupplicant(kWPASupplicantSignature); 1048 if (!wpaSupplicant.IsValid()) { 1049 // The wpa_supplicant isn't running yet, we may join ourselves. 1050 if (!askForConfig 1051 && network.authentication_mode == B_NETWORK_AUTHENTICATION_NONE) { 1052 // We can join this network ourselves. 1053 status_t status = set_80211(deviceName, IEEE80211_IOC_SSID, 1054 network.name, strlen(network.name)); 1055 if (status != B_OK) { 1056 fprintf(stderr, "%s: joining SSID failed: %s\n", name, 1057 strerror(status)); 1058 return status; 1059 } 1060 } 1061 1062 // We need the supplicant, try to launch it. 1063 status_t status = be_roster->Launch(kWPASupplicantSignature); 1064 if (status != B_OK && status != B_ALREADY_RUNNING) 1065 return status; 1066 1067 wpaSupplicant.SetTo(kWPASupplicantSignature); 1068 if (!wpaSupplicant.IsValid()) 1069 return B_ERROR; 1070 } 1071 1072 // TODO: listen to notifications from the supplicant! 1073 1074 BMessage join(kMsgWPAJoinNetwork); 1075 status_t status = join.AddString("device", deviceName); 1076 if (status == B_OK) 1077 status = join.AddString("name", network.name); 1078 if (status == B_OK) 1079 status = join.AddFlat("address", &network.address); 1080 if (status == B_OK && !askForConfig) 1081 status = join.AddUInt32("authentication", network.authentication_mode); 1082 if (status == B_OK && password != NULL) 1083 status = join.AddString("password", password); 1084 if (status != B_OK) 1085 return status; 1086 1087 status = wpaSupplicant.SendMessage(&join); 1088 if (status != B_OK) 1089 return status; 1090 1091 return B_OK; 1092 } 1093 1094 1095 status_t 1096 NetServer::_LeaveNetwork(const BMessage& message) 1097 { 1098 const char* deviceName; 1099 if (message.FindString("device", &deviceName) != B_OK) 1100 return B_BAD_VALUE; 1101 1102 int32 reason; 1103 if (message.FindInt32("reason", &reason) != B_OK) 1104 reason = IEEE80211_REASON_AUTH_LEAVE; 1105 1106 // We always try to send the leave request to the wpa_supplicant. 1107 1108 BMessenger wpaSupplicant(kWPASupplicantSignature); 1109 if (wpaSupplicant.IsValid()) { 1110 BMessage leave(kMsgWPALeaveNetwork); 1111 status_t status = leave.AddString("device", deviceName); 1112 if (status == B_OK) 1113 status = leave.AddInt32("reason", reason); 1114 if (status != B_OK) 1115 return status; 1116 1117 status = wpaSupplicant.SendMessage(&leave); 1118 if (status == B_OK) 1119 return B_OK; 1120 } 1121 1122 // The wpa_supplicant doesn't seem to be running, check if this was an open 1123 // network we connected ourselves. 1124 BNetworkDevice device(deviceName); 1125 wireless_network network; 1126 1127 uint32 cookie = 0; 1128 if (device.GetNextAssociatedNetwork(cookie, network) != B_OK 1129 || network.authentication_mode != B_NETWORK_AUTHENTICATION_NONE) { 1130 // We didn't join ourselves, we can't do much. 1131 return B_ERROR; 1132 } 1133 1134 // We joined ourselves, so we can just disassociate again. 1135 ieee80211req_mlme mlmeRequest; 1136 memset(&mlmeRequest, 0, sizeof(mlmeRequest)); 1137 mlmeRequest.im_op = IEEE80211_MLME_DISASSOC; 1138 mlmeRequest.im_reason = reason; 1139 1140 return set_80211(deviceName, IEEE80211_IOC_MLME, &mlmeRequest, 1141 sizeof(mlmeRequest)); 1142 } 1143 1144 1145 // #pragma mark - 1146 1147 1148 int 1149 main(int argc, char** argv) 1150 { 1151 srand(system_time()); 1152 1153 status_t status; 1154 NetServer server(status); 1155 if (status != B_OK) { 1156 fprintf(stderr, "net_server: Failed to create application: %s\n", 1157 strerror(status)); 1158 return 1; 1159 } 1160 1161 server.Run(); 1162 return 0; 1163 } 1164 1165