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