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