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