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); +}