* Copyright 2006-2017, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Axel Dörfler, axeld@pinc-software.de
* Lin Longzhou, linlongzhou@163.com
* Alexander von Gluck IV, kallisti5@unixzen.com
*/
#include <net_stack.h>
#include <NetBufferUtilities.h>
#include <KernelExport.h>
#include <lock.h>
#include <util/AutoLock.h>
#include <util/DoublyLinkedList.h>
#include <new>
#include <ppp_device.h>
#include <KPPPManager.h>
struct entry_private : ppp_interface_entry, DoublyLinkedListLinkImpl<entry_private> {
};
static DoublyLinkedList<entry_private> sEntryList;
net_buffer_module_info* gBufferModule = NULL;
net_stack_module_info* gStackModule = NULL;
static mutex sListLock;
static uint32 ppp_interface_count;
static KPPPInterface* GetInterface(ppp_interface_id ID);
static ppp_interface_id
CreateInterface(const driver_settings* settings, ppp_interface_id parentID)
{
MutexLocker _(sListLock);
if (parentID > 0) {
TRACE("Not support Multi_Link yet!\n");
return 0l;
}
if (settings == NULL) {
TRACE("No driver_settings yet!\n");
return 0l;
}
ppp_interface_count++;
if (GetInterface(ppp_interface_count) != NULL) {
TRACE("PPP Interface already exists!\n");
return 0l;
}
entry_private* pentry = new (std::nothrow) entry_private;
memset(pentry, 0, sizeof(entry_private));
pentry->accessing = ppp_interface_count;
sEntryList.Add(pentry);
KPPPInterface* device = new (std::nothrow) KPPPInterface(NULL,
pentry, ppp_interface_count, NULL, NULL);
if (device == NULL || pentry == NULL) {
TRACE("device or pentry is NULL\n");
ppp_interface_count--;
return 0l;
}
TRACE("setting ppp_interface_count %" B_PRIu32 "\n", ppp_interface_count);
return ppp_interface_count;
}
static ppp_interface_id
CreateInterfaceWithName(const char* name, ppp_interface_id parentID)
{
MutexLocker _(sListLock);
if (parentID > 0) {
dprintf("Not support Multi_Link yet!\n");
return(0);
}
if (strncmp(name, "ppp", 3)) {
dprintf("%s is not ppp device!\n", name);
return(0);
}
ppp_interface_count++;
if (GetInterface(ppp_interface_count) != NULL) {
TRACE("PPP Interface already exists!\n");
return 0l;
}
entry_private* pentry = new (std::nothrow) entry_private;
memset(pentry, 0, sizeof(entry_private));
pentry->accessing = ppp_interface_count;
sEntryList.Add(pentry);
KPPPInterface* device = new (std::nothrow) KPPPInterface(name,
pentry, ppp_interface_count, NULL, NULL);
if (device == NULL || pentry == NULL) {
TRACE("can not create ppp interface!\n");
ppp_interface_count--;
return 0l;
}
TRACE("setting ppp_interface_count %" B_PRIu32 "\n", ppp_interface_count);
return ppp_interface_count;
}
static bool
DeleteInterface(ppp_interface_id ID)
{
MutexLocker _(sListLock);
DoublyLinkedList<entry_private>::Iterator iterator
= sEntryList.GetIterator();
while (iterator.HasNext()) {
entry_private* pentry = iterator.Next();
if ((ppp_interface_id)pentry->accessing == ID) {
pentry->deleting = true;
return true;
}
}
return false;
}
static bool
RemoveInterface(ppp_interface_id ID)
{
MutexLocker _(sListLock);
if (ID <= 0 || ID > ppp_interface_count)
return false;
DoublyLinkedList<entry_private>::Iterator iterator
= sEntryList.GetIterator();
while (iterator.HasNext()) {
entry_private* pentry = iterator.Next();
if ((ppp_interface_id)pentry->accessing == ID) {
pentry->deleting = true;
break;
}
}
return false;
}
static net_device*
RegisterInterface(ppp_interface_id ID)
{
entry_private* entry = NULL;
DoublyLinkedList<entry_private>::Iterator iterator
= sEntryList.GetIterator();
while (iterator.HasNext()) {
entry_private* pentry = iterator.Next();
if ((ppp_interface_id)pentry->accessing == ID) {
entry = pentry;
break;
}
}
if (entry == NULL)
return NULL;
ppp_device* device = new (std::nothrow) ppp_device;
if (device == NULL)
return NULL;
memset(device, 0, sizeof(ppp_device));
device->KPPP_Interface = entry->interface;
return device;
}
static KPPPInterface*
GetInterface(ppp_interface_id ID)
{
DoublyLinkedList<entry_private>::Iterator iterator
= sEntryList.GetIterator();
while (iterator.HasNext()) {
entry_private* pentry = iterator.Next();
TRACE("testing interface id:%" B_PRId32 "\n", pentry->accessing);
if ((ppp_interface_id)(pentry->accessing) == ID) {
TRACE("get interface id:%" B_PRId32 "\n", ID);
return pentry->interface;
}
}
TRACE("can not get interface id:%" B_PRId32 "\n", ID);
return NULL;
}
static bool
UnregisterInterface(ppp_interface_id ID)
{
MutexLocker _(sListLock);
if (ID <= 0 || ID > ppp_interface_count)
return false;
return true;
}
static status_t
ControlInterface(ppp_interface_id ID, uint32 op, void* data, size_t length)
{
MutexLocker _(sListLock);
if (ID <= 0 || ID > ppp_interface_count)
return B_ERROR;
DoublyLinkedList<entry_private>::Iterator iterator
= sEntryList.GetIterator();
while (iterator.HasNext()) {
entry_private* pentry = iterator.Next();
if ((ppp_interface_id)pentry->accessing == ID)
return B_OK;
}
return B_ERROR;
}
static int32
GetInterfaces(ppp_interface_id* interfaces, int32 count, ppp_interface_filter filter)
{
MutexLocker _(sListLock);
if (count <= 0 || count > (int32)ppp_interface_count)
return(0);
uint32 ppp_count = 0;
DoublyLinkedList<entry_private>::Iterator iterator
= sEntryList.GetIterator();
while (iterator.HasNext()) {
entry_private* pentry = iterator.Next();
interfaces[ppp_count] = pentry->accessing;
ppp_count++;
}
return ppp_count;
}
static int32
CountInterfaces(ppp_interface_filter filter)
{
MutexLocker _(sListLock);
uint32 ppp_count = 0;
DoublyLinkedList<entry_private>::Iterator iterator
= sEntryList.GetIterator();
while (iterator.HasNext()) {
iterator.Next();
ppp_count++;
}
return ppp_count;
}
static void
EnableReports(ppp_report_type type, thread_id thread, int32 flags)
{
MutexLocker _(sListLock);
return;
}
static void
DisableReports(ppp_report_type type, thread_id thread)
{
MutexLocker _(sListLock);
return;
}
static bool
DoesReport(ppp_report_type type, thread_id thread)
{
MutexLocker _(sListLock);
return false;
}
static status_t
KPPPManager_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
mutex_init(&sListLock, "KPPPManager");
new (&sEntryList) DoublyLinkedList<entry_private>;
ppp_interface_count = 0;
if (get_module(NET_STACK_MODULE_NAME, (module_info**)&gStackModule)
!= B_OK)
return B_ERROR;
if (get_module(NET_BUFFER_MODULE_NAME, (module_info**)&gBufferModule)
!= B_OK) {
put_module(NET_STACK_MODULE_NAME);
return B_ERROR;
}
return B_OK;
case B_MODULE_UNINIT:
mutex_destroy(&sListLock);
put_module(NET_BUFFER_MODULE_NAME);
put_module(NET_STACK_MODULE_NAME);
return B_OK;
default:
return B_ERROR;
}
}
static ppp_interface_module_info sKPPPManagerModule = {
{
PPP_INTERFACE_MODULE_NAME,
0,
KPPPManager_std_ops
},
CreateInterface,
CreateInterfaceWithName,
DeleteInterface,
RemoveInterface,
RegisterInterface,
GetInterface,
UnregisterInterface,
ControlInterface,
GetInterfaces,
CountInterfaces,
EnableReports,
DisableReports,
DoesReport
};
module_info* modules[] = {
(module_info*)&sKPPPManagerModule,
NULL
};