#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;
}
}
bool
NetServer::_IsValidFamily(uint32 family)
{
int socket = ::socket(family, SOCK_DGRAM, 0);
if (socket < 0)
return false;
close(socket);
return true;
}
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);
}
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);
}
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) {
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);
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;
}