1/*
2 * Copyright 2008-2013, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6/*! Provides the networking stack notification service. */
7
8#include <net_notifications.h>
9
10#include <kernel.h>
11#include <generic_syscall.h>
12#include <Notifications.h>
13#include <util/KMessage.h>
14
15//#define TRACE_NOTIFICATIONS
16#ifdef TRACE_NOTIFICATIONS
17#	define TRACE(x...) dprintf("\33[32mnet_notifications:\33[0m " x)
18#else
19#	define TRACE(x...) ;
20#endif
21
22
23class NetNotificationService : public DefaultUserNotificationService {
24public:
25								NetNotificationService();
26	virtual						~NetNotificationService();
27
28			void				Notify(const KMessage& event);
29
30protected:
31	virtual	void				LastReferenceReleased();
32	virtual	void				FirstAdded();
33	virtual	void				LastRemoved();
34};
35
36
37static NetNotificationService sNotificationService;
38
39
40//	#pragma mark - NetNotificationService
41
42
43NetNotificationService::NetNotificationService()
44	:
45	DefaultUserNotificationService("network")
46{
47}
48
49
50NetNotificationService::~NetNotificationService()
51{
52}
53
54
55void
56NetNotificationService::Notify(const KMessage& event)
57{
58	uint32 opcode = event.GetInt32("opcode", 0);
59	if (opcode == 0)
60		return;
61
62	TRACE("notify for %lx\n", opcode);
63
64	DefaultUserNotificationService::Notify(event, opcode);
65}
66
67
68void
69NetNotificationService::LastReferenceReleased()
70{
71	// don't delete us here
72}
73
74
75void
76NetNotificationService::FirstAdded()
77{
78	// The reference counting doesn't work for us, as we'll have to
79	// ensure our module stays loaded.
80	module_info* dummy;
81	get_module(NET_NOTIFICATIONS_MODULE_NAME, &dummy);
82}
83
84
85void
86NetNotificationService::LastRemoved()
87{
88	// Give up the reference _AddListener()
89	put_module(NET_NOTIFICATIONS_MODULE_NAME);
90}
91
92
93//	#pragma mark - User generic syscall
94
95
96static status_t
97net_notifications_control(const char *subsystem, uint32 function, void *buffer,
98	size_t bufferSize)
99{
100	struct net_notifications_control control;
101	if (bufferSize != sizeof(struct net_notifications_control)
102		|| function != NET_NOTIFICATIONS_CONTROL_WATCHING)
103		return B_BAD_VALUE;
104	if (!IS_USER_ADDRESS(buffer) || user_memcpy(&control, buffer,
105			sizeof(struct net_notifications_control)) < B_OK)
106		return B_BAD_ADDRESS;
107
108	if (control.flags != 0) {
109		return sNotificationService.UpdateUserListener(control.flags,
110			control.port, control.token);
111	}
112
113	return sNotificationService.RemoveUserListeners(control.port,
114		control.token);
115}
116
117
118//	#pragma mark - exported module API
119
120
121static status_t
122send_notification(const KMessage* event)
123{
124	sNotificationService.Notify(*event);
125	return B_OK;
126}
127
128
129static status_t
130notifications_std_ops(int32 op, ...)
131{
132	switch (op) {
133		case B_MODULE_INIT:
134		{
135			TRACE("init\n");
136
137			new(&sNotificationService) NetNotificationService();
138			status_t result = sNotificationService.Register();
139			if (result != B_OK)
140				return result;
141
142			register_generic_syscall(NET_NOTIFICATIONS_SYSCALLS,
143				net_notifications_control, 1, 0);
144			return B_OK;
145		}
146		case B_MODULE_UNINIT:
147			TRACE("uninit\n");
148
149			unregister_generic_syscall(NET_NOTIFICATIONS_SYSCALLS, 1);
150
151			// TODO: due to the way the locking in the notification
152			// manager works, there's a potential race condition here
153			// where someone attempts to add a listener right as
154			// we're uninitializing. Needs to be looked at/resolved.
155			sNotificationService.Unregister();
156
157			// we need to release the reference that was acquired
158			// on our behalf by the NotificationManager.
159			sNotificationService.ReleaseReference();
160			sNotificationService.~NetNotificationService();
161			return B_OK;
162
163		default:
164			return B_ERROR;
165	}
166}
167
168
169net_notifications_module_info sNotificationsModule = {
170	{
171		NET_NOTIFICATIONS_MODULE_NAME,
172		0,
173		notifications_std_ops
174	},
175
176	send_notification
177};
178
179module_info* modules[] = {
180	(module_info*)&sNotificationsModule,
181	NULL
182};
183