#include "PPPManager.h"
#include "PPPInterface.h"
#include "MessageDriverSettingsUtils.h"
#include <Directory.h>
#include <File.h>
#include <Message.h>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <settings_tools.h>
#include <unistd.h>
#include <net/if.h>
#include <net/if_media.h>
#include <net/if_types.h>
#include <Message.h>
#include <Messenger.h>
#include <NetworkDevice.h>
#include <NetworkInterface.h>
#include <NetworkRoster.h>
#include <NetServer.h>
PPPManager::PPPManager()
{
int family = AF_INET;
fFD = socket(family, SOCK_DGRAM, 0);
}
PPPManager::~PPPManager()
{
if (fFD >= 0)
close(fFD);
}
bool
PPPManager::SetDefaultInterface(const BString name)
{
BMessage settings;
if (!ReadMessageDriverSettings("ptpnet.settings", &settings))
settings.MakeEmpty();
BMessage parameter;
int32 index = 0;
if (FindMessageParameter("default", settings, ¶meter, &index))
settings.RemoveData(MDSU_PARAMETERS, index);
parameter.MakeEmpty();
if (name != "") {
parameter.AddString(MDSU_NAME, "default");
parameter.AddString(MDSU_VALUES, name);
settings.AddMessage(MDSU_PARAMETERS, ¶meter);
}
BFile file(PTP_SETTINGS_PATH, B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
if (file.InitCheck() != B_OK)
return false;
if (WriteMessageDriverSettings(file, settings))
return true;
else
return false;
}
BString
PPPManager::DefaultInterface()
{
void *handle = load_driver_settings("ptpnet.settings");
BString name = get_driver_parameter(handle, "default", NULL, NULL);
unload_driver_settings(handle);
return name;
}
bool
PPPManager::GetSettingsDirectory(BDirectory *settingsDirectory)
{
if (settingsDirectory) {
BDirectory settings(PTP_INTERFACE_SETTINGS_PATH);
if (settings.InitCheck() != B_OK) {
create_directory(PTP_INTERFACE_SETTINGS_PATH, 0750);
settings.SetTo(PTP_INTERFACE_SETTINGS_PATH);
if (settings.InitCheck() != B_OK)
return false;
}
*settingsDirectory = settings;
}
return true;
}
status_t
PPPManager::InitCheck() const
{
if (fFD < 0)
return B_ERROR;
else
return B_OK;
}
status_t
PPPManager::Control(uint32 op, void *data, size_t length) const
{
if (InitCheck() != B_OK)
return B_ERROR;
control_net_module_args args;
sprintf(args.ifr_name, "%s", "ppp1");
args.name = PPP_INTERFACE_MODULE_NAME;
args.op = op;
args.data = data;
args.length = length;
return ioctl(fFD, NET_STACK_CONTROL_NET_MODULE, &args);
}
status_t
PPPManager::ControlModule(const char *name, uint32 op, void *data,
size_t length) const
{
if (!name)
return B_ERROR;
control_net_module_args args;
sprintf(args.ifr_name, "%s", "ppp1");
args.name = name;
args.op = op;
args.data = data;
args.length = length;
return Control(PPPC_CONTROL_MODULE, &args, sizeof(args));
}
ppp_interface_id
PPPManager::CreateInterface(const driver_settings *settings) const
{
ppp_interface_description_info info;
info.u.settings = settings;
if (Control(PPPC_CREATE_INTERFACE, &info, sizeof(info)) != B_OK)
return PPP_UNDEFINED_INTERFACE_ID;
else
return info.interface;
}
ppp_interface_id
PPPManager::CreateInterfaceWithName(const char *name) const
{
ppp_interface_id ID = InterfaceWithName(name);
if (ID != PPP_UNDEFINED_INTERFACE_ID)
return ID;
BNetworkInterface interface(name);
if (!interface.Exists()) {
BNetworkRoster& roster = BNetworkRoster::Default();
status_t status = roster.AddInterface(interface);
if (status != B_OK) {
fprintf(stderr, "PPPManager::CreateInterfaceWithName: Could not add interface: %s\n",
strerror(status));
return PPP_UNDEFINED_INTERFACE_ID;
}
return InterfaceWithName(name);
}
return PPP_UNDEFINED_INTERFACE_ID;
}
bool
delete_interface(const char* name)
{
BNetworkInterface interface(name);
BNetworkRoster& roster = BNetworkRoster::Default();
status_t status = roster.RemoveInterface(interface);
if (status != B_OK) {
fprintf(stderr, "delete_interface: Could not delete interface %s\n",
name);
return false;
}
return true;
}
bool
PPPManager::DeleteInterface(const char* name) const
{
ppp_interface_id ID = InterfaceWithName(name);
if (ID == PPP_UNDEFINED_INTERFACE_ID)
return false;
return delete_interface(name);
}
bool
PPPManager::DeleteInterface(ppp_interface_id ID) const
{
if (Control(PPPC_DELETE_INTERFACE, &ID, sizeof(ID)) != B_OK)
return false;
else
return true;
}
ppp_interface_id*
PPPManager::Interfaces(int32 *count,
ppp_interface_filter filter) const
{
int32 requestCount;
ppp_interface_id *interfaces;
while (true) {
requestCount = *count = CountInterfaces(filter);
if (*count <= 0) {
printf("No interface, count, first round: %" B_PRId32 "\n", *count);
return NULL;
}
requestCount += 10;
interfaces = new ppp_interface_id[requestCount];
*count = GetInterfaces(interfaces, requestCount, filter);
if (*count <= 0) {
printf("No interface, count second round: %" B_PRId32 "\n", *count);
delete[] interfaces;
return NULL;
}
if (*count < requestCount)
break;
delete[] interfaces;
}
return interfaces;
}
int32
PPPManager::GetInterfaces(ppp_interface_id *interfaces, int32 count,
ppp_interface_filter filter) const
{
ppp_get_interfaces_info info;
info.interfaces = interfaces;
info.count = count;
info.filter = filter;
if (Control(PPPC_GET_INTERFACES, &info, sizeof(info)) != B_OK)
return -1;
else
return info.resultCount;
}
ppp_interface_id
PPPManager::InterfaceWithSettings(const driver_settings *settings) const
{
ppp_interface_description_info info;
info.u.settings = settings;
info.interface = PPP_UNDEFINED_INTERFACE_ID;
Control(PPPC_FIND_INTERFACE_WITH_SETTINGS, &info, sizeof(info));
return info.interface;
}
ppp_interface_id
PPPManager::InterfaceWithUnit(int32 if_unit) const
{
int32 count;
ppp_interface_id *interfaces = Interfaces(&count, PPP_REGISTERED_INTERFACES);
if (!interfaces)
return PPP_UNDEFINED_INTERFACE_ID;
ppp_interface_id id = PPP_UNDEFINED_INTERFACE_ID;
PPPInterface interface;
ppp_interface_info_t info;
for (int32 index = 0; index < count; index++) {
interface.SetTo(interfaces[index]);
if (interface.InitCheck() == B_OK && interface.GetInterfaceInfo(&info)
&& info.info.if_unit == if_unit) {
id = interface.ID();
break;
}
}
delete[] interfaces;
return id;
}
ppp_interface_id
PPPManager::InterfaceWithName(const char *name) const
{
if (!name)
return PPP_UNDEFINED_INTERFACE_ID;
int32 count;
ppp_interface_id *interfaces = Interfaces(&count, PPP_REGISTERED_INTERFACES);
if (!interfaces || count <= 0) {
printf("ERROR: Could not get ppp name:%s\n", name);
return PPP_UNDEFINED_INTERFACE_ID;
}
ppp_interface_id id = PPP_UNDEFINED_INTERFACE_ID;
PPPInterface interface;
ppp_interface_info_t info;
for (int32 index = 0; index < count; index++) {
interface.SetTo(interfaces[index]);
if (interface.InitCheck() == B_OK && interface.GetInterfaceInfo(&info)
&& strlen(info.info.name) > 0 && !strcasecmp(info.info.name, name)) {
id = interface.ID();
break;
}
}
delete[] interfaces;
if (id != PPP_UNDEFINED_INTERFACE_ID)
return id;
else if (!strncmp(name, "ppp", 3) && strlen(name) > 3 && isdigit(name[3]))
return InterfaceWithUnit(atoi(name + 3));
else if (isdigit(name[0]))
return atoi(name);
else
return PPP_UNDEFINED_INTERFACE_ID;
}
bool
is_ppp_interface(const char* name)
{
BNetworkInterface interface(name);
BNetworkAddress linkAddress;
status_t status = interface.GetHardwareAddress(linkAddress);
if (status == B_OK) {
switch (linkAddress.LinkLevelType()) {
case IFT_ETHER:
break;
case IFT_LOOP:
break;
case IFT_MODEM:
break;
case IFT_PPP:
return true;
break;
default:
;
}
}
return false;
}
int32
count_ppp_interface(void)
{
int32 count = 0;
BNetworkRoster& roster = BNetworkRoster::Default();
BNetworkInterface interface;
uint32 cookie = 0;
while (roster.GetNextInterface(&cookie, interface) == B_OK) {
if (is_ppp_interface(interface.Name()))
count++;
}
return count;
}
int32
PPPManager::CountInterfaces(ppp_interface_filter filter) const
{
return count_ppp_interface();
}
bool
PPPManager::EnableReports(ppp_report_type type, thread_id thread,
int32 flags) const
{
ppp_report_request request;
request.type = type;
request.thread = thread;
request.flags = flags;
return Control(PPPC_ENABLE_REPORTS, &request, sizeof(request)) == B_OK;
}
bool
PPPManager::DisableReports(ppp_report_type type, thread_id thread) const
{
ppp_report_request request;
request.type = type;
request.thread = thread;
return Control(PPPC_DISABLE_REPORTS, &request, sizeof(request)) == B_OK;
}