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