From 0fc3ae8c5cca9348dee43722a9711be112ca5156 Mon Sep 17 00:00:00 2001 From: Waldemar Kornewald Date: Wed, 15 Oct 2003 16:01:40 +0000 Subject: [PATCH] Finished PPP interface manager module. TODO: - IPCP protocol module - PAP authentication module - PPPoE device module - pppdial cmd-line app including needed net_stack_driver changes for control() function support - tests, tests, tests :)) git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5040 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../network/interfaces/ppp/PPPManager.cpp | 410 ++++++++++++++++-- .../network/interfaces/ppp/PPPManager.h | 25 +- .../kernel/network/interfaces/ppp/ppp.cpp | 32 ++ 3 files changed, 431 insertions(+), 36 deletions(-) diff --git a/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp b/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp index 87662bbb1b..ffa40ce01e 100644 --- a/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp +++ b/src/add-ons/kernel/network/interfaces/ppp/PPPManager.cpp @@ -6,50 +6,172 @@ //--------------------------------------------------------------------- #include "PPPManager.h" +#include +#include -#include #include #include #include +#include -static int ppp_ifnet_stop(ifnet *ifp) -{ - return B_ERROR; -} - - -int ppp_ifnet_output(ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, - struct rtentry *rt0) -{ - return B_ERROR; -} - - -int ppp_ifnet_ioctl(struct ifnet *ifp, ulong cmd, caddr_t data) -{ - return B_ERROR; -} +#ifdef _KERNEL_MODE +#define spawn_thread spawn_kernel_thread +#endif static const char ppp_if_name_base[] = "ppp"; +static +status_t +deleter_thread(void *data) +{ + PPPManager *manager = (PPPManager*) data; + thread_id sender; + int32 code; + + while(true) { + manager->DeleterThreadEvent(); + + // check if the manager is being destroyed + if(receive_data_with_timeout(&sender, &code, NULL, 0, 50000) == B_OK) + return B_OK; + } + + return B_OK; +} + + +static +void +pulse_timer(void *data) +{ + ((PPPManager*)data)->Pulse(); +} + + PPPManager::PPPManager() - : fReportManager(fLock), + : fReportManager(fReportLock), fNextID(1) { + fDeleterThread = spawn_thread(deleter_thread, "PPPManager: deleter_thread", + B_NORMAL_PRIORITY, this); + resume_thread(fDeleterThread); + fPulseTimer = net_add_timer(pulse_timer, this, PPP_PULSE_RATE); } PPPManager::~PPPManager() { + int32 tmp; + send_data(fDeleterThread, 0, NULL, 0); + // notify deleter_thread that we are being destroyed + wait_for_thread(fDeleterThread, &tmp); + net_remove_timer(fPulseTimer); + + // now really delete the interfaces (the deleter_thread is not running) + interface_entry *entry; + for(int32 index = 0; index < fEntries.CountItems(); index++) { + entry = fEntries.ItemAt(index); + if(entry) + delete entry->interface; + delete entry; + } +} + + +int32 +PPPManager::Stop(ifnet *ifp) +{ + LockerHelper locker(fLock); + + interface_entry *entry = EntryFor(ifp); + if(!entry) + return B_ERROR; + + DeleteInterface(entry->interface->ID()); + + return B_OK; +} + + +int32 +PPPManager::Output(ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, + struct rtentry *rt0) +{ + if(dst->sa_family == AF_UNSPEC) + return B_ERROR; + + LockerHelper locker(fLock); + interface_entry *entry = EntryFor(ifp); + if(!entry) + return B_ERROR; + + ++entry->accessing; + locker.UnlockNow(); + + if(ifp->if_flags & (IFF_UP | IFF_RUNNING) != (IFF_UP | IFF_RUNNING)) { + m_freem(buf); + --entry->accessing; + return ENETDOWN; + } + + int32 result = B_ERROR; + PPPProtocol *protocol = entry->interface->FirstProtocol(); + for(; protocol; protocol = protocol->NextProtocol()) { + if(!protocol->IsEnabled() || protocol->AddressFamily() != dst->sa_family) + continue; + + result = protocol->Send(buf, protocol->ProtocolNumber()); + if(result == PPP_UNHANDLED) + continue; + + --entry->accessing; + return result; + } + + m_freem(buf); + --entry->accessing; + return B_ERROR; +} + + +int32 +PPPManager::Control(ifnet *ifp, ulong cmd, caddr_t data) +{ + LockerHelper locker(fLock); + interface_entry *entry = EntryFor(ifp); + if(!entry || entry->deleting) + return B_ERROR; + + ++entry->accessing; + locker.UnlockNow(); + + switch(cmd) { + case SIOCSIFFLAGS: + if(((ifreq*)data)->ifr_flags & IFF_DOWN) + DeleteInterface(entry->interface->ID()); + else if(((ifreq*)data)->ifr_flags & IFF_UP) { + int32 result = entry->interface->Up() ? B_OK : B_ERROR; + --entry->accessing; + return result; + } + break; + + default: + return entry->interface->StackControl(cmd, data); + } + + --entry->accessing; + return B_OK; } interface_id -PPPManager::CreateInterface(const driver_settings *settings, interface_id parentID) +PPPManager::CreateInterface(const driver_settings *settings, + interface_id parentID = PPP_UNDEFINED_INTERFACE_ID) { LockerHelper locker(fLock); @@ -73,6 +195,12 @@ PPPManager::CreateInterface(const driver_settings *settings, interface_id parent fEntries.AddItem(entry); locker.UnlockNow(); + if(Report(PPP_MANAGER_REPORT, PPP_REPORT_INTERFACE_CREATED, + &id, sizeof(interface_id)) != B_OK) { + DeleteInterface(id); + return PPP_UNDEFINED_INTERFACE_ID; + } + if(!entry->interface->DoesDialOnDemand()) entry->interface->Up(); @@ -98,9 +226,9 @@ PPPManager::RemoveInterface(interface_id ID) { LockerHelper locker(fLock); - int32 index = 0; + int32 index; interface_entry *entry = EntryFor(ID, &index); - if(!entry) + if(!entry || entry->deleting) return; UnregisterInterface(ID); @@ -116,7 +244,7 @@ PPPManager::RegisterInterface(interface_id ID) LockerHelper locker(fLock); interface_entry *entry = EntryFor(ID); - if(!entry) + if(!entry || entry->deleting) return NULL; // maybe the interface is already registered @@ -144,21 +272,117 @@ PPPManager::RegisterInterface(interface_id ID) bool PPPManager::UnregisterInterface(interface_id ID) { - return false; + LockerHelper locker(fLock); + + interface_entry *entry = EntryFor(ID); + if(!entry) + return false; + + if(entry->interface->Ifnet()) { + if_detach(entry->interface->Ifnet()); + delete entry->interface->Ifnet(); + } + + return true; } status_t PPPManager::Control(uint32 op, void *data, size_t length) { - return B_ERROR; + // this method is intended for use by userland applications + + switch(op) { + case PPPC_CREATE_INTERFACE: { + if(length < sizeof(pppc_create_interface_info) || !data) + return B_ERROR; + + pppc_create_interface_info *info = (pppc_create_interface_info*) data; + if(!info->settings) + return B_ERROR; + + info->resultID = CreateInterface(info->settings); + // parents cannot be set from userland + return info->resultID != PPP_UNDEFINED_INTERFACE_ID ? B_OK : B_ERROR; + } break; + + case PPPC_DELETE_INTERFACE: + if(length != sizeof(interface_id) || !data) + return B_ERROR; + + DeleteInterface(*(interface_id*)data); + break; + + case PPPC_CONTROL_INTERFACE: { + if(length < sizeof(ppp_control_info) || !data) + return B_ERROR; + + LockerHelper locker(fLock); + + ppp_control_info *control = (ppp_control_info*) data; + interface_entry *entry = EntryFor(control->index); + if(!entry) + return B_BAD_INDEX; + + return entry->interface->Control(control->op, control->data, + control->length); + } break; + + case PPPC_GET_INTERFACES: { + if(length < sizeof(pppc_get_interfaces_info) || !data) + return B_ERROR; + + pppc_get_interfaces_info *info = (pppc_get_interfaces_info*) data; + if(!info->interfaces) + return B_ERROR; + + info->resultCount = GetInterfaces(info->interfaces, info->count, + info->filter); + return info->resultCount >= 0 ? B_OK : B_ERROR; + } break; + + case PPPC_COUNT_INTERFACES: + if(length != sizeof(ppp_interface_filter) || !data) + return B_ERROR; + + return CountInterfaces(*(ppp_interface_filter*)data); + break; + + case PPPC_ENABLE_MANAGER_REPORTS: { + if(length < sizeof(ppp_report_request) || !data) + return B_ERROR; + + ppp_report_request *request = (ppp_report_request*) data; + ReportManager().EnableReports(request->type, request->thread, + request->flags); + } break; + + case PPPC_DISABLE_MANAGER_REPORTS: { + if(length < sizeof(ppp_report_request) || !data) + return B_ERROR; + + ppp_report_request *request = (ppp_report_request*) data; + ReportManager().DisableReports(request->type, request->thread); + } break; + + default: + return B_BAD_VALUE; + } + + return B_OK; } status_t PPPManager::ControlInterface(interface_id ID, uint32 op, void *data, size_t length) { - return B_ERROR; + LockerHelper locker(fLock); + + interface_entry *entry = EntryFor(ID); + if(entry && !entry->deleting) + return entry->interface->Control(op, data, length); + + return B_BAD_INDEX; } @@ -166,30 +390,111 @@ int32 PPPManager::GetInterfaces(interface_id *interfaces, int32 count, ppp_interface_filter filter = PPP_REGISTERED_INTERFACES) { - return 0; + LockerHelper locker(fLock); + + int32 item = 0; + // the current item in 'interfaces' (also the number of ids copied) + interface_entry *entry; + + for(int32 index = 0; item < count && index < fEntries.CountItems(); index++) { + entry = fEntries.ItemAt(index); + if(!entry || entry->deleting) + continue; + + switch(filter) { + case PPP_ALL_INTERFACES: + interfaces[item++] = entry->interface->ID(); + break; + + case PPP_REGISTERED_INTERFACES: + if(entry->interface->Ifnet()) + interfaces[item++] = entry->interface->ID(); + break; + + case PPP_UNREGISTERED_INTERFACES: + if(!entry->interface->Ifnet()) + interfaces[item++] = entry->interface->ID(); + break; + + default: + return B_ERROR; + // the filter is unknown + } + } + + return item; } int32 PPPManager::CountInterfaces(ppp_interface_filter filter = PPP_REGISTERED_INTERFACES) { - return 0; + LockerHelper locker(fLock); + + if(filter == PPP_ALL_INTERFACES) + return fEntries.CountItems(); + + int32 count = 0; + interface_entry *entry; + + for(int32 index = 0; index < fEntries.CountItems(); index++) { + entry = fEntries.ItemAt(index); + if(!entry || entry->deleting) + continue; + + switch(filter) { + case PPP_REGISTERED_INTERFACES: + if(entry->interface->Ifnet()) + ++count; + break; + + case PPP_UNREGISTERED_INTERFACES: + if(!entry->interface->Ifnet()) + ++count; + break; + + default: + return B_ERROR; + // the filter is unknown + } + } + + return count; } interface_entry* -PPPManager::EntryFor(interface_id ID, int32 *start = NULL) const +PPPManager::EntryFor(interface_id ID, int32 *saveIndex = NULL) const { if(ID == PPP_UNDEFINED_INTERFACE_ID) return NULL; interface_entry *entry; - - for(int32 index = start ? *start : 0; index < fEntries.CountItems(); index++) { + for(int32 index = 0; index < fEntries.CountItems(); index++) { entry = fEntries.ItemAt(index); if(entry && entry->interface->ID() == ID) { - if(start) - *start = index; + if(saveIndex) + *saveIndex = index; + return entry; + } + } + + return NULL; +} + + +interface_entry* +PPPManager::EntryFor(ifnet *ifp, int32 *saveIndex = NULL) const +{ + if(!ifp) + return NULL; + + interface_entry *entry; + for(int32 index = 0; index < fEntries.CountItems(); index++) { + entry = fEntries.ItemAt(index); + if(entry && entry->interface->Ifnet() == ifp) { + if(saveIndex) + *saveIndex = index; return entry; } } @@ -233,3 +538,42 @@ PPPManager::FindUnit() const return unit; } + + +void +PPPManager::DeleterThreadEvent() +{ + LockerHelper locker(fLock); + + // delete and remove marked interfaces + interface_entry *entry; + for(int32 index = 0; index < fEntries.CountItems(); index++) { + entry = fEntries.ItemAt(index); + if(!entry) { + fEntries.RemoveItem(index); + --index; + continue; + } + + if(entry->deleting && entry->accessing == 0) { + delete entry->interface; + delete entry; + fEntries.RemoveItem(index); + --index; + } + } +} + + +void +PPPManager::Pulse() +{ + LockerHelper locker(fLock); + + interface_entry *entry; + for(int32 index = 0; index < fEntries.CountItems(); index++) { + entry = fEntries.ItemAt(index); + if(entry) + entry->interface->Pulse(); + } +} diff --git a/src/add-ons/kernel/network/interfaces/ppp/PPPManager.h b/src/add-ons/kernel/network/interfaces/ppp/PPPManager.h index 28611630ab..5070707d62 100644 --- a/src/add-ons/kernel/network/interfaces/ppp/PPPManager.h +++ b/src/add-ons/kernel/network/interfaces/ppp/PPPManager.h @@ -10,6 +10,14 @@ #include #include +#include + + +// these functions are defined in ppp.cpp +extern int ppp_ifnet_stop(ifnet *ifp); +extern int ppp_ifnet_output(ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, + struct rtentry *rt0); +extern int ppp_ifnet_ioctl(ifnet *ifp, ulong cmd, caddr_t data); typedef struct interface_entry { @@ -24,8 +32,13 @@ class PPPManager { PPPManager(); ~PPPManager(); + int32 Stop(ifnet *ifp); + int32 Output(ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, + struct rtentry *rt0); + int32 Control(ifnet *ifp, ulong cmd, caddr_t data); + interface_id CreateInterface(const driver_settings *settings, - interface_id parentID); + interface_id parentID = PPP_UNDEFINED_INTERFACE_ID); void DeleteInterface(interface_id ID); void RemoveInterface(interface_id ID); @@ -46,19 +59,25 @@ class PPPManager { { return ReportManager().Report(type, code, data, length); } // returns false if reply was bad (or an error occured) - interface_entry *EntryFor(interface_id ID, int32 *start = NULL) const; + interface_entry *EntryFor(interface_id ID, int32 *saveIndex = NULL) const; + interface_entry *EntryFor(ifnet *ifp, int32 *saveIndex = NULL) const; interface_id NextID() { return (interface_id) atomic_add((vint32*) &fNextID, 1); } + + void DeleterThreadEvent(); + void Pulse(); private: int32 FindUnit() const; private: - BLocker fLock; + BLocker fLock, fReportLock; PPPReportManager fReportManager; List fEntries; interface_id fNextID; + thread_id fDeleterThread; + net_timer_id fPulseTimer; }; diff --git a/src/add-ons/kernel/network/interfaces/ppp/ppp.cpp b/src/add-ons/kernel/network/interfaces/ppp/ppp.cpp index 0684c5d322..e6698bf4a1 100644 --- a/src/add-ons/kernel/network/interfaces/ppp/ppp.cpp +++ b/src/add-ons/kernel/network/interfaces/ppp/ppp.cpp @@ -21,6 +21,37 @@ struct core_module_info *core = NULL; static PPPManager *manager = NULL; +int +ppp_ifnet_stop(ifnet *ifp) +{ + if(manager) + return manager->Stop(ifp); + else + return B_ERROR; +} + + +int +ppp_ifnet_output(ifnet *ifp, struct mbuf *buf, struct sockaddr *dst, + struct rtentry *rt0) +{ + if(manager) + return manager->Output(ifp, buf, dst, rt0); + else + return B_ERROR; +} + + +int +ppp_ifnet_ioctl(ifnet *ifp, ulong cmd, caddr_t data) +{ + if(manager) + return manager->Control(ifp, cmd, data); + else + return B_ERROR; +} + + static int ppp_start(void *cpp) @@ -39,6 +70,7 @@ int ppp_stop() { delete manager; + manager = NULL; return B_OK; }