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