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