diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
index 5b005c4da9..0d4cddd507 100644
--- a/build/jam/HaikuImage
+++ b/build/jam/HaikuImage
@@ -138,12 +138,12 @@ BEOS_ADD_ONS_DRIVERS_GRAPHICS = $(X86_ONLY)radeon $(X86_ONLY)nvidia
$(X86_ONLY)s3 $(X86_ONLY)vesa #$(X86_ONLY)via #$(X86_ONLY)vmware
;
BEOS_ADD_ONS_DRIVERS_MIDI = emuxki ;
-BEOS_ADD_ONS_DRIVERS_NET = $(X86_ONLY)3com $(X86_ONLY)broadcom440x
+BEOS_ADD_ONS_DRIVERS_NET = $(X86_ONLY)3com $(X86_ONLY)broadcom440x
$(X86_ONLY)broadcom570x etherpci $(X86_ONLY)ipro1000
pegasus $(X86_ONLY)rtl8139 rtl8169 $(X86_ONLY)rtl81xx sis900
$(X86_ONLY)via_rhine wb840 $(X86_ONLY)ipro100 $(X86_ONLY)nforce
#vlance
- $(X86_ONLY)marvell_yukon $(X86_ONLY)syskonnect
+ $(X86_ONLY)marvell_yukon $(X86_ONLY)syskonnect
$(X86_ONLY)attansic_l2 $(X86_ONLY)ar81xx usb_ecm
;
#BEOS_ADD_ONS_DRIVERS_ACPI = $(X86_ONLY)acpi_button ;
@@ -420,7 +420,8 @@ AddSymlinkToHaikuImage beos system add-ons Tracker
AddFilesToHaikuImage beos system add-ons input_server devices
: keyboard mouse wacom ;
AddFilesToHaikuImage beos system add-ons input_server filters : screen_saver ;
-AddFilesToHaikuImage beos system add-ons kernel network : stack ;
+AddFilesToHaikuImage beos system add-ons kernel network
+ : notifications stack ;
AddFilesToHaikuImage beos system add-ons kernel network devices
: $(BEOS_NETWORK_DEVICES) ;
AddFilesToHaikuImage beos system add-ons kernel network datalink_protocols
diff --git a/headers/private/net/net_notifications.h b/headers/private/net/net_notifications.h
index 291c2f1d4d..5ab4af0863 100644
--- a/headers/private/net/net_notifications.h
+++ b/headers/private/net/net_notifications.h
@@ -24,8 +24,7 @@ struct net_notifications_module_info {
// generic syscall interface
#define NET_NOTIFICATIONS_SYSCALLS "network/notifications"
-#define NET_NOTIFICATIONS_START_WATCHING 1
-#define NET_NOTIFICATIONS_STOP_WATCHING 2
+#define NET_NOTIFICATIONS_CONTROL_WATCHING 1
struct net_notifications_control {
uint32 flags;
@@ -36,15 +35,15 @@ struct net_notifications_control {
// 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
+#define B_NETWORK_INTERFACE_ADDED 0x01
+#define B_NETWORK_INTERFACE_REMOVED 0x02
+#define B_NETWORK_INTERFACE_CHANGED 0x03
+#define B_NETWORK_DEVICE_LINK_CHANGED 0x10
// TODO: add routes, stack unloaded/loaded, ... events
enum {
- B_WATCH_NETWORK_INTERFACE_CHANGES = 0x0001,
- B_WATCH_NETWORK_LINK_CHANGES = 0x0002
+ B_WATCH_NETWORK_INTERFACE_CHANGES = 0x000f,
+ B_WATCH_NETWORK_LINK_CHANGES = 0x00f0
};
#define B_NETWORK_MONITOR '_NTN'
diff --git a/src/add-ons/kernel/network/notifications/notifications.cpp b/src/add-ons/kernel/network/notifications/notifications.cpp
index c6d5ea3151..63651889b8 100644
--- a/src/add-ons/kernel/network/notifications/notifications.cpp
+++ b/src/add-ons/kernel/network/notifications/notifications.cpp
@@ -7,12 +7,18 @@
#include
-//#include
+#include
#include
#include
+//#define TRACE_NOTIFICATIONS
+#ifdef TRACE_NOTIFICATIONS
+# define TRACE(x...) dprintf("\33[32mnet_notifications:\33[0m " x)
+#else
+# define TRACE(x...) ;
+#endif
-// TODO: add generic syscall interface
+// TODO: add possibility to remove teams/ports that are gone
static UserMessagingMessageSender sNotificationSender;
@@ -75,8 +81,11 @@ static NetNotificationService sNotificationService;
net_listener::~net_listener()
{
- if (dynamic_cast(listener) != NULL)
+ // Only delete the listener if it's one of ours
+ if (dynamic_cast(listener) != NULL) {
+ TRACE("delete user listener %p\n", listener);
delete listener;
+ }
}
@@ -101,21 +110,25 @@ NetNotificationService::~NetNotificationService()
void
NetNotificationService::Notify(const KMessage& event)
{
- uint32 flags = event.GetInt32("flags", 0);
- if (flags == 0)
+ uint32 opcode = event.GetInt32("opcode", 0);
+ if (opcode == 0)
return;
+ TRACE("notify for %lx\n", opcode);
+
RecursiveLocker _(fRecursiveLock);
ListenerList::Iterator iterator = fListeners.GetIterator();
while (net_listener* listener = iterator.Next()) {
- if ((listener->flags & flags) != 0)
+ if ((listener->flags & opcode) != 0) {
+ TRACE(" notify listener %p for %lx\n", listener, opcode);
listener->listener->EventOccured(*this, &event);
+ }
}
iterator = fListeners.GetIterator();
while (net_listener* listener = iterator.Next()) {
- if ((listener->flags & flags) != 0)
+ if ((listener->flags & opcode) != 0)
listener->listener->AllListenersNotified(*this);
}
}
@@ -170,8 +183,14 @@ NetNotificationService::RemoveListener(const KMessage* eventSpecifier,
ListenerList::Iterator iterator = fListeners.GetIterator();
while (net_listener* listener = iterator.Next()) {
if (listener->listener == ¬ificationListener) {
+ TRACE("remove listener %p\n", listener);
iterator.Remove();
delete listener;
+
+ if (fListeners.IsEmpty()) {
+ // Give up the reference _AddListener()
+ put_module(NET_NOTIFICATIONS_MODULE_NAME);
+ }
return B_OK;
}
}
@@ -180,7 +199,7 @@ NetNotificationService::RemoveListener(const KMessage* eventSpecifier,
}
-inline status_t
+status_t
NetNotificationService::RemoveUserListeners(port_id port, uint32 token)
{
UserNetListener userListener(port, token);
@@ -190,8 +209,14 @@ NetNotificationService::RemoveUserListeners(port_id port, uint32 token)
ListenerList::Iterator iterator = fListeners.GetIterator();
while (net_listener* listener = iterator.Next()) {
if (*listener->listener == userListener) {
+ TRACE("remove user listener %p\n", listener);
iterator.Remove();
delete listener;
+
+ if (fListeners.IsEmpty()) {
+ // Give up the reference _AddListener()
+ put_module(NET_NOTIFICATIONS_MODULE_NAME);
+ }
return B_OK;
}
}
@@ -237,11 +262,22 @@ NetNotificationService::_AddListener(uint32 flags,
if (listener == NULL)
return B_NO_MEMORY;
+ TRACE("add %slistener %p for %lx\n",
+ dynamic_cast(¬ificationListener) != NULL
+ ? "user " : "", listener, flags);
+
listener->flags = flags;
listener->listener = ¬ificationListener;
RecursiveLocker _(fRecursiveLock);
+ if (fListeners.IsEmpty()) {
+ // The reference counting doesn't work for us, as we'll have to
+ // ensure our module stays loaded.
+ module_info* dummy;
+ get_module(NET_NOTIFICATIONS_MODULE_NAME, &dummy);
+ }
+
fListeners.Add(listener);
return B_OK;
}
@@ -250,27 +286,36 @@ NetNotificationService::_AddListener(uint32 flags,
// #pragma mark - User generic syscall
-status_t
-_user_start_watching_network(uint32 flags, port_id port, uint32 token)
+static status_t
+net_notifications_control(const char *subsystem, uint32 function, void *buffer,
+ size_t bufferSize)
{
- return sNotificationService.UpdateUserListener(flags, port, token);
-}
+ struct net_notifications_control control;
+ if (bufferSize != sizeof(struct net_notifications_control)
+ || function != NET_NOTIFICATIONS_CONTROL_WATCHING)
+ return B_BAD_VALUE;
+ if (user_memcpy(&control, buffer,
+ sizeof(struct net_notifications_control)) < B_OK)
+ return B_BAD_ADDRESS;
+ if (control.flags != 0) {
+ return sNotificationService.UpdateUserListener(control.flags,
+ control.port, control.token);
+ }
-status_t
-_user_stop_watching_network(port_id port, uint32 token)
-{
- return sNotificationService.RemoveUserListeners(port, token);
+ return sNotificationService.RemoveUserListeners(control.port,
+ control.token);
}
// #pragma mark - exported module API
-static void
+static status_t
send_notification(const KMessage* event)
{
sNotificationService.Notify(*event);
+ return B_OK;
}
@@ -279,10 +324,20 @@ notifications_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
+ TRACE("init\n");
+
new(&sNotificationSender) UserMessagingMessageSender();
new(&sNotificationService) NetNotificationService();
+
+ register_generic_syscall(NET_NOTIFICATIONS_SYSCALLS,
+ net_notifications_control, 1, 0);
return B_OK;
+
case B_MODULE_UNINIT:
+ TRACE("uninit\n");
+
+ unregister_generic_syscall(NET_NOTIFICATIONS_SYSCALLS, 1);
+
sNotificationSender.~UserMessagingMessageSender();
sNotificationService.~NetNotificationService();
return B_OK;
diff --git a/src/add-ons/kernel/network/stack/datalink.cpp b/src/add-ons/kernel/network/stack/datalink.cpp
index 68bff84c65..4e3f4738a9 100644
--- a/src/add-ons/kernel/network/stack/datalink.cpp
+++ b/src/add-ons/kernel/network/stack/datalink.cpp
@@ -518,7 +518,8 @@ datalink_std_ops(int32 op, ...)
status_t
-interface_protocol_init(struct net_interface *_interface, net_datalink_protocol **_protocol)
+interface_protocol_init(struct net_interface *_interface,
+ net_datalink_protocol **_protocol)
{
net_interface_private *interface = (net_interface_private *)_interface;
@@ -547,7 +548,8 @@ interface_protocol_send_data(net_datalink_protocol *_protocol,
net_buffer *buffer)
{
interface_protocol *protocol = (interface_protocol *)_protocol;
- net_interface_private *interface = (net_interface_private *)protocol->interface;
+ net_interface_private *interface
+ = (net_interface_private *)protocol->interface;
// TODO: Need to think about this locking. We can't obtain the
// RX Lock here (nor would it make sense) as the ARP
diff --git a/src/add-ons/kernel/network/stack/domains.cpp b/src/add-ons/kernel/network/stack/domains.cpp
index 9be49abfda..460e046726 100644
--- a/src/add-ons/kernel/network/stack/domains.cpp
+++ b/src/add-ons/kernel/network/stack/domains.cpp
@@ -186,8 +186,10 @@ add_interface_to_domain(net_domain *_domain,
put_device_interface(deviceInterface);
- if (status == B_OK)
+ if (status == B_OK) {
list_add_item(&domain->interfaces, interface);
+ notify_interface_added(interface);
+ }
return status;
}
@@ -203,6 +205,7 @@ remove_interface_from_domain(net_interface *interface)
net_domain_private *domain = (net_domain_private *)interface->domain;
list_remove_item(&domain->interfaces, interface);
+ notify_interface_removed(interface);
delete_interface((net_interface_private *)interface);
return B_OK;
}
diff --git a/src/add-ons/kernel/network/stack/interfaces.cpp b/src/add-ons/kernel/network/stack/interfaces.cpp
index bf46eb918b..359f300082 100644
--- a/src/add-ons/kernel/network/stack/interfaces.cpp
+++ b/src/add-ons/kernel/network/stack/interfaces.cpp
@@ -764,6 +764,7 @@ unregister_device_monitor(net_device *device, net_device_monitor *monitor)
status_t
device_link_changed(net_device *device)
{
+ notify_link_changed(device);
return B_OK;
}
diff --git a/src/add-ons/kernel/network/stack/notifications.cpp b/src/add-ons/kernel/network/stack/notifications.cpp
index 7b00da7869..0c2c05429d 100644
--- a/src/add-ons/kernel/network/stack/notifications.cpp
+++ b/src/add-ons/kernel/network/stack/notifications.cpp
@@ -9,6 +9,7 @@
notification listeners independent from the stack status.
*/
+#include
#include
#include
@@ -20,7 +21,7 @@ static net_notifications_module_info* sNotificationModule;
status_t
-notify_interface_added(const char* interface)
+notify_interface_added(net_interface* interface)
{
if (sNotificationModule == NULL)
return B_NOT_SUPPORTED;
@@ -29,14 +30,14 @@ notify_interface_added(const char* interface)
KMessage message;
message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
message.AddInt32("opcode", B_NETWORK_INTERFACE_ADDED);
- message.AddString("interface", interface);
+ message.AddString("interface", interface->name);
return sNotificationModule->send_notification(&message);
}
status_t
-notify_interface_removed(const char* interface)
+notify_interface_removed(net_interface* interface)
{
if (sNotificationModule == NULL)
return B_NOT_SUPPORTED;
@@ -45,14 +46,14 @@ notify_interface_removed(const char* interface)
KMessage message;
message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
message.AddInt32("opcode", B_NETWORK_INTERFACE_REMOVED);
- message.AddString("interface", interface);
+ message.AddString("interface", interface->name);
return sNotificationModule->send_notification(&message);
}
status_t
-notify_interface_changed(const char* interface)
+notify_interface_changed(net_interface* interface)
{
if (sNotificationModule == NULL)
return B_NOT_SUPPORTED;
@@ -61,14 +62,14 @@ notify_interface_changed(const char* interface)
KMessage message;
message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
message.AddInt32("opcode", B_NETWORK_INTERFACE_CHANGED);
- message.AddString("interface", interface);
+ message.AddString("interface", interface->name);
return sNotificationModule->send_notification(&message);
}
status_t
-notify_link_changed(const char* interface)
+notify_link_changed(net_device* device)
{
if (sNotificationModule == NULL)
return B_NOT_SUPPORTED;
@@ -77,7 +78,10 @@ notify_link_changed(const char* interface)
KMessage message;
message.SetTo(messageBuffer, sizeof(messageBuffer), B_NETWORK_MONITOR);
message.AddInt32("opcode", B_NETWORK_DEVICE_LINK_CHANGED);
- message.AddString("interface", interface);
+ message.AddString("device", device->name);
+ message.AddInt32("media", device->media);
+ message.AddInt64("link speed", device->link_speed);
+ message.AddInt32("link quality", device->link_quality);
return sNotificationModule->send_notification(&message);
}
diff --git a/src/add-ons/kernel/network/stack/stack_private.h b/src/add-ons/kernel/network/stack/stack_private.h
index 7d85bfdb2c..d659448683 100644
--- a/src/add-ons/kernel/network/stack/stack_private.h
+++ b/src/add-ons/kernel/network/stack/stack_private.h
@@ -34,10 +34,10 @@ status_t get_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 notify_interface_added(net_interface* interface);
+status_t notify_interface_removed(net_interface* interface);
+status_t notify_interface_changed(net_interface* interface);
+status_t notify_link_changed(net_device* device);
status_t init_notifications();
void uninit_notifications();
diff --git a/src/kits/network/Jamfile b/src/kits/network/Jamfile
index 86fe4e355e..4f039aff2e 100644
--- a/src/kits/network/Jamfile
+++ b/src/kits/network/Jamfile
@@ -1,14 +1,16 @@
SubDir HAIKU_TOP src kits network ;
-UsePrivateHeaders libroot net shared ;
+UsePrivateHeaders app libroot net shared ;
UsePrivateSystemHeaders ;
SharedLibrary libnetwork.so :
init.cpp
interfaces.cpp
+ notifications.cpp
socket.cpp
r5_compatibility.cpp
:
+ be
dns_dst.o
dns_inet.o
dns_irs.o
diff --git a/src/kits/network/notifications.cpp b/src/kits/network/notifications.cpp
new file mode 100644
index 0000000000..21aec19732
--- /dev/null
+++ b/src/kits/network/notifications.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2008, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+/*! The notifications API uses the generic syscall interface of the
+ network's stack notification module.
+*/
+
+#include
+
+#include
+#include
+#include
+
+
+static status_t
+check_for_notifications_syscall(void)
+{
+ uint32 version = 0;
+ return _kern_generic_syscall(NET_NOTIFICATIONS_SYSCALLS, B_SYSCALL_INFO,
+ &version, sizeof(version));
+}
+
+
+// #pragma mark -
+
+
+status_t
+start_watching_network(uint32 flags, const BMessenger& target)
+{
+ if (check_for_notifications_syscall() != B_OK)
+ return B_NOT_SUPPORTED;
+
+ BMessenger::Private targetPrivate(const_cast(target));
+ net_notifications_control control;
+ control.flags = flags;
+ control.port = targetPrivate.Port();
+ control.token = targetPrivate.Token();
+
+ return _kern_generic_syscall(NET_NOTIFICATIONS_SYSCALLS,
+ NET_NOTIFICATIONS_CONTROL_WATCHING, &control,
+ sizeof(net_notifications_control));
+}
+
+
+status_t
+start_watching_network(uint32 flags, const BHandler* handler,
+ const BLooper* looper)
+{
+ const BMessenger target(handler, looper);
+ return start_watching_network(flags, target);
+}
+
+status_t
+stop_watching_network(const BMessenger& target)
+{
+ return start_watching_network(0, target);
+ // start_watching_network() without flags just stops everything
+}
+
+
+status_t
+stop_watching_network(const BHandler* handler, const BLooper* looper)
+{
+ const BMessenger target(handler, looper);
+ return stop_watching_network(target);
+}