2 * Copyright 2006-2015, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
6 * Axel Dörfler, axeld@pinc-software.de
7 * Vegard Wærp, vegarwa@online.no
8 * Alexander von Gluck, kallisti5@unixzen.com
12 #include "NetServer.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>
32 #include <Directory.h>
34 #include <NetworkDevice.h>
35 #include <NetworkInterface.h>
36 #include <NetworkRoster.h>
37 #include <NetworkSettings.h>
39 #include <PathMonitor.h>
43 #include <FindDirectory.h>
45 #include <AutoDeleter.h>
46 #include <WPASupplicant.h>
48 #include "AutoconfigLooper.h"
52 # include <net80211/ieee80211_ioctl.h>
56 using namespace BNetworkKit
;
59 typedef std::map
<std::string
, AutoconfigLooper
*> LooperMap
;
62 class NetServer
: public BServer
{
64 NetServer(status_t
& status
);
67 virtual void AboutRequested();
68 virtual void ReadyToRun();
69 virtual void MessageReceived(BMessage
* message
);
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
);
104 BNetworkSettings fSettings
;
105 LooperMap fDeviceMap
;
106 BMessenger fServices
;
110 // #pragma mark - private functions
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);
121 FileDescriptorCloser
closer(socket
);
123 struct ieee80211req ireq
;
124 strlcpy(ireq
.i_name
, name
, IF_NAMESIZE
);
130 if (ioctl(socket
, SIOCS80211
, &ireq
, sizeof(struct ieee80211req
)) < 0)
140 NetServer::NetServer(status_t
& error
)
142 BServer(kNetServerSignature
, false, &error
)
147 NetServer::~NetServer()
149 BPrivate::BPathMonitor::StopWatching("/dev/net", this);
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();
161 view
->SetStylable(true);
163 view
->GetFont(&font
);
165 font
.SetFace(B_BOLD_FACE
);
166 view
->SetFontAndColor(0, 17, &font
);
168 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
174 NetServer::ReadyToRun()
176 fSettings
.StartMonitoring(this);
177 _BringUpInterfaces();
180 BPrivate::BPathMonitor::StartWatching("/dev/net",
181 B_WATCH_FILES_ONLY
| B_WATCH_RECURSIVELY
, this);
186 NetServer::MessageReceived(BMessage
* message
)
188 switch (message
->what
) {
191 fSettings
.Update(message
);
192 _HandleDeviceMonitor(message
);
196 case BNetworkSettings::kMsgInterfaceSettingsUpdated
:
198 _ConfigureInterfacesFromSettings();
202 case BNetworkSettings::kMsgServiceSettingsUpdated
:
204 BMessage update
= fSettings
.Services();
205 update
.what
= kMsgUpdateServices
;
207 fServices
.SendMessage(&update
);
211 case kMsgConfigureInterface
:
213 status_t status
= _ConfigureInterface(*message
);
215 BMessage
reply(B_REPLY
);
216 reply
.AddInt32("status", status
);
217 message
->SendReply(&reply
);
221 case kMsgConfigureResolver
:
223 status_t status
= _ConfigureResolver(*message
);
225 BMessage
reply(B_REPLY
);
226 reply
.AddInt32("status", status
);
227 message
->SendReply(&reply
);
231 case kMsgJoinNetwork
:
233 status_t status
= _JoinNetwork(*message
);
235 BMessage
reply(B_REPLY
);
236 reply
.AddInt32("status", status
);
237 message
->SendReply(&reply
);
241 case kMsgLeaveNetwork
:
243 status_t status
= _LeaveNetwork(*message
);
245 BMessage
reply(B_REPLY
);
246 reply
.AddInt32("status", status
);
247 message
->SendReply(&reply
);
251 case kMsgAutoJoinNetwork
:
253 _AutoJoinNetwork(*message
);
257 case kMsgCountPersistentNetworks
:
259 BMessage
reply(B_REPLY
);
260 reply
.AddInt32("count", fSettings
.CountNetworks());
261 message
->SendReply(&reply
);
265 case kMsgGetPersistentNetwork
:
268 status_t result
= message
->FindInt32("index", (int32
*)&index
);
270 BMessage
reply(B_REPLY
);
271 if (result
== B_OK
) {
273 result
= fSettings
.GetNextNetwork(index
, network
);
275 result
= reply
.AddMessage("network", &network
);
278 reply
.AddInt32("status", result
);
279 message
->SendReply(&reply
);
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
);
294 case kMsgRemovePersistentNetwork
:
296 const char* networkName
= NULL
;
297 status_t result
= message
->FindString("name", &networkName
);
299 result
= fSettings
.RemoveNetwork(networkName
);
301 BMessage
reply(B_REPLY
);
302 reply
.AddInt32("status", result
);
303 message
->SendReply(&reply
);
307 case kMsgIsServiceRunning
:
309 // Forward the message to the handler that can answer it
310 BHandler
* handler
= fServices
.Target(NULL
);
312 handler
->MessageReceived(message
);
317 BApplication::MessageReceived(message
);
323 /*! Checks if provided address family is valid.
324 Families include AF_INET, AF_INET6, AF_APPLETALK, etc
327 NetServer::_IsValidFamily(uint32 family
)
329 // Mostly verifies add-on is present
330 int socket
= ::socket(family
, SOCK_DGRAM
, 0);
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.
343 NetServer::_IsValidInterface(BNetworkInterface
& interface
)
345 // check if it has an address
347 if (interface
.CountAddresses() == 0)
350 // check if it has a hardware address, too, in case of ethernet
352 BNetworkAddress link
;
353 if (interface
.GetHardwareAddress(link
) != B_OK
)
356 if (link
.LinkLevelType() == IFT_ETHER
&& link
.LinkLevelAddressLength() != 6)
364 NetServer::_RemoveInvalidInterfaces()
366 BNetworkRoster
& roster
= BNetworkRoster::Default();
367 BNetworkInterface interface
;
370 while (roster
.GetNextInterface(&cookie
, interface
) == B_OK
) {
371 if (!_IsValidInterface(interface
)) {
372 // remove invalid interface
373 _RemoveInterface(interface
.Name());
380 NetServer::_TestForInterface(const char* name
)
383 BNetworkRoster
& roster
= BNetworkRoster::Default();
384 int32 nameLength
= strlen(name
);
385 BNetworkInterface interface
;
388 while (roster
.GetNextInterface(&cookie
, interface
) == B_OK
) {
389 if (!strncmp(interface
.Name(), name
, nameLength
))
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
));
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(),
428 fprintf(stderr
, "%s: set %s interface down...\n", Name(), name
);
434 NetServer::_ConfigureInterface(BMessage
& message
)
437 if (message
.FindString("device", &name
) != B_OK
)
440 bool startAutoConfig
= false;
443 if (message
.FindInt32("flags", &flags
) != B_OK
)
447 if (message
.FindBool("auto_configured", &autoConfigured
) == B_OK
449 flags
|= IFF_AUTO_CONFIGURED
;
453 if (message
.FindInt32("mtu", &mtu
) != B_OK
)
457 if (message
.FindInt32("metric", &metric
) != B_OK
)
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
));
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
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(),
528 int32 newFlags
= interface
.Flags();
529 newFlags
= (newFlags
& ~IFF_CONFIGURING
) | flags
;
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(),
543 status_t status
= interface
.SetMTU(mtu
);
544 if (status
!= B_OK
) {
545 fprintf(stderr
, "%s: Setting MTU failed: %s\n", Name(),
551 status_t status
= interface
.SetMetric(metric
);
552 if (status
!= B_OK
) {
553 fprintf(stderr
, "%s: Setting metric failed: %s\n", Name(),
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
);
585 fDeviceMap
[name
] = looper
;
586 } else if (!autoConfigured
)
587 _QuitLooperForDevice(name
);
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.
602 if (find_directory(B_SYSTEM_SETTINGS_DIRECTORY
, &path
) != B_OK
603 || path
.Append("network/resolv.conf") != B_OK
)
606 FILE* file
= fopen(path
.Path(), "w");
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
);
615 if (resolverConfiguration
.FindString("domain", &domain
) == B_OK
)
616 fprintf(file
, "domain %s\n", domain
);
625 NetServer::_QuitLooperForDevice(const char* device
)
627 LooperMap::iterator iterator
= fDeviceMap
.find(device
);
628 if (iterator
== fDeviceMap
.end())
631 // there is a looper for this device - quit it
632 if (iterator
->second
->Lock())
633 iterator
->second
->Quit();
635 fDeviceMap
.erase(iterator
);
641 NetServer::_LooperForDevice(const char* device
)
643 LooperMap::const_iterator iterator
= fDeviceMap
.find(device
);
644 if (iterator
== fDeviceMap
.end())
647 return iterator
->second
;
652 NetServer::_ConfigureDevice(const char* device
)
654 // bring interface up, but don't configure it just yet
656 interface
.AddString("device", device
);
658 address
.AddString("family", "inet");
659 address
.AddBool("auto_config", true);
660 interface
.AddMessage("address", &address
);
662 return _ConfigureInterface(interface
);
667 NetServer::_ConfigureDevices(const char* startPath
,
668 BMessage
* suggestedInterface
)
670 BDirectory
directory(startPath
);
672 while (directory
.GetNextEntry(&entry
) == B_OK
) {
673 char name
[B_FILE_NAME_LENGTH
];
676 if (entry
.GetName(name
) != B_OK
677 || entry
.GetPath(&path
) != B_OK
678 || entry
.GetStat(&stat
) != B_OK
)
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
;
688 _ConfigureDevice(path
.Path());
689 } else if (entry
.IsDirectory())
690 _ConfigureDevices(path
.Path(), suggestedInterface
);
696 NetServer::_ConfigureInterfacesFromSettings(BMessage
* _missingDevice
)
700 bool missing
= false;
701 while (fSettings
.GetNextInterface(cookie
, interface
) == B_OK
) {
703 if (interface
.FindString("device", &device
) != B_OK
)
706 bool disabled
= false;
707 if (interface
.FindBool("disabled", &disabled
) == B_OK
&& disabled
) {
708 // disabled by user request
709 _DisableInterface(device
);
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
;
725 _ConfigureInterface(interface
);
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());
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
753 interface
.AddString("device", "loop");
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
)) {
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.
784 NetServer::_ConfigureIPv6LinkLocal(const char* name
)
786 // Check for IPv6 support
787 if (!_IsValidFamily(AF_INET6
))
790 BNetworkInterface
interface(name
);
792 // Lets make sure this is *not* the loopback interface
793 if ((interface
.Flags() & IFF_LOOPBACK
) != 0)
796 BNetworkAddress link
;
797 status_t result
= interface
.GetHardwareAddress(link
);
799 if (result
!= B_OK
|| link
.LinkLevelAddressLength() != 6)
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.",
815 // Generate a Link Local Scope address
816 // (IPv6 address based on Mac address)
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",
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
);
861 NetServer::_StartServices()
863 BHandler
* services
= new (std::nothrow
) Services(fSettings
.Services());
864 if (services
!= NULL
) {
865 AddHandler(services
);
866 fServices
= BMessenger(services
);
872 NetServer::_HandleDeviceMonitor(BMessage
* message
)
876 if (message
->FindInt32("opcode", &opcode
) != B_OK
877 || (opcode
!= B_ENTRY_CREATED
&& opcode
!= B_ENTRY_REMOVED
)
878 || message
->FindString("path", &path
) != B_OK
)
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
);
889 _RemoveInterface(path
);
896 NetServer::_AutoJoinNetwork(const BMessage
& message
)
898 const char* name
= NULL
;
899 if (message
.FindString("device", &name
) != B_OK
)
902 BNetworkDevice
device(name
);
904 // Choose among configured networks
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
,
924 printf("auto join network \"%s\": %s\n", network
.name
,
936 NetServer::_JoinNetwork(const BMessage
& message
, const BNetworkAddress
* address
,
939 const char* deviceName
;
940 if (message
.FindString("device", &deviceName
) != B_OK
)
943 BNetworkAddress deviceAddress
;
944 message
.FindFlat("address", &deviceAddress
);
946 address
= &deviceAddress
;
949 message
.FindString("name", &name
);
951 // No name specified, we need a network address
952 if (address
->Family() != AF_LINK
)
956 // Search for a network configuration that may override the defaults
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
)) {
971 if (networkMessage
.FindString("mac", &mac
) == B_OK
972 && address
->Family() == AF_LINK
) {
973 BNetworkAddress
link(AF_LINK
, mac
);
974 if (link
== *address
) {
981 const char* password
;
982 if (message
.FindString("password", &password
) != B_OK
&& found
)
983 password
= networkMessage
.FindString("password");
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
;
999 network
.group_cipher
= 0;
1000 network
.key_mode
= 0;
1001 askForConfig
= true;
1005 if (message
.FindString("authentication", &string
) == B_OK
1006 || (found
&& networkMessage
.FindString("authentication", &string
)
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.
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
,
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
)
1051 wpaSupplicant
.SetTo(kWPASupplicantSignature
);
1052 if (!wpaSupplicant
.IsValid())
1056 // TODO: listen to notifications from the supplicant!
1058 BMessage
join(kMsgWPAJoinNetwork
);
1059 status_t status
= join
.AddString("device", deviceName
);
1061 status
= join
.AddString("name", network
.name
);
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
);
1071 status
= wpaSupplicant
.SendMessage(&join
);
1080 NetServer::_LeaveNetwork(const BMessage
& message
)
1082 const char* deviceName
;
1083 if (message
.FindString("device", &deviceName
) != B_OK
)
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
);
1097 status
= leave
.AddInt32("reason", reason
);
1101 status
= wpaSupplicant
.SendMessage(&leave
);
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
;
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.
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
));
1133 main(int argc
, char** argv
)
1135 srand(system_time());
1138 NetServer
server(status
);
1139 if (status
!= B_OK
) {
1140 fprintf(stderr
, "net_server: Failed to create application: %s\n",