* Work-in-progress of a network notification implementation.
* Compiles, but doesn't work at all yet. For those who wonder: the networking notifications are put into a separate module, so that the network stack can be unloaded without losing connection, IOW user applications will continue to retrieve notifications when the stack is loaded again. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28790 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Haiku, Inc. All Rights Reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
#ifndef NET_NOTIFICATIONS_H
|
||||||
|
#define NET_NOTIFICATIONS_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <module.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define NET_NOTIFICATIONS_MODULE_NAME "network/notifications/v1"
|
||||||
|
|
||||||
|
namespace BPrivate {
|
||||||
|
class KMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct net_notifications_module_info {
|
||||||
|
module_info info;
|
||||||
|
|
||||||
|
void (*send_notification)(const BPrivate::KMessage* event);
|
||||||
|
};
|
||||||
|
|
||||||
|
// generic syscall interface
|
||||||
|
#define NET_NOTIFICATIONS_SYSCALLS "network/notifications"
|
||||||
|
|
||||||
|
#define NET_NOTIFICATIONS_START_WATCHING 1
|
||||||
|
#define NET_NOTIFICATIONS_STOP_WATCHING 2
|
||||||
|
|
||||||
|
struct net_notifications_control {
|
||||||
|
uint32 flags;
|
||||||
|
port_id port;
|
||||||
|
uint32 token;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: the following part of this header should end up in a public header
|
||||||
|
// some day!
|
||||||
|
|
||||||
|
#define B_NETWORK_INTERFACE_ADDED 1
|
||||||
|
#define B_NETWORK_INTERFACE_REMOVED 2
|
||||||
|
#define B_NETWORK_INTERFACE_CHANGED 3
|
||||||
|
#define B_NETWORK_DEVICE_LINK_CHANGED 4
|
||||||
|
// TODO: add routes, stack unloaded/loaded, ... events
|
||||||
|
|
||||||
|
enum {
|
||||||
|
B_WATCH_NETWORK_INTERFACE_CHANGES = 0x0001,
|
||||||
|
B_WATCH_NETWORK_LINK_CHANGES = 0x0002
|
||||||
|
};
|
||||||
|
|
||||||
|
#define B_NETWORK_MONITOR '_NTN'
|
||||||
|
|
||||||
|
#ifndef _KERNEL_MODE
|
||||||
|
# include <Messenger.h>
|
||||||
|
|
||||||
|
status_t start_watching_network(uint32 flags, const BMessenger& target);
|
||||||
|
status_t start_watching_network(uint32 flags, const BHandler* handler,
|
||||||
|
const BLooper* looper = NULL);
|
||||||
|
|
||||||
|
status_t stop_watching_network(const BMessenger& target);
|
||||||
|
status_t stop_watching_network(const BHandler* handler,
|
||||||
|
const BLooper* looper = NULL);
|
||||||
|
|
||||||
|
#endif // _KERNEL_MODE
|
||||||
|
|
||||||
|
#endif // NET_NOTIFICATIONS_H
|
||||||
@@ -2,5 +2,6 @@ SubDir HAIKU_TOP src add-ons kernel network ;
|
|||||||
|
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ;
|
SubInclude HAIKU_TOP src add-ons kernel network datalink_protocols ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network devices ;
|
SubInclude HAIKU_TOP src add-ons kernel network devices ;
|
||||||
|
SubInclude HAIKU_TOP src add-ons kernel network notifications ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network protocols ;
|
SubInclude HAIKU_TOP src add-ons kernel network protocols ;
|
||||||
SubInclude HAIKU_TOP src add-ons kernel network stack ;
|
SubInclude HAIKU_TOP src add-ons kernel network stack ;
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
SubDir HAIKU_TOP src add-ons kernel network notifications ;
|
||||||
|
|
||||||
|
UseHeaders $(TARGET_PRIVATE_KERNEL_HEADERS) : true ;
|
||||||
|
UsePrivateHeaders net shared ;
|
||||||
|
|
||||||
|
KernelAddon <net>notifications :
|
||||||
|
notifications.cpp
|
||||||
|
;
|
||||||
@@ -0,0 +1,309 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! Provides the networking stack notification service. */
|
||||||
|
|
||||||
|
#include <net_notifications.h>
|
||||||
|
|
||||||
|
//#include <messaging.h>
|
||||||
|
#include <Notifications.h>
|
||||||
|
#include <util/KMessage.h>
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: add generic syscall interface
|
||||||
|
|
||||||
|
|
||||||
|
static UserMessagingMessageSender sNotificationSender;
|
||||||
|
|
||||||
|
struct net_listener : public DoublyLinkedListLinkImpl<net_listener> {
|
||||||
|
~net_listener();
|
||||||
|
|
||||||
|
uint32 flags;
|
||||||
|
NotificationListener* listener;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef DoublyLinkedList<net_listener> ListenerList;
|
||||||
|
|
||||||
|
class UserNetListener : public UserMessagingListener {
|
||||||
|
public:
|
||||||
|
UserNetListener(port_id port, int32 token)
|
||||||
|
: UserMessagingListener(sNotificationSender, port, token)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const NotificationListener& _other) const
|
||||||
|
{
|
||||||
|
const UserNetListener* other
|
||||||
|
= dynamic_cast<const UserNetListener*>(&_other);
|
||||||
|
return other != NULL && other->Port() == Port()
|
||||||
|
&& other->Token() == Token();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class NetNotificationService : public NotificationService {
|
||||||
|
public:
|
||||||
|
NetNotificationService();
|
||||||
|
virtual ~NetNotificationService();
|
||||||
|
|
||||||
|
void Notify(const KMessage& event);
|
||||||
|
|
||||||
|
status_t AddListener(const KMessage* eventSpecifier,
|
||||||
|
NotificationListener& listener);
|
||||||
|
status_t UpdateListener(const KMessage* eventSpecifier,
|
||||||
|
NotificationListener& listener);
|
||||||
|
status_t RemoveListener(const KMessage* eventSpecifier,
|
||||||
|
NotificationListener& listener);
|
||||||
|
|
||||||
|
status_t RemoveUserListeners(port_id port, uint32 token);
|
||||||
|
status_t UpdateUserListener(uint32 flags,
|
||||||
|
port_id port, uint32 token);
|
||||||
|
|
||||||
|
virtual const char* Name() { return "network"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t _AddListener(uint32 flags,
|
||||||
|
NotificationListener& listener);
|
||||||
|
|
||||||
|
recursive_lock fRecursiveLock;
|
||||||
|
ListenerList fListeners;
|
||||||
|
};
|
||||||
|
|
||||||
|
static NetNotificationService sNotificationService;
|
||||||
|
|
||||||
|
|
||||||
|
net_listener::~net_listener()
|
||||||
|
{
|
||||||
|
if (dynamic_cast<UserNetListener*>(listener) != NULL)
|
||||||
|
delete listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - NetNotificationService
|
||||||
|
|
||||||
|
|
||||||
|
NetNotificationService::NetNotificationService()
|
||||||
|
{
|
||||||
|
recursive_lock_init(&fRecursiveLock, "net notifications");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NetNotificationService::~NetNotificationService()
|
||||||
|
{
|
||||||
|
recursive_lock_destroy(&fRecursiveLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*! \brief Notifies all registered listeners.
|
||||||
|
\param event The message defining the event
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
NetNotificationService::Notify(const KMessage& event)
|
||||||
|
{
|
||||||
|
uint32 flags = event.GetInt32("flags", 0);
|
||||||
|
if (flags == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RecursiveLocker _(fRecursiveLock);
|
||||||
|
|
||||||
|
ListenerList::Iterator iterator = fListeners.GetIterator();
|
||||||
|
while (net_listener* listener = iterator.Next()) {
|
||||||
|
if ((listener->flags & flags) != 0)
|
||||||
|
listener->listener->EventOccured(*this, &event);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator = fListeners.GetIterator();
|
||||||
|
while (net_listener* listener = iterator.Next()) {
|
||||||
|
if ((listener->flags & flags) != 0)
|
||||||
|
listener->listener->AllListenersNotified(*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NetNotificationService::AddListener(const KMessage* eventSpecifier,
|
||||||
|
NotificationListener& listener)
|
||||||
|
{
|
||||||
|
if (eventSpecifier == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
uint32 flags = eventSpecifier->GetInt32("flags", 0);
|
||||||
|
|
||||||
|
return _AddListener(flags, listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NetNotificationService::UpdateListener(const KMessage* eventSpecifier,
|
||||||
|
NotificationListener& notificationListener)
|
||||||
|
{
|
||||||
|
if (eventSpecifier == NULL)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
uint32 flags = eventSpecifier->GetInt32("flags", 0);
|
||||||
|
bool addFlags = eventSpecifier->GetBool("add flags", false);
|
||||||
|
|
||||||
|
RecursiveLocker _(fRecursiveLock);
|
||||||
|
|
||||||
|
ListenerList::Iterator iterator = fListeners.GetIterator();
|
||||||
|
while (net_listener* listener = iterator.Next()) {
|
||||||
|
if (*listener->listener == notificationListener) {
|
||||||
|
if (addFlags)
|
||||||
|
listener->flags |= flags;
|
||||||
|
else
|
||||||
|
listener->flags = flags;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NetNotificationService::RemoveListener(const KMessage* eventSpecifier,
|
||||||
|
NotificationListener& notificationListener)
|
||||||
|
{
|
||||||
|
RecursiveLocker _(fRecursiveLock);
|
||||||
|
|
||||||
|
ListenerList::Iterator iterator = fListeners.GetIterator();
|
||||||
|
while (net_listener* listener = iterator.Next()) {
|
||||||
|
if (listener->listener == ¬ificationListener) {
|
||||||
|
iterator.Remove();
|
||||||
|
delete listener;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline status_t
|
||||||
|
NetNotificationService::RemoveUserListeners(port_id port, uint32 token)
|
||||||
|
{
|
||||||
|
UserNetListener userListener(port, token);
|
||||||
|
|
||||||
|
RecursiveLocker _(fRecursiveLock);
|
||||||
|
|
||||||
|
ListenerList::Iterator iterator = fListeners.GetIterator();
|
||||||
|
while (net_listener* listener = iterator.Next()) {
|
||||||
|
if (*listener->listener == userListener) {
|
||||||
|
iterator.Remove();
|
||||||
|
delete listener;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NetNotificationService::UpdateUserListener(uint32 flags, port_id port,
|
||||||
|
uint32 token)
|
||||||
|
{
|
||||||
|
UserNetListener userListener(port, token);
|
||||||
|
|
||||||
|
RecursiveLocker _(fRecursiveLock);
|
||||||
|
|
||||||
|
ListenerList::Iterator iterator = fListeners.GetIterator();
|
||||||
|
while (net_listener* listener = iterator.Next()) {
|
||||||
|
if (*listener->listener == userListener) {
|
||||||
|
listener->flags |= flags;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserNetListener* copiedListener = new(std::nothrow) UserNetListener(
|
||||||
|
userListener);
|
||||||
|
if (copiedListener == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t status = _AddListener(flags, *copiedListener);
|
||||||
|
if (status != B_OK)
|
||||||
|
delete copiedListener;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
NetNotificationService::_AddListener(uint32 flags,
|
||||||
|
NotificationListener& notificationListener)
|
||||||
|
{
|
||||||
|
net_listener* listener = new(std::nothrow) net_listener;
|
||||||
|
if (listener == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
listener->flags = flags;
|
||||||
|
listener->listener = ¬ificationListener;
|
||||||
|
|
||||||
|
RecursiveLocker _(fRecursiveLock);
|
||||||
|
|
||||||
|
fListeners.Add(listener);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - User generic syscall
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
_user_start_watching_network(uint32 flags, port_id port, uint32 token)
|
||||||
|
{
|
||||||
|
return sNotificationService.UpdateUserListener(flags, port, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
_user_stop_watching_network(port_id port, uint32 token)
|
||||||
|
{
|
||||||
|
return sNotificationService.RemoveUserListeners(port, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - exported module API
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
send_notification(const KMessage* event)
|
||||||
|
{
|
||||||
|
sNotificationService.Notify(*event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static status_t
|
||||||
|
notifications_std_ops(int32 op, ...)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
case B_MODULE_INIT:
|
||||||
|
new(&sNotificationSender) UserMessagingMessageSender();
|
||||||
|
new(&sNotificationService) NetNotificationService();
|
||||||
|
return B_OK;
|
||||||
|
case B_MODULE_UNINIT:
|
||||||
|
sNotificationSender.~UserMessagingMessageSender();
|
||||||
|
sNotificationService.~NetNotificationService();
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
net_notifications_module_info sNotificationsModule = {
|
||||||
|
{
|
||||||
|
NET_NOTIFICATIONS_MODULE_NAME,
|
||||||
|
0,
|
||||||
|
notifications_std_ops
|
||||||
|
},
|
||||||
|
|
||||||
|
send_notification
|
||||||
|
};
|
||||||
|
|
||||||
|
module_info* modules[] = {
|
||||||
|
(module_info*)&sNotificationsModule,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
@@ -21,6 +21,7 @@ KernelAddon stack :
|
|||||||
interfaces.cpp
|
interfaces.cpp
|
||||||
net_buffer.cpp
|
net_buffer.cpp
|
||||||
net_socket.cpp
|
net_socket.cpp
|
||||||
|
notifications.cpp
|
||||||
link.cpp
|
link.cpp
|
||||||
radix.c
|
radix.c
|
||||||
routes.cpp
|
routes.cpp
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2008, Axel Dörfler, [email protected].
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! Provides the stack internal notification API.
|
||||||
|
|
||||||
|
The actual message sending happens in another module to make the
|
||||||
|
notification listeners independent from the stack status.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <net_notifications.h>
|
||||||
|
|
||||||
|
#include <util/KMessage.h>
|
||||||
|
|
||||||
|
#include "stack_private.h"
|
||||||
|
|
||||||
|
|
||||||
|
static net_notifications_module_info* sNotificationModule;
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
notify_interface_added(const char* interface)
|
||||||
|
{
|
||||||
|
if (sNotificationModule == NULL)
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
char messageBuffer[512];
|
||||||
|
KMessage message;
|
||||||
|
message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
|
||||||
|
message.AddInt32("opcode", B_NETWORK_INTERFACE_ADDED);
|
||||||
|
message.AddString("interface", interface);
|
||||||
|
|
||||||
|
return sNotificationModule->send_notification(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
notify_interface_removed(const char* interface)
|
||||||
|
{
|
||||||
|
if (sNotificationModule == NULL)
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
char messageBuffer[512];
|
||||||
|
KMessage message;
|
||||||
|
message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
|
||||||
|
message.AddInt32("opcode", B_NETWORK_INTERFACE_REMOVED);
|
||||||
|
message.AddString("interface", interface);
|
||||||
|
|
||||||
|
return sNotificationModule->send_notification(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
notify_interface_changed(const char* interface)
|
||||||
|
{
|
||||||
|
if (sNotificationModule == NULL)
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
char messageBuffer[512];
|
||||||
|
KMessage message;
|
||||||
|
message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
|
||||||
|
message.AddInt32("opcode", B_NETWORK_INTERFACE_CHANGED);
|
||||||
|
message.AddString("interface", interface);
|
||||||
|
|
||||||
|
return sNotificationModule->send_notification(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
notify_link_changed(const char* interface)
|
||||||
|
{
|
||||||
|
if (sNotificationModule == NULL)
|
||||||
|
return B_NOT_SUPPORTED;
|
||||||
|
|
||||||
|
char messageBuffer[512];
|
||||||
|
KMessage message;
|
||||||
|
message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
|
||||||
|
message.AddInt32("opcode", B_NETWORK_DEVICE_LINK_CHANGED);
|
||||||
|
message.AddString("interface", interface);
|
||||||
|
|
||||||
|
return sNotificationModule->send_notification(&message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
init_notifications()
|
||||||
|
{
|
||||||
|
return get_module(NET_NOTIFICATIONS_MODULE_NAME,
|
||||||
|
(module_info**)&sNotificationModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
uninit_notifications()
|
||||||
|
{
|
||||||
|
if (sNotificationModule != NULL)
|
||||||
|
put_module(NET_NOTIFICATIONS_MODULE_NAME);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -753,6 +753,14 @@ init_stack()
|
|||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
goto err2;
|
goto err2;
|
||||||
|
|
||||||
|
status = init_notifications();
|
||||||
|
if (status < B_OK) {
|
||||||
|
// If this fails, it just means there won't be any notifications,
|
||||||
|
// it's not a fatal error.
|
||||||
|
dprintf("networking stack notifications could not be initialized: %s\n",
|
||||||
|
strerror(status));
|
||||||
|
}
|
||||||
|
|
||||||
mutex_init(&sChainLock, "net chains");
|
mutex_init(&sChainLock, "net chains");
|
||||||
mutex_init(&sInitializeChainLock, "net intialize chains");
|
mutex_init(&sInitializeChainLock, "net intialize chains");
|
||||||
|
|
||||||
@@ -827,6 +835,7 @@ uninit_stack()
|
|||||||
uninit_timers();
|
uninit_timers();
|
||||||
uninit_interfaces();
|
uninit_interfaces();
|
||||||
uninit_domains();
|
uninit_domains();
|
||||||
|
uninit_notifications();
|
||||||
|
|
||||||
mutex_destroy(&sChainLock);
|
mutex_destroy(&sChainLock);
|
||||||
mutex_destroy(&sInitializeChainLock);
|
mutex_destroy(&sInitializeChainLock);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2006-2007, Haiku, Inc. All Rights Reserved.
|
* Copyright 2006-2008, Haiku, Inc. All Rights Reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
@@ -33,6 +33,14 @@ status_t put_domain_protocols(net_socket *socket);
|
|||||||
status_t get_domain_datalink_protocols(net_interface *interface);
|
status_t get_domain_datalink_protocols(net_interface *interface);
|
||||||
status_t put_domain_datalink_protocols(net_interface *interface);
|
status_t put_domain_datalink_protocols(net_interface *interface);
|
||||||
|
|
||||||
|
// notifications.cpp
|
||||||
|
status_t notify_interface_added(const char* interface);
|
||||||
|
status_t notify_interface_removed(const char* interface);
|
||||||
|
status_t notify_interface_changed(const char* interface);
|
||||||
|
status_t notify_link_changed(const char* interface);
|
||||||
|
status_t init_notifications();
|
||||||
|
void uninit_notifications();
|
||||||
|
|
||||||
status_t init_stack();
|
status_t init_stack();
|
||||||
status_t uninit_stack();
|
status_t uninit_stack();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user