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