btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / servers / net / NetServer.cpp
blob22670eda911315ae64b2d9e2bfb5aafe5eeaeec5
1 /*
2 * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
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 */
12 #include "NetServer.h"
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>
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>
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>
45 #include <AutoDeleter.h>
46 #include <WPASupplicant.h>
48 #include "AutoconfigLooper.h"
49 #include "Services.h"
51 extern "C" {
52 # include <net80211/ieee80211_ioctl.h>
56 using namespace BNetworkKit;
59 typedef std::map<std::string, AutoconfigLooper*> LooperMap;
62 class NetServer : public BServer {
63 public:
64 NetServer(status_t& status);
65 virtual ~NetServer();
67 virtual void AboutRequested();
68 virtual void ReadyToRun();
69 virtual void MessageReceived(BMessage* message);
71 private:
72 bool _IsValidFamily(uint32 family);
73 bool _IsValidInterface(BNetworkInterface& interface);
74 void _RemoveInvalidInterfaces();
75 status_t _RemoveInterface(const char* name);
76 status_t _DisableInterface(const char* name);
77 bool _TestForInterface(const char* name);
78 status_t _ConfigureInterface(BMessage& interface);
79 status_t _ConfigureResolver(
80 BMessage& resolverConfiguration);
81 bool _QuitLooperForDevice(const char* device);
82 AutoconfigLooper* _LooperForDevice(const char* device);
83 status_t _ConfigureDevice(const char* path);
84 void _ConfigureDevices(const char* path,
85 BMessage* suggestedInterface = NULL);
86 void _ConfigureInterfacesFromSettings(
87 BMessage* _missingDevice = NULL);
88 void _ConfigureIPv6LinkLocal(const char* name);
90 void _BringUpInterfaces();
91 void _StartServices();
92 status_t _HandleDeviceMonitor(BMessage* message);
94 status_t _AutoJoinNetwork(const BMessage& message);
95 status_t _JoinNetwork(const BMessage& message,
96 const BNetworkAddress* address = NULL,
97 const char* name = NULL);
98 status_t _LeaveNetwork(const BMessage& message);
100 status_t _ConvertNetworkToSettings(BMessage& message);
101 status_t _ConvertNetworkFromSettings(BMessage& message);
103 private:
104 BNetworkSettings fSettings;
105 LooperMap fDeviceMap;
106 BMessenger fServices;
110 // #pragma mark - private functions
113 static status_t
114 set_80211(const char* name, int32 type, void* data,
115 int32 length = 0, int32 value = 0)
117 int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
118 if (socket < 0)
119 return errno;
121 FileDescriptorCloser closer(socket);
123 struct ieee80211req ireq;
124 strlcpy(ireq.i_name, name, IF_NAMESIZE);
125 ireq.i_type = type;
126 ireq.i_val = value;
127 ireq.i_len = length;
128 ireq.i_data = data;
130 if (ioctl(socket, SIOCS80211, &ireq, sizeof(struct ieee80211req)) < 0)
131 return errno;
133 return B_OK;
137 // #pragma mark -
140 NetServer::NetServer(status_t& error)
142 BServer(kNetServerSignature, false, &error)
147 NetServer::~NetServer()
149 BPrivate::BPathMonitor::StopWatching("/dev/net", this);
153 void
154 NetServer::AboutRequested()
156 BAlert *alert = new BAlert("about", "Networking Server\n"
157 "\tCopyright " B_UTF8_COPYRIGHT "2006, Haiku.\n", "OK");
158 BTextView *view = alert->TextView();
159 BFont font;
161 view->SetStylable(true);
163 view->GetFont(&font);
164 font.SetSize(18);
165 font.SetFace(B_BOLD_FACE);
166 view->SetFontAndColor(0, 17, &font);
168 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
169 alert->Go(NULL);
173 void
174 NetServer::ReadyToRun()
176 fSettings.StartMonitoring(this);
177 _BringUpInterfaces();
178 _StartServices();
180 BPrivate::BPathMonitor::StartWatching("/dev/net",
181 B_WATCH_FILES_ONLY | B_WATCH_RECURSIVELY, this);
185 void
186 NetServer::MessageReceived(BMessage* message)
188 switch (message->what) {
189 case B_PATH_MONITOR:
191 fSettings.Update(message);
192 _HandleDeviceMonitor(message);
193 break;
196 case BNetworkSettings::kMsgInterfaceSettingsUpdated:
198 _ConfigureInterfacesFromSettings();
199 break;
202 case BNetworkSettings::kMsgServiceSettingsUpdated:
204 BMessage update = fSettings.Services();
205 update.what = kMsgUpdateServices;
207 fServices.SendMessage(&update);
208 break;
211 case kMsgConfigureInterface:
213 status_t status = _ConfigureInterface(*message);
215 BMessage reply(B_REPLY);
216 reply.AddInt32("status", status);
217 message->SendReply(&reply);
218 break;
221 case kMsgConfigureResolver:
223 status_t status = _ConfigureResolver(*message);
225 BMessage reply(B_REPLY);
226 reply.AddInt32("status", status);
227 message->SendReply(&reply);
228 break;
231 case kMsgJoinNetwork:
233 status_t status = _JoinNetwork(*message);
235 BMessage reply(B_REPLY);
236 reply.AddInt32("status", status);
237 message->SendReply(&reply);
238 break;
241 case kMsgLeaveNetwork:
243 status_t status = _LeaveNetwork(*message);
245 BMessage reply(B_REPLY);
246 reply.AddInt32("status", status);
247 message->SendReply(&reply);
248 break;
251 case kMsgAutoJoinNetwork:
253 _AutoJoinNetwork(*message);
254 break;
257 case kMsgCountPersistentNetworks:
259 BMessage reply(B_REPLY);
260 reply.AddInt32("count", fSettings.CountNetworks());
261 message->SendReply(&reply);
262 break;
265 case kMsgGetPersistentNetwork:
267 uint32 index = 0;
268 status_t result = message->FindInt32("index", (int32*)&index);
270 BMessage reply(B_REPLY);
271 if (result == B_OK) {
272 BMessage network;
273 result = fSettings.GetNextNetwork(index, network);
274 if (result == B_OK)
275 result = reply.AddMessage("network", &network);
278 reply.AddInt32("status", result);
279 message->SendReply(&reply);
280 break;
283 case kMsgAddPersistentNetwork:
285 BMessage network = *message;
286 status_t result = fSettings.AddNetwork(network);
288 BMessage reply(B_REPLY);
289 reply.AddInt32("status", result);
290 message->SendReply(&reply);
291 break;
294 case kMsgRemovePersistentNetwork:
296 const char* networkName = NULL;
297 status_t result = message->FindString("name", &networkName);
298 if (result == B_OK)
299 result = fSettings.RemoveNetwork(networkName);
301 BMessage reply(B_REPLY);
302 reply.AddInt32("status", result);
303 message->SendReply(&reply);
304 break;
307 case kMsgIsServiceRunning:
309 // Forward the message to the handler that can answer it
310 BHandler* handler = fServices.Target(NULL);
311 if (handler != NULL)
312 handler->MessageReceived(message);
313 break;
316 default:
317 BApplication::MessageReceived(message);
318 return;
323 /*! Checks if provided address family is valid.
324 Families include AF_INET, AF_INET6, AF_APPLETALK, etc
326 bool
327 NetServer::_IsValidFamily(uint32 family)
329 // Mostly verifies add-on is present
330 int socket = ::socket(family, SOCK_DGRAM, 0);
331 if (socket < 0)
332 return false;
334 close(socket);
335 return true;
339 /*! Checks if an interface is valid, that is, if it has an address in any
340 family, and, in case of ethernet, a hardware MAC address.
342 bool
343 NetServer::_IsValidInterface(BNetworkInterface& interface)
345 // check if it has an address
347 if (interface.CountAddresses() == 0)
348 return false;
350 // check if it has a hardware address, too, in case of ethernet
352 BNetworkAddress link;
353 if (interface.GetHardwareAddress(link) != B_OK)
354 return false;
356 if (link.LinkLevelType() == IFT_ETHER && link.LinkLevelAddressLength() != 6)
357 return false;
359 return true;
363 void
364 NetServer::_RemoveInvalidInterfaces()
366 BNetworkRoster& roster = BNetworkRoster::Default();
367 BNetworkInterface interface;
368 uint32 cookie = 0;
370 while (roster.GetNextInterface(&cookie, interface) == B_OK) {
371 if (!_IsValidInterface(interface)) {
372 // remove invalid interface
373 _RemoveInterface(interface.Name());
379 bool
380 NetServer::_TestForInterface(const char* name)
383 BNetworkRoster& roster = BNetworkRoster::Default();
384 int32 nameLength = strlen(name);
385 BNetworkInterface interface;
386 uint32 cookie = 0;
388 while (roster.GetNextInterface(&cookie, interface) == B_OK) {
389 if (!strncmp(interface.Name(), name, nameLength))
390 return true;
393 return false;
397 status_t
398 NetServer::_RemoveInterface(const char* name)
400 BNetworkRoster& roster = BNetworkRoster::Default();
401 status_t status = roster.RemoveInterface(name);
402 if (status != B_OK) {
403 fprintf(stderr, "%s: Could not delete interface %s: %s\n",
404 Name(), name, strerror(status));
405 return status;
408 return B_OK;
412 status_t
413 NetServer::_DisableInterface(const char* name)
415 BNetworkInterface interface(name);
416 int32 flags = interface.Flags();
418 // Set interface down
419 flags &= ~(IFF_UP | IFF_AUTO_CONFIGURED | IFF_CONFIGURING);
421 status_t status = interface.SetFlags(flags);
422 if (status != B_OK) {
423 fprintf(stderr, "%s: Setting flags failed: %s\n", Name(),
424 strerror(status));
425 return status;
428 fprintf(stderr, "%s: set %s interface down...\n", Name(), name);
429 return B_OK;
433 status_t
434 NetServer::_ConfigureInterface(BMessage& message)
436 const char* name;
437 if (message.FindString("device", &name) != B_OK)
438 return B_BAD_VALUE;
440 bool startAutoConfig = false;
442 int32 flags;
443 if (message.FindInt32("flags", &flags) != B_OK)
444 flags = IFF_UP;
446 bool autoConfigured;
447 if (message.FindBool("auto_configured", &autoConfigured) == B_OK
448 && autoConfigured) {
449 flags |= IFF_AUTO_CONFIGURED;
452 int32 mtu;
453 if (message.FindInt32("mtu", &mtu) != B_OK)
454 mtu = -1;
456 int32 metric;
457 if (message.FindInt32("metric", &metric) != B_OK)
458 metric = -1;
460 BNetworkInterface interface(name);
461 if (!interface.Exists()) {
462 // the interface does not exist yet, we have to add it first
463 BNetworkRoster& roster = BNetworkRoster::Default();
465 status_t status = roster.AddInterface(interface);
466 if (status != B_OK) {
467 fprintf(stderr, "%s: Could not add interface: %s\n",
468 interface.Name(), strerror(status));
469 return status;
473 // Set up IPv6 Link Local address (based on MAC, if not loopback)
475 // TODO: our IPv6 stack is still fairly fragile. We need more v6 work
476 // (including IPv6 address scope flags before we start attaching link
477 // local addresses by default.
478 //_ConfigureIPv6LinkLocal(name);
480 BMessage addressMessage;
481 for (int32 index = 0; message.FindMessage("address", index,
482 &addressMessage) == B_OK; index++) {
483 BNetworkInterfaceAddressSettings addressSettings(addressMessage);
485 if (addressSettings.IsAutoConfigure()) {
486 _QuitLooperForDevice(name);
487 startAutoConfig = true;
488 } else if (!addressSettings.Gateway().IsEmpty()) {
489 // add gateway route, if we're asked for it
490 interface.RemoveDefaultRoute(addressSettings.Family());
491 // Try to remove a previous default route, doesn't matter
492 // if it fails.
494 status_t status = interface.AddDefaultRoute(
495 addressSettings.Gateway());
496 if (status != B_OK) {
497 fprintf(stderr, "%s: Could not add route for %s: %s\n",
498 Name(), name, strerror(errno));
502 // set address/mask/broadcast/peer
504 if (!addressSettings.Address().IsEmpty()
505 || !addressSettings.Mask().IsEmpty()
506 || !addressSettings.Broadcast().IsEmpty()
507 || !addressSettings.Peer().IsEmpty()
508 || !addressSettings.IsAutoConfigure()) {
509 BNetworkInterfaceAddress interfaceAddress;
510 interfaceAddress.SetAddress(addressSettings.Address());
511 interfaceAddress.SetMask(addressSettings.Mask());
512 if (!addressSettings.Broadcast().IsEmpty())
513 interfaceAddress.SetBroadcast(addressSettings.Broadcast());
514 else if (!addressSettings.Peer().IsEmpty())
515 interfaceAddress.SetDestination(addressSettings.Peer());
517 status_t status = interface.SetAddress(interfaceAddress);
518 if (status != B_OK) {
519 fprintf(stderr, "%s: Setting address failed: %s\n", Name(),
520 strerror(status));
521 return status;
525 // set flags
527 if (flags != 0) {
528 int32 newFlags = interface.Flags();
529 newFlags = (newFlags & ~IFF_CONFIGURING) | flags;
530 if (!autoConfigured)
531 newFlags &= ~IFF_AUTO_CONFIGURED;
533 status_t status = interface.SetFlags(newFlags);
534 if (status != B_OK) {
535 fprintf(stderr, "%s: Setting flags failed: %s\n", Name(),
536 strerror(status));
540 // set options
542 if (mtu != -1) {
543 status_t status = interface.SetMTU(mtu);
544 if (status != B_OK) {
545 fprintf(stderr, "%s: Setting MTU failed: %s\n", Name(),
546 strerror(status));
550 if (metric != -1) {
551 status_t status = interface.SetMetric(metric);
552 if (status != B_OK) {
553 fprintf(stderr, "%s: Setting metric failed: %s\n", Name(),
554 strerror(status));
559 // Join the specified networks
560 BMessage networkMessage;
561 for (int32 index = 0; message.FindMessage("network", index,
562 &networkMessage) == B_OK; index++) {
563 const char* networkName = message.GetString("name", NULL);
564 const char* addressString = message.GetString("mac", NULL);
566 BNetworkAddress address;
567 status_t addressStatus = address.SetTo(AF_LINK, addressString);
569 BNetworkDevice device(name);
570 if (device.IsWireless() && !device.HasLink()) {
571 status_t status = _JoinNetwork(message,
572 addressStatus == B_OK ? &address : NULL, networkName);
573 if (status != B_OK) {
574 fprintf(stderr, "%s: joining network \"%s\" failed: %s\n",
575 interface.Name(), networkName, strerror(status));
580 if (startAutoConfig) {
581 // start auto configuration
582 AutoconfigLooper* looper = new AutoconfigLooper(this, name);
583 looper->Run();
585 fDeviceMap[name] = looper;
586 } else if (!autoConfigured)
587 _QuitLooperForDevice(name);
589 return B_OK;
593 status_t
594 NetServer::_ConfigureResolver(BMessage& resolverConfiguration)
596 // TODO: resolv.conf should be parsed, all information should be
597 // maintained and it should be distinguished between user entered
598 // and auto-generated parts of the file, with this method only re-writing
599 // the auto-generated parts of course.
601 BPath path;
602 if (find_directory(B_SYSTEM_SETTINGS_DIRECTORY, &path) != B_OK
603 || path.Append("network/resolv.conf") != B_OK)
604 return B_ERROR;
606 FILE* file = fopen(path.Path(), "w");
607 if (file != NULL) {
608 const char* nameserver;
609 for (int32 i = 0; resolverConfiguration.FindString("nameserver", i,
610 &nameserver) == B_OK; i++) {
611 fprintf(file, "nameserver %s\n", nameserver);
614 const char* domain;
615 if (resolverConfiguration.FindString("domain", &domain) == B_OK)
616 fprintf(file, "domain %s\n", domain);
618 fclose(file);
620 return B_OK;
624 bool
625 NetServer::_QuitLooperForDevice(const char* device)
627 LooperMap::iterator iterator = fDeviceMap.find(device);
628 if (iterator == fDeviceMap.end())
629 return false;
631 // there is a looper for this device - quit it
632 if (iterator->second->Lock())
633 iterator->second->Quit();
635 fDeviceMap.erase(iterator);
636 return true;
640 AutoconfigLooper*
641 NetServer::_LooperForDevice(const char* device)
643 LooperMap::const_iterator iterator = fDeviceMap.find(device);
644 if (iterator == fDeviceMap.end())
645 return NULL;
647 return iterator->second;
651 status_t
652 NetServer::_ConfigureDevice(const char* device)
654 // bring interface up, but don't configure it just yet
655 BMessage interface;
656 interface.AddString("device", device);
657 BMessage address;
658 address.AddString("family", "inet");
659 address.AddBool("auto_config", true);
660 interface.AddMessage("address", &address);
662 return _ConfigureInterface(interface);
666 void
667 NetServer::_ConfigureDevices(const char* startPath,
668 BMessage* suggestedInterface)
670 BDirectory directory(startPath);
671 BEntry entry;
672 while (directory.GetNextEntry(&entry) == B_OK) {
673 char name[B_FILE_NAME_LENGTH];
674 struct stat stat;
675 BPath path;
676 if (entry.GetName(name) != B_OK
677 || entry.GetPath(&path) != B_OK
678 || entry.GetStat(&stat) != B_OK)
679 continue;
681 if (S_ISBLK(stat.st_mode) || S_ISCHR(stat.st_mode)) {
682 if (suggestedInterface != NULL
683 && suggestedInterface->RemoveName("device") == B_OK
684 && suggestedInterface->AddString("device", path.Path()) == B_OK
685 && _ConfigureInterface(*suggestedInterface) == B_OK)
686 suggestedInterface = NULL;
687 else
688 _ConfigureDevice(path.Path());
689 } else if (entry.IsDirectory())
690 _ConfigureDevices(path.Path(), suggestedInterface);
695 void
696 NetServer::_ConfigureInterfacesFromSettings(BMessage* _missingDevice)
698 BMessage interface;
699 uint32 cookie = 0;
700 bool missing = false;
701 while (fSettings.GetNextInterface(cookie, interface) == B_OK) {
702 const char *device;
703 if (interface.FindString("device", &device) != B_OK)
704 continue;
706 bool disabled = false;
707 if (interface.FindBool("disabled", &disabled) == B_OK && disabled) {
708 // disabled by user request
709 _DisableInterface(device);
710 continue;
713 if (!strncmp(device, "/dev/net/", 9)) {
714 // it's a kernel device, check if it's present
715 BEntry entry(device);
716 if (!entry.Exists()) {
717 if (!missing && _missingDevice != NULL) {
718 *_missingDevice = interface;
719 missing = true;
721 continue;
725 _ConfigureInterface(interface);
730 void
731 NetServer::_BringUpInterfaces()
733 // we need a socket to talk to the networking stack
734 if (!_IsValidFamily(AF_LINK)) {
735 fprintf(stderr, "%s: The networking stack doesn't seem to be "
736 "available.\n", Name());
737 Quit();
738 return;
741 _RemoveInvalidInterfaces();
743 // First, we look into the settings, and try to bring everything up from there
745 BMessage missingDevice;
746 _ConfigureInterfacesFromSettings(&missingDevice);
748 // check configuration
750 if (!_TestForInterface("loop")) {
751 // there is no loopback interface, create one
752 BMessage interface;
753 interface.AddString("device", "loop");
754 BMessage v4address;
755 v4address.AddString("family", "inet");
756 v4address.AddString("address", "127.0.0.1");
757 interface.AddMessage("address", &v4address);
759 // Check for IPv6 support and add ::1
760 if (_IsValidFamily(AF_INET6)) {
761 BMessage v6address;
762 v6address.AddString("family", "inet6");
763 v6address.AddString("address", "::1");
764 interface.AddMessage("address", &v6address);
766 _ConfigureInterface(interface);
769 // TODO: also check if the networking driver is correctly initialized!
770 // (and check for other devices to take over its configuration)
772 if (!_TestForInterface("/dev/net/")) {
773 // there is no driver configured - see if there is one and try to use it
774 _ConfigureDevices("/dev/net",
775 missingDevice.HasString("device") ? &missingDevice : NULL);
780 /*! Configure the link local address based on the network card's MAC address
781 if this isn't a loopback device.
783 void
784 NetServer::_ConfigureIPv6LinkLocal(const char* name)
786 // Check for IPv6 support
787 if (!_IsValidFamily(AF_INET6))
788 return;
790 BNetworkInterface interface(name);
792 // Lets make sure this is *not* the loopback interface
793 if ((interface.Flags() & IFF_LOOPBACK) != 0)
794 return;
796 BNetworkAddress link;
797 status_t result = interface.GetHardwareAddress(link);
799 if (result != B_OK || link.LinkLevelAddressLength() != 6)
800 return;
802 const uint8* mac = link.LinkLevelAddress();
804 // Check for a few failure situations
805 static const uint8 zeroMac[6] = {0, 0, 0, 0, 0, 0};
806 static const uint8 fullMac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
807 if (memcmp(mac, zeroMac, 6) == 0
808 || memcmp(mac, fullMac, 6) == 0) {
809 // Mac address is all 0 or all FF's
810 syslog(LOG_DEBUG, "%s: MacAddress for interface '%s' is invalid.",
811 __func__, name);
812 return;
815 // Generate a Link Local Scope address
816 // (IPv6 address based on Mac address)
817 in6_addr addressRaw;
818 memset(addressRaw.s6_addr, 0, sizeof(addressRaw.s6_addr));
819 addressRaw.s6_addr[0] = 0xfe;
820 addressRaw.s6_addr[1] = 0x80;
821 addressRaw.s6_addr[8] = mac[0] ^ 0x02;
822 addressRaw.s6_addr[9] = mac[1];
823 addressRaw.s6_addr[10] = mac[2];
824 addressRaw.s6_addr[11] = 0xff;
825 addressRaw.s6_addr[12] = 0xfe;
826 addressRaw.s6_addr[13] = mac[3];
827 addressRaw.s6_addr[14] = mac[4];
828 addressRaw.s6_addr[15] = mac[5];
830 BNetworkAddress localLinkAddress(addressRaw, 0);
831 BNetworkAddress localLinkMask("ffff:ffff:ffff:ffff::"); // 64
832 BNetworkAddress localLinkBroadcast("fe80::ffff:ffff:ffff:ffff");
834 if (interface.FindAddress(localLinkAddress) >= 0) {
835 // uhoh... already has a local link address
837 /* TODO: Check for any local link scope addresses assigned to card
838 There isn't any flag at the moment though for address scope
840 syslog(LOG_DEBUG, "%s: Local Link address already assigned to %s\n",
841 __func__, name);
842 return;
845 BNetworkInterfaceAddress interfaceAddress;
846 interfaceAddress.SetAddress(localLinkAddress);
847 interfaceAddress.SetMask(localLinkMask);
848 interfaceAddress.SetBroadcast(localLinkMask);
850 /* TODO: Duplicate Address Detection. (DAD)
851 Need to blast an icmp packet over the IPv6 network from :: to ensure
852 there aren't duplicate MAC addresses on the network. (definitely an
853 edge case, but a possible issue)
856 interface.AddAddress(interfaceAddress);
860 void
861 NetServer::_StartServices()
863 BHandler* services = new (std::nothrow) Services(fSettings.Services());
864 if (services != NULL) {
865 AddHandler(services);
866 fServices = BMessenger(services);
871 status_t
872 NetServer::_HandleDeviceMonitor(BMessage* message)
874 int32 opcode;
875 const char* path;
876 if (message->FindInt32("opcode", &opcode) != B_OK
877 || (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED)
878 || message->FindString("path", &path) != B_OK)
879 return B_BAD_VALUE;
881 if (strncmp(path, "/dev/net/", 9)) {
882 // not a valid device entry, ignore
883 return B_NAME_NOT_FOUND;
886 if (opcode == B_ENTRY_CREATED)
887 _ConfigureDevice(path);
888 else
889 _RemoveInterface(path);
891 return B_OK;
895 status_t
896 NetServer::_AutoJoinNetwork(const BMessage& message)
898 const char* name = NULL;
899 if (message.FindString("device", &name) != B_OK)
900 return B_BAD_VALUE;
902 BNetworkDevice device(name);
904 // Choose among configured networks
906 uint32 cookie = 0;
907 BMessage networkMessage;
908 while (fSettings.GetNextNetwork(cookie, networkMessage) == B_OK) {
909 status_t status = B_ERROR;
910 wireless_network network;
911 const char* networkName;
912 BNetworkAddress link;
914 const char* mac = NULL;
915 if (networkMessage.FindString("mac", &mac) == B_OK) {
916 link.SetTo(AF_LINK, mac);
917 status = device.GetNetwork(link, network);
918 } else if (networkMessage.FindString("name", &networkName) == B_OK)
919 status = device.GetNetwork(networkName, network);
921 if (status == B_OK) {
922 status = _JoinNetwork(message, mac != NULL ? &link : NULL,
923 network.name);
924 printf("auto join network \"%s\": %s\n", network.name,
925 strerror(status));
926 if (status == B_OK)
927 return B_OK;
931 return B_NO_INIT;
935 status_t
936 NetServer::_JoinNetwork(const BMessage& message, const BNetworkAddress* address,
937 const char* name)
939 const char* deviceName;
940 if (message.FindString("device", &deviceName) != B_OK)
941 return B_BAD_VALUE;
943 BNetworkAddress deviceAddress;
944 message.FindFlat("address", &deviceAddress);
945 if (address == NULL)
946 address = &deviceAddress;
948 if (name == NULL)
949 message.FindString("name", &name);
950 if (name == NULL) {
951 // No name specified, we need a network address
952 if (address->Family() != AF_LINK)
953 return B_BAD_VALUE;
956 // Search for a network configuration that may override the defaults
958 bool found = false;
959 uint32 cookie = 0;
960 BMessage networkMessage;
961 while (fSettings.GetNextNetwork(cookie, networkMessage) == B_OK) {
962 const char* networkName;
963 if (networkMessage.FindString("name", &networkName) == B_OK
964 && name != NULL && address->Family() != AF_LINK
965 && !strcmp(name, networkName)) {
966 found = true;
967 break;
970 const char* mac;
971 if (networkMessage.FindString("mac", &mac) == B_OK
972 && address->Family() == AF_LINK) {
973 BNetworkAddress link(AF_LINK, mac);
974 if (link == *address) {
975 found = true;
976 break;
981 const char* password;
982 if (message.FindString("password", &password) != B_OK && found)
983 password = networkMessage.FindString("password");
985 // Get network
986 BNetworkDevice device(deviceName);
987 wireless_network network;
989 bool askForConfig = false;
990 if ((address->Family() != AF_LINK
991 || device.GetNetwork(*address, network) != B_OK)
992 && device.GetNetwork(name, network) != B_OK) {
993 // We did not find a network - just ignore that, and continue
994 // with some defaults
995 strlcpy(network.name, name, sizeof(network.name));
996 network.address = *address;
997 network.authentication_mode = B_NETWORK_AUTHENTICATION_NONE;
998 network.cipher = 0;
999 network.group_cipher = 0;
1000 network.key_mode = 0;
1001 askForConfig = true;
1004 const char* string;
1005 if (message.FindString("authentication", &string) == B_OK
1006 || (found && networkMessage.FindString("authentication", &string)
1007 == B_OK)) {
1008 askForConfig = false;
1009 if (!strcasecmp(string, "wpa2")) {
1010 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2;
1011 network.key_mode = B_KEY_MODE_IEEE802_1X;
1012 network.cipher = network.group_cipher = B_NETWORK_CIPHER_CCMP;
1013 } else if (!strcasecmp(string, "wpa")) {
1014 network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA;
1015 network.key_mode = B_KEY_MODE_IEEE802_1X;
1016 network.cipher = network.group_cipher = B_NETWORK_CIPHER_TKIP;
1017 } else if (!strcasecmp(string, "wep")) {
1018 network.authentication_mode = B_NETWORK_AUTHENTICATION_WEP;
1019 network.key_mode = B_KEY_MODE_NONE;
1020 network.cipher = network.group_cipher = B_NETWORK_CIPHER_WEP_40;
1021 } else if (strcasecmp(string, "none") && strcasecmp(string, "open")) {
1022 fprintf(stderr, "%s: invalid authentication mode.\n", name);
1023 askForConfig = true;
1027 // We always try to join via the wpa_supplicant. Even if we could join
1028 // ourselves, we need to make sure that the wpa_supplicant knows about
1029 // our intention, as otherwise it would interfere with it.
1031 BMessenger wpaSupplicant(kWPASupplicantSignature);
1032 if (!wpaSupplicant.IsValid()) {
1033 // The wpa_supplicant isn't running yet, we may join ourselves.
1034 if (!askForConfig
1035 && network.authentication_mode == B_NETWORK_AUTHENTICATION_NONE) {
1036 // We can join this network ourselves.
1037 status_t status = set_80211(deviceName, IEEE80211_IOC_SSID,
1038 network.name, strlen(network.name));
1039 if (status != B_OK) {
1040 fprintf(stderr, "%s: joining SSID failed: %s\n", name,
1041 strerror(status));
1042 return status;
1046 // We need the supplicant, try to launch it.
1047 status_t status = be_roster->Launch(kWPASupplicantSignature);
1048 if (status != B_OK && status != B_ALREADY_RUNNING)
1049 return status;
1051 wpaSupplicant.SetTo(kWPASupplicantSignature);
1052 if (!wpaSupplicant.IsValid())
1053 return B_ERROR;
1056 // TODO: listen to notifications from the supplicant!
1058 BMessage join(kMsgWPAJoinNetwork);
1059 status_t status = join.AddString("device", deviceName);
1060 if (status == B_OK)
1061 status = join.AddString("name", network.name);
1062 if (status == B_OK)
1063 status = join.AddFlat("address", &network.address);
1064 if (status == B_OK && !askForConfig)
1065 status = join.AddUInt32("authentication", network.authentication_mode);
1066 if (status == B_OK && password != NULL)
1067 status = join.AddString("password", password);
1068 if (status != B_OK)
1069 return status;
1071 status = wpaSupplicant.SendMessage(&join);
1072 if (status != B_OK)
1073 return status;
1075 return B_OK;
1079 status_t
1080 NetServer::_LeaveNetwork(const BMessage& message)
1082 const char* deviceName;
1083 if (message.FindString("device", &deviceName) != B_OK)
1084 return B_BAD_VALUE;
1086 int32 reason;
1087 if (message.FindInt32("reason", &reason) != B_OK)
1088 reason = IEEE80211_REASON_AUTH_LEAVE;
1090 // We always try to send the leave request to the wpa_supplicant.
1092 BMessenger wpaSupplicant(kWPASupplicantSignature);
1093 if (wpaSupplicant.IsValid()) {
1094 BMessage leave(kMsgWPALeaveNetwork);
1095 status_t status = leave.AddString("device", deviceName);
1096 if (status == B_OK)
1097 status = leave.AddInt32("reason", reason);
1098 if (status != B_OK)
1099 return status;
1101 status = wpaSupplicant.SendMessage(&leave);
1102 if (status == B_OK)
1103 return B_OK;
1106 // The wpa_supplicant doesn't seem to be running, check if this was an open
1107 // network we connected ourselves.
1108 BNetworkDevice device(deviceName);
1109 wireless_network network;
1111 uint32 cookie = 0;
1112 if (device.GetNextAssociatedNetwork(cookie, network) != B_OK
1113 || network.authentication_mode != B_NETWORK_AUTHENTICATION_NONE) {
1114 // We didn't join ourselves, we can't do much.
1115 return B_ERROR;
1118 // We joined ourselves, so we can just disassociate again.
1119 ieee80211req_mlme mlmeRequest;
1120 memset(&mlmeRequest, 0, sizeof(mlmeRequest));
1121 mlmeRequest.im_op = IEEE80211_MLME_DISASSOC;
1122 mlmeRequest.im_reason = reason;
1124 return set_80211(deviceName, IEEE80211_IOC_MLME, &mlmeRequest,
1125 sizeof(mlmeRequest));
1129 // #pragma mark -
1133 main(int argc, char** argv)
1135 srand(system_time());
1137 status_t status;
1138 NetServer server(status);
1139 if (status != B_OK) {
1140 fprintf(stderr, "net_server: Failed to create application: %s\n",
1141 strerror(status));
1142 return 1;
1145 server.Run();
1146 return 0;