xref: /haiku/src/servers/net/NetServer.cpp (revision 4c1d9cf74e1c1706922e5b5795e788fb14fe81c9)
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