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