* Copyright 2006-2019, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Vegard Wærp, vegarwa@online.no
* Alexander von Gluck, kallisti5@unixzen.com
*/
#include "NetServer.h"
#include <errno.h>
#include <map>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <strings.h>
#include <syslog.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <Alert.h>
#include <Deskbar.h>
#include <Directory.h>
#include <Entry.h>
#include <NetworkDevice.h>
#include <NetworkInterface.h>
#include <NetworkRoster.h>
#include <NetworkSettings.h>
#include <Path.h>
#include <PathMonitor.h>
#include <Roster.h>
#include <Server.h>
#include <TextView.h>
#include <FindDirectory.h>
#include <AutoDeleter.h>
#include <WPASupplicant.h>
#include "AutoconfigLooper.h"
#include "Services.h"
extern "C" {
# include <freebsd_network/compat/sys/cdefs.h>
# include <freebsd_network/compat/sys/ioccom.h>
# include <net80211/ieee80211_ioctl.h>
}
using namespace BNetworkKit;
typedef std::map<std::string, AutoconfigLooper*> LooperMap;
class NetServer : public BServer {
public:
NetServer(status_t& status);
virtual ~NetServer();
virtual void ReadyToRun();
virtual void MessageReceived(BMessage* message);
private:
bool _IsValidFamily(uint32 family);
bool _IsValidInterface(BNetworkInterface& interface);
void _RemoveInvalidInterfaces();
status_t _RemoveInterface(const char* name);
status_t _DisableInterface(const char* name);
bool _TestForInterface(const char* name);
status_t _ConfigureInterface(BMessage& interface);
status_t _ConfigureResolver(
BMessage& resolverConfiguration);
bool _QuitLooperForDevice(const char* device);
AutoconfigLooper* _LooperForDevice(const char* device);
status_t _ConfigureDevice(const char* path);
void _ConfigureDevices(const char* path,
BStringList& devicesAlreadyConfigured,
BMessage* suggestedInterface = NULL);
void _ConfigureInterfacesFromSettings(
BStringList& devicesSet,
BMessage* _missingDevice = NULL);
void _ConfigureIPv6LinkLocal(const char* name);
void _BringUpInterfaces();
void _StartServices();
status_t _HandleDeviceMonitor(BMessage* message);
status_t _AutoJoinNetwork(const BMessage& message);
status_t _JoinNetwork(const BMessage& message,
const BNetworkAddress* address = NULL,
const char* name = NULL);
status_t _LeaveNetwork(const BMessage& message);
status_t _ConvertNetworkToSettings(BMessage& message);
status_t _ConvertNetworkFromSettings(BMessage& message);
private:
BNetworkSettings fSettings;
LooperMap fDeviceMap;
BMessenger fServices;
};
static status_t
set_80211(const char* name, int32 type, void* data,
int32 length = 0, int32 value = 0)
{
FileDescriptorCloser socket(::socket(AF_INET, SOCK_DGRAM, 0));
if (!socket.IsSet())
return errno;
struct ieee80211req ireq;
strlcpy(ireq.i_name, name, IF_NAMESIZE);
ireq.i_type = type;
ireq.i_val = value;
ireq.i_len = length;
ireq.i_data = data;
if (ioctl(socket.Get(), SIOCS80211, &ireq, sizeof(struct ieee80211req))
< 0)
return errno;
return B_OK;
}
NetServer::NetServer(status_t& error)
:
BServer(kNetServerSignature, false, &error)
{
}
NetServer::~NetServer()
{
BPrivate::BPathMonitor::StopWatching("/dev/net", this);
}
void
NetServer::ReadyToRun()
{
fSettings.StartMonitoring(this);
_BringUpInterfaces();
_StartServices();
BPrivate::BPathMonitor::StartWatching("/dev/net",
B_WATCH_FILES_ONLY | B_WATCH_RECURSIVELY, this);
}
void
NetServer::MessageReceived(BMessage* message)
{
switch (message->what) {
case B_PATH_MONITOR:
{
fSettings.Update(message);
_HandleDeviceMonitor(message);
break;
}
case BNetworkSettings::kMsgInterfaceSettingsUpdated:
{
BStringList devicesSet;
_ConfigureInterfacesFromSettings(devicesSet);
break;
}
case BNetworkSettings::kMsgServiceSettingsUpdated:
{
BMessage update = fSettings.Services();
update.what = kMsgUpdateServices;
fServices.SendMessage(&update);
break;
}
case kMsgConfigureInterface:
{
status_t status = _ConfigureInterface(*message);
BMessage reply(B_REPLY);
reply.AddInt32("status", status);
message->SendReply(&reply);
break;
}
case kMsgConfigureResolver:
{
status_t status = _ConfigureResolver(*message);
BMessage reply(B_REPLY);
reply.AddInt32("status", status);
message->SendReply(&reply);
break;
}
case kMsgJoinNetwork:
{
status_t status = _JoinNetwork(*message);
BMessage reply(B_REPLY);
reply.AddInt32("status", status);
message->SendReply(&reply);
break;
}
case kMsgLeaveNetwork:
{
status_t status = _LeaveNetwork(*message);
BMessage reply(B_REPLY);
reply.AddInt32("status", status);
message->SendReply(&reply);
break;
}
case kMsgAutoJoinNetwork:
{
_AutoJoinNetwork(*message);
break;
}
case kMsgCountPersistentNetworks:
{
BMessage reply(B_REPLY);
reply.AddInt32("count", fSettings.CountNetworks());
message->SendReply(&reply);
break;
}
case kMsgGetPersistentNetwork:
{
uint32 index = 0;
status_t result = message->FindInt32("index", (int32*)&index);
BMessage reply(B_REPLY);
if (result == B_OK) {
BMessage network;
result = fSettings.GetNextNetwork(index, network);
if (result == B_OK)
result = reply.AddMessage("network", &network);
}
reply.AddInt32("status", result);
message->SendReply(&reply);
break;
}
case kMsgAddPersistentNetwork:
{
BMessage network = *message;
status_t result = fSettings.AddNetwork(network);
BMessage reply(B_REPLY);
reply.AddInt32("status", result);
message->SendReply(&reply);
break;
}
case kMsgRemovePersistentNetwork:
{
const char* networkName = NULL;
status_t result = message->FindString("name", &networkName);
if (result == B_OK)
result = fSettings.RemoveNetwork(networkName);
BMessage reply(B_REPLY);
reply.AddInt32("status", result);
message->SendReply(&reply);
break;
}
case kMsgIsServiceRunning:
{
BHandler* handler = fServices.Target(NULL);
if (handler != NULL)
handler->MessageReceived(message);
break;
}
default:
BApplication::MessageReceived(message);
return;
}
}
Families include AF_INET, AF_INET6, AF_APPLETALK, etc
*/
bool
NetServer::_IsValidFamily(uint32 family)
{
int socket = ::socket(family, SOCK_DGRAM, 0);
if (socket < 0)
return false;
close(socket);
return true;
}
family, and, in case of ethernet, a hardware MAC address.
*/
bool
NetServer::_IsValidInterface(BNetworkInterface& interface)
{
if (interface.CountAddresses() == 0)
return false;
BNetworkAddress link;
if (interface.GetHardwareAddress(link) != B_OK)
return false;
if (link.LinkLevelType() == IFT_ETHER && link.LinkLevelAddressLength() != 6)
return false;
return true;
}
void
NetServer::_RemoveInvalidInterfaces()
{
BNetworkRoster& roster = BNetworkRoster::Default();
BNetworkInterface interface;
uint32 cookie = 0;
while (roster.GetNextInterface(&cookie, interface) == B_OK) {
if (!_IsValidInterface(interface)) {
_RemoveInterface(interface.Name());
}
}
}
bool
NetServer::_TestForInterface(const char* name)
{
BNetworkRoster& roster = BNetworkRoster::Default();
int32 nameLength = strlen(name);
BNetworkInterface interface;
uint32 cookie = 0;
while (roster.GetNextInterface(&cookie, interface) == B_OK) {
if (!strncmp(interface.Name(), name, nameLength))
return true;
}
return false;
}
status_t
NetServer::_RemoveInterface(const char* name)
{
BNetworkRoster& roster = BNetworkRoster::Default();
status_t status = roster.RemoveInterface(name);
if (status != B_OK) {
fprintf(stderr, "%s: Could not delete interface %s: %s\n",
Name(), name, strerror(status));
return status;
}
return B_OK;
}
status_t
NetServer::_DisableInterface(const char* name)
{
BNetworkInterface interface(name);
int32 flags = interface.Flags();
flags &= ~(IFF_UP | IFF_AUTO_CONFIGURED | IFF_CONFIGURING);
status_t status = interface.SetFlags(flags);
if (status != B_OK) {
fprintf(stderr, "%s: Setting flags failed: %s\n", Name(),
strerror(status));
return status;
}
fprintf(stderr, "%s: set %s interface down...\n", Name(), name);
return B_OK;
}
status_t
NetServer::_ConfigureInterface(BMessage& message)
{
const char* name;
if (message.FindString("device", &name) != B_OK)
return B_BAD_VALUE;
bool startAutoConfig = false;
int32 flags;
if (message.FindInt32("flags", &flags) != B_OK)
flags = IFF_UP;
bool autoConfigured = false;
if (message.FindBool("auto_configured", &autoConfigured) == B_OK
&& autoConfigured) {
flags |= IFF_AUTO_CONFIGURED;
} else {
_QuitLooperForDevice(name);
}
int32 mtu;
if (message.FindInt32("mtu", &mtu) != B_OK)
mtu = -1;
int32 metric;
if (message.FindInt32("metric", &metric) != B_OK)
metric = -1;
BNetworkInterface interface(name);
if (!interface.Exists()) {
BNetworkRoster& roster = BNetworkRoster::Default();
status_t status = roster.AddInterface(interface);
if (status != B_OK) {
fprintf(stderr, "%s: Could not add interface: %s\n",
interface.Name(), strerror(status));
return status;
}
}
BMessage addressMessage;
for (int32 index = 0; message.FindMessage("address", index,
&addressMessage) == B_OK; index++) {
BNetworkInterfaceAddressSettings addressSettings(addressMessage);
if (addressSettings.IsAutoConfigure())
startAutoConfig = true;
if (!addressSettings.Address().IsEmpty()
|| !addressSettings.Mask().IsEmpty()
|| !addressSettings.Broadcast().IsEmpty()
|| !addressSettings.Peer().IsEmpty()
|| !addressSettings.IsAutoConfigure()) {
BNetworkInterfaceAddress interfaceAddress;
interfaceAddress.SetAddress(addressSettings.Address());
interfaceAddress.SetMask(addressSettings.Mask());
if (!addressSettings.Broadcast().IsEmpty())
interfaceAddress.SetBroadcast(addressSettings.Broadcast());
else if (!addressSettings.Peer().IsEmpty())
interfaceAddress.SetDestination(addressSettings.Peer());
status_t status = interface.SetAddress(interfaceAddress);
if (status != B_OK) {
fprintf(stderr, "%s: Setting address failed: %s\n", Name(),
strerror(status));
return status;
}
}
if (!addressSettings.Gateway().IsEmpty()) {
interface.RemoveDefaultRoute(addressSettings.Family());
status_t status = interface.AddDefaultRoute(
addressSettings.Gateway());
if (status != B_OK) {
fprintf(stderr, "%s: Could not add route for %s: %s\n",
Name(), name, strerror(errno));
}
}
if (flags != 0) {
int32 newFlags = interface.Flags();
newFlags = (newFlags & ~IFF_CONFIGURING) | flags;
if (!autoConfigured)
newFlags &= ~IFF_AUTO_CONFIGURED;
status_t status = interface.SetFlags(newFlags);
if (status != B_OK) {
fprintf(stderr, "%s: Setting flags failed: %s\n", Name(),
strerror(status));
}
}
if (mtu != -1) {
status_t status = interface.SetMTU(mtu);
if (status != B_OK) {
fprintf(stderr, "%s: Setting MTU failed: %s\n", Name(),
strerror(status));
}
}
if (metric != -1) {
status_t status = interface.SetMetric(metric);
if (status != B_OK) {
fprintf(stderr, "%s: Setting metric failed: %s\n", Name(),
strerror(status));
}
}
}
BMessage networkMessage;
for (int32 index = 0; message.FindMessage("network", index,
&networkMessage) == B_OK; index++) {
const char* networkName = message.GetString("name", NULL);
const char* addressString = message.GetString("mac", NULL);
BNetworkAddress address;
status_t addressStatus = address.SetTo(AF_LINK, addressString);
BNetworkDevice device(name);
if (device.IsWireless() && !device.HasLink()) {
status_t status = _JoinNetwork(message,
addressStatus == B_OK ? &address : NULL, networkName);
if (status != B_OK) {
fprintf(stderr, "%s: joining network \"%s\" failed: %s\n",
interface.Name(), networkName, strerror(status));
}
}
}
if (startAutoConfig) {
AutoconfigLooper* looper = new AutoconfigLooper(this, name);
looper->Run();
fDeviceMap[name] = looper;
}
return B_OK;
}
status_t
NetServer::_ConfigureResolver(BMessage& resolverConfiguration)
{
BPath path;
if (find_directory(B_SYSTEM_SETTINGS_DIRECTORY, &path) != B_OK
|| path.Append("network/resolv.conf") != B_OK)
return B_ERROR;
FILE* file = fopen(path.Path(), "r+");
if (file == NULL) {
file = fopen(path.Path(), "w");
if (file == NULL) {
fprintf(stderr, "Could not open resolv.conf: %s\n",
strerror(errno));
return errno;
}
} else {
const char* staticDNS = "# Static DNS Only";
size_t sizeStaticDNS = strlen(staticDNS);
const char* dynamicDNS = "# Dynamic DNS entries";
size_t sizeDynamicDNS = strlen(dynamicDNS);
char resolveConfBuffer[80];
size_t sizeResolveConfBuffer = sizeof(resolveConfBuffer);
while (fgets(resolveConfBuffer, sizeResolveConfBuffer, file)) {
if (strncmp(resolveConfBuffer, staticDNS, sizeStaticDNS) == 0) {
fclose(file);
return B_OK;
} else if (strncmp(resolveConfBuffer, dynamicDNS, sizeDynamicDNS)
== 0) {
break;
}
}
if (feof(file) != 0) {
fclose(file);
file = fopen(path.Path(), "w");
if (file == NULL) {
fprintf(stderr, "Could not open resolv.conf: %s\n",
strerror(errno));
return errno;
}
}
}
fprintf(file, "# Added automatically by DHCP\n");
const char* nameserver;
for (int32 i = 0; resolverConfiguration.FindString("nameserver", i,
&nameserver) == B_OK; i++) {
fprintf(file, "nameserver %s\n", nameserver);
}
const char* domain;
if (resolverConfiguration.FindString("domain", &domain) == B_OK)
fprintf(file, "domain %s\n", domain);
fprintf(file, "# End of automatic DHCP additions\n");
fclose(file);
return B_OK;
}
bool
NetServer::_QuitLooperForDevice(const char* device)
{
LooperMap::iterator iterator = fDeviceMap.find(device);
if (iterator == fDeviceMap.end())
return false;
if (iterator->second->Lock())
iterator->second->Quit();
fDeviceMap.erase(iterator);
return true;
}
AutoconfigLooper*
NetServer::_LooperForDevice(const char* device)
{
LooperMap::const_iterator iterator = fDeviceMap.find(device);
if (iterator == fDeviceMap.end())
return NULL;
return iterator->second;
}
status_t
NetServer::_ConfigureDevice(const char* device)
{
BMessage interface;
interface.AddString("device", device);
BMessage address;
address.AddString("family", "inet");
address.AddBool("auto_config", true);
interface.AddMessage("address", &address);
return _ConfigureInterface(interface);
}
everything that has not yet been configured via settings before.
\param suggestedInterface Contains the configuration of an interface that
does not have any hardware left. It is used to configure the first
unconfigured device. This allows to move a Haiku configuration around
without losing the network configuration.
*/
void
NetServer::_ConfigureDevices(const char* startPath,
BStringList& devicesAlreadyConfigured, BMessage* suggestedInterface)
{
BDirectory directory(startPath);
BEntry entry;
while (directory.GetNextEntry(&entry) == B_OK) {
char name[B_FILE_NAME_LENGTH];
struct stat stat;
BPath path;
if (entry.GetName(name) != B_OK
|| entry.GetPath(&path) != B_OK
|| entry.GetStat(&stat) != B_OK
|| devicesAlreadyConfigured.HasString(path.Path()))
continue;
if (S_ISBLK(stat.st_mode) || S_ISCHR(stat.st_mode)) {
if (suggestedInterface != NULL
&& suggestedInterface->SetString("device", path.Path()) == B_OK
&& _ConfigureInterface(*suggestedInterface) == B_OK)
suggestedInterface = NULL;
else
_ConfigureDevice(path.Path());
} else if (entry.IsDirectory()) {
_ConfigureDevices(path.Path(), devicesAlreadyConfigured,
suggestedInterface);
}
}
}
void
NetServer::_ConfigureInterfacesFromSettings(BStringList& devicesSet,
BMessage* _missingDevice)
{
BMessage interface;
uint32 cookie = 0;
bool missing = false;
while (fSettings.GetNextInterface(cookie, interface) == B_OK) {
const char *device;
if (interface.FindString("device", &device) != B_OK)
continue;
bool disabled = false;
if (interface.FindBool("disabled", &disabled) == B_OK && disabled) {
_DisableInterface(device);
continue;
}
if (!strncmp(device, "/dev/net/", 9)) {
BEntry entry(device);
if (!entry.Exists()) {
if (!missing && _missingDevice != NULL) {
*_missingDevice = interface;
missing = true;
}
continue;
}
}
if (_ConfigureInterface(interface) == B_OK)
devicesSet.Add(device);
}
}
void
NetServer::_BringUpInterfaces()
{
if (!_IsValidFamily(AF_LINK)) {
fprintf(stderr, "%s: The networking stack doesn't seem to be "
"available.\n", Name());
Quit();
return;
}
_RemoveInvalidInterfaces();
BStringList devicesAlreadyConfigured;
BMessage missingDevice;
_ConfigureInterfacesFromSettings(devicesAlreadyConfigured, &missingDevice);
if (!_TestForInterface("loop")) {
BMessage interface;
interface.AddString("device", "loop");
BMessage v4address;
v4address.AddString("family", "inet");
v4address.AddString("address", "127.0.0.1");
interface.AddMessage("address", &v4address);
if (_IsValidFamily(AF_INET6)) {
BMessage v6address;
v6address.AddString("family", "inet6");
v6address.AddString("address", "::1");
interface.AddMessage("address", &v6address);
}
_ConfigureInterface(interface);
}
_ConfigureDevices("/dev/net", devicesAlreadyConfigured,
missingDevice.HasString("device") ? &missingDevice : NULL);
}
if this isn't a loopback device.
*/
void
NetServer::_ConfigureIPv6LinkLocal(const char* name)
{
if (!_IsValidFamily(AF_INET6))
return;
BNetworkInterface interface(name);
if ((interface.Flags() & IFF_LOOPBACK) != 0)
return;
BNetworkAddress link;
status_t result = interface.GetHardwareAddress(link);
if (result != B_OK || link.LinkLevelAddressLength() != 6)
return;
const uint8* mac = link.LinkLevelAddress();
static const uint8 zeroMac[6] = {0, 0, 0, 0, 0, 0};
static const uint8 fullMac[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
if (memcmp(mac, zeroMac, 6) == 0
|| memcmp(mac, fullMac, 6) == 0) {
syslog(LOG_DEBUG, "%s: MacAddress for interface '%s' is invalid.",
__func__, name);
return;
}
in6_addr addressRaw;
memset(addressRaw.s6_addr, 0, sizeof(addressRaw.s6_addr));
addressRaw.s6_addr[0] = 0xfe;
addressRaw.s6_addr[1] = 0x80;
addressRaw.s6_addr[8] = mac[0] ^ 0x02;
addressRaw.s6_addr[9] = mac[1];
addressRaw.s6_addr[10] = mac[2];
addressRaw.s6_addr[11] = 0xff;
addressRaw.s6_addr[12] = 0xfe;
addressRaw.s6_addr[13] = mac[3];
addressRaw.s6_addr[14] = mac[4];
addressRaw.s6_addr[15] = mac[5];
BNetworkAddress localLinkAddress(addressRaw, 0);
BNetworkAddress localLinkMask(
AF_INET6,
"ffff:ffff:ffff:ffff::",
(uint16)0,
B_UNCONFIGURED_ADDRESS_FAMILIES);
BNetworkAddress localLinkBroadcast(
AF_INET6,
"fe80::ffff:ffff:ffff:ffff",
(uint16)0,
B_UNCONFIGURED_ADDRESS_FAMILIES);
if (interface.FindAddress(localLinkAddress) >= 0) {
There isn't any flag at the moment though for address scope
*/
syslog(LOG_DEBUG, "%s: Local Link address already assigned to %s\n",
__func__, name);
return;
}
BNetworkInterfaceAddress interfaceAddress;
interfaceAddress.SetAddress(localLinkAddress);
interfaceAddress.SetMask(localLinkMask);
interfaceAddress.SetBroadcast(localLinkMask);
Need to blast an icmp packet over the IPv6 network from :: to ensure
there aren't duplicate MAC addresses on the network. (definitely an
edge case, but a possible issue)
*/
interface.AddAddress(interfaceAddress);
}
void
NetServer::_StartServices()
{
BHandler* services = new (std::nothrow) Services(fSettings.Services());
if (services != NULL) {
AddHandler(services);
fServices = BMessenger(services);
}
}
status_t
NetServer::_HandleDeviceMonitor(BMessage* message)
{
int32 opcode;
const char* path;
if (message->FindInt32("opcode", &opcode) != B_OK
|| (opcode != B_ENTRY_CREATED && opcode != B_ENTRY_REMOVED)
|| message->FindString("path", &path) != B_OK)
return B_BAD_VALUE;
if (strncmp(path, "/dev/net/", 9)) {
return B_NAME_NOT_FOUND;
}
if (opcode == B_ENTRY_CREATED)
_ConfigureDevice(path);
else
_RemoveInterface(path);
return B_OK;
}
status_t
NetServer::_AutoJoinNetwork(const BMessage& message)
{
const char* name = NULL;
if (message.FindString("device", &name) != B_OK)
return B_BAD_VALUE;
BNetworkDevice device(name);
uint32 cookie = 0;
BMessage networkMessage;
while (fSettings.GetNextNetwork(cookie, networkMessage) == B_OK) {
status_t status = B_ERROR;
wireless_network network;
const char* networkName;
BNetworkAddress link;
const char* mac = NULL;
if (networkMessage.FindString("mac", &mac) == B_OK) {
link.SetTo(AF_LINK, mac);
status = device.GetNetwork(link, network);
} else if (networkMessage.FindString("name", &networkName) == B_OK)
status = device.GetNetwork(networkName, network);
if (status == B_OK) {
status = _JoinNetwork(message, mac != NULL ? &link : NULL,
network.name);
printf("auto join network \"%s\": %s\n", network.name,
strerror(status));
if (status == B_OK)
return B_OK;
}
}
return B_NO_INIT;
}
status_t
NetServer::_JoinNetwork(const BMessage& message, const BNetworkAddress* address,
const char* name)
{
const char* deviceName;
if (message.FindString("device", &deviceName) != B_OK)
return B_BAD_VALUE;
BNetworkAddress deviceAddress;
message.FindFlat("address", &deviceAddress);
if (address == NULL)
address = &deviceAddress;
if (name == NULL)
message.FindString("name", &name);
if (name == NULL) {
if (address->Family() != AF_LINK)
return B_BAD_VALUE;
}
bool found = false;
uint32 cookie = 0;
BMessage networkMessage;
while (fSettings.GetNextNetwork(cookie, networkMessage) == B_OK) {
const char* networkName;
if (networkMessage.FindString("name", &networkName) == B_OK
&& name != NULL && address->Family() != AF_LINK
&& !strcmp(name, networkName)) {
found = true;
break;
}
const char* mac;
if (networkMessage.FindString("mac", &mac) == B_OK
&& address->Family() == AF_LINK) {
BNetworkAddress link(AF_LINK, mac);
if (link == *address) {
found = true;
break;
}
}
}
const char* password;
if (message.FindString("password", &password) != B_OK && found)
password = networkMessage.FindString("password");
BNetworkDevice device(deviceName);
wireless_network network;
bool askForConfig = false;
if ((address->Family() != AF_LINK
|| device.GetNetwork(*address, network) != B_OK)
&& device.GetNetwork(name, network) != B_OK) {
strlcpy(network.name, name != NULL ? name : "", sizeof(network.name));
network.address = *address;
network.authentication_mode = B_NETWORK_AUTHENTICATION_NONE;
network.cipher = 0;
network.group_cipher = 0;
network.key_mode = 0;
askForConfig = true;
}
BString string;
if ((message.FindString("authentication", &string) == B_OK
&& !string.IsEmpty())
|| (found && networkMessage.FindString("authentication", &string)
== B_OK && !string.IsEmpty())) {
askForConfig = false;
if (string.ICompare("wpa2") == 0) {
network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA2;
network.key_mode = B_KEY_MODE_IEEE802_1X;
network.cipher = network.group_cipher = B_NETWORK_CIPHER_CCMP;
} else if (string.ICompare("wpa") == 0) {
network.authentication_mode = B_NETWORK_AUTHENTICATION_WPA;
network.key_mode = B_KEY_MODE_IEEE802_1X;
network.cipher = network.group_cipher = B_NETWORK_CIPHER_TKIP;
} else if (string.ICompare("wep") == 0) {
network.authentication_mode = B_NETWORK_AUTHENTICATION_WEP;
network.key_mode = B_KEY_MODE_NONE;
network.cipher = network.group_cipher = B_NETWORK_CIPHER_WEP_40;
} else if (string.ICompare("none") != 0 && string.ICompare("open") != 0) {
fprintf(stderr, "%s: invalid authentication mode.\n", name);
askForConfig = true;
}
}
BMessenger wpaSupplicant(kWPASupplicantSignature);
if (!wpaSupplicant.IsValid()) {
if (!askForConfig
&& network.authentication_mode == B_NETWORK_AUTHENTICATION_NONE) {
status_t status = set_80211(deviceName, IEEE80211_IOC_SSID,
network.name, strlen(network.name));
if (status != B_OK) {
fprintf(stderr, "%s: joining SSID failed: %s\n", name,
strerror(status));
return status;
}
}
status_t status = be_roster->Launch(kWPASupplicantSignature);
if (status != B_OK && status != B_ALREADY_RUNNING)
return status;
wpaSupplicant.SetTo(kWPASupplicantSignature);
if (!wpaSupplicant.IsValid())
return B_ERROR;
}
BMessage join(kMsgWPAJoinNetwork);
status_t status = join.AddString("device", deviceName);
if (status == B_OK)
status = join.AddString("name", network.name);
if (status == B_OK)
status = join.AddFlat("address", &network.address);
if (status == B_OK && !askForConfig)
status = join.AddUInt32("authentication", network.authentication_mode);
if (status == B_OK && password != NULL)
status = join.AddString("password", password);
if (status != B_OK)
return status;
status = wpaSupplicant.SendMessage(&join);
if (status != B_OK)
return status;
return B_OK;
}
status_t
NetServer::_LeaveNetwork(const BMessage& message)
{
const char* deviceName;
if (message.FindString("device", &deviceName) != B_OK)
return B_BAD_VALUE;
int32 reason;
if (message.FindInt32("reason", &reason) != B_OK)
reason = IEEE80211_REASON_AUTH_LEAVE;
BMessenger wpaSupplicant(kWPASupplicantSignature);
if (wpaSupplicant.IsValid()) {
BMessage leave(kMsgWPALeaveNetwork);
status_t status = leave.AddString("device", deviceName);
if (status == B_OK)
status = leave.AddInt32("reason", reason);
if (status != B_OK)
return status;
status = wpaSupplicant.SendMessage(&leave);
if (status == B_OK)
return B_OK;
}
BNetworkDevice device(deviceName);
wireless_network network;
uint32 cookie = 0;
if (device.GetNextAssociatedNetwork(cookie, network) != B_OK
|| network.authentication_mode != B_NETWORK_AUTHENTICATION_NONE) {
return B_ERROR;
}
ieee80211req_mlme mlmeRequest;
memset(&mlmeRequest, 0, sizeof(mlmeRequest));
mlmeRequest.im_op = IEEE80211_MLME_DISASSOC;
mlmeRequest.im_reason = reason;
return set_80211(deviceName, IEEE80211_IOC_MLME, &mlmeRequest,
sizeof(mlmeRequest));
}
int
main(int argc, char** argv)
{
srand(system_time());
status_t status;
NetServer server(status);
if (status != B_OK) {
fprintf(stderr, "net_server: Failed to create application: %s\n",
strerror(status));
return 1;
}
server.Run();
return 0;
}