1 /*
2 * Copyright (c) 2004
3 *	Hartmut Brandt
4 *	All rights reserved.
5 *
6 * Author: Harti Brandt <[email protected]>
7 *
8 * Redistribution of this software and documentation and use in source and
9 * binary forms, with or without modification, are permitted provided that
10 * the following conditions are met:
11 *
12 * 1. Redistributions of source code or documentation must retain the above
13 *    copyright notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
19 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
22 * THE AUTHOR OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $Begemot: libunimsg/netnatm/api/cc_sig.c,v 1.1 2004/07/08 08:21:54 brandt Exp $
31 *
32 * ATM API as defined per af-saa-0108
33 *
34 * Generic signal handling
35 */
36 #include <netnatm/unimsg.h>
37 #include <netnatm/msg/unistruct.h>
38 #include <netnatm/msg/unimsglib.h>
39 #include <netnatm/api/unisap.h>
40 #include <netnatm/sig/unidef.h>
41 #include <netnatm/api/atmapi.h>
42 #include <netnatm/api/ccatm.h>
43 #include <netnatm/api/ccpriv.h>
44 
45 enum {
46 	SIG_USER,
47 	SIG_CONN,
48 };
49 
50 struct ccsig {
51 	u_char	type;		/* type of target */
52 	u_char	has_msg;	/* arg1 is a message */
53 	void	*target;	/* target instance */
54 	u_int	sig;		/* signal */
55 	void	*arg1;		/* argument */
56 	u_int	arg2;		/* argument */
57 	TAILQ_ENTRY(ccsig) link;
58 };
59 
60 #if defined(__GNUC__) && __GNUC__ < 3
61 #define	cc_sig_log(CC, FMT, ARGS...) do {				\
62 	if ((CC)->log & CCLOG_SIGS)					\
63 		(CC)->funcs->log("%s: " FMT, __FUNCTION__ , ## ARGS);	\
64     } while (0)
65 #else
66 #define	cc_sig_log(CC, FMT, ...) do {					\
67 	if ((CC)->log & CCLOG_SIGS)					\
68 		(CC)->funcs->log("%s: " FMT, __func__, __VA_ARGS__);	\
69     } while (0)
70 #endif
71 
72 
73 const char *const cc_user_sigtab[] = {
74 #define	DEF(N) [USER_SIG_##N] = #N,
75 USER_SIGS
76 #undef DEF
77 };
78 
79 const char *const cc_conn_sigtab[] = {
80 #define	DEF(N) [CONN_SIG_##N] = #N,
81 CONN_SIGS
82 #undef DEF
83 };
84 
85 
86 /*
87  * Allocate and populate a signal
88  */
89 static /* __inline */ struct ccsig *
sig_alloc(struct ccdata * cc,u_int type,void * target,u_int has_msg,u_int sig,void * arg1,u_int arg2)90 sig_alloc(struct ccdata *cc, u_int type, void *target, u_int has_msg,
91     u_int sig, void *arg1, u_int arg2)
92 {
93 	struct ccsig *s;
94 
95 	if ((s = TAILQ_FIRST(&cc->free_sigs)) == NULL) {
96 		s = CCZALLOC(sizeof(struct ccsig));
97 		if (s == NULL) {
98 			cc_log(cc, "signal %u/%u lost - ENOMEM", type, sig);
99 			return (NULL);
100 		}
101 	} else
102 		TAILQ_REMOVE(&cc->free_sigs, s, link);
103 
104 	s->type = type;
105 	s->has_msg = has_msg;
106 	s->target = target;
107 	s->sig = sig;
108 	s->arg1 = arg1;
109 	s->arg2 = arg2;
110 
111 	return (s);
112 }
113 
114 /*
115  * Queue a signal to this user
116  */
117 int
cc_user_sig(struct ccuser * user,enum user_sig sig,void * arg1,u_int arg2)118 cc_user_sig(struct ccuser *user, enum user_sig sig, void *arg1, u_int arg2)
119 {
120 	struct ccsig *s;
121 
122 	s = sig_alloc(user->cc, SIG_USER, user, 0, sig, arg1, arg2);
123 	if (s == NULL)
124 		return (ENOMEM);
125 	TAILQ_INSERT_TAIL(&user->cc->sigs, s, link);
126 	cc_sig_log(user->cc, "queuing sig %s to user %p", cc_user_sigtab[sig],
127 	    user);
128 	return (0);
129 }
130 
131 /* Queue a signal with message to this user */
132 int
cc_user_sig_msg(struct ccuser * user,enum user_sig sig,struct uni_msg * msg)133 cc_user_sig_msg(struct ccuser *user, enum user_sig sig, struct uni_msg *msg)
134 {
135 	struct ccsig *s;
136 
137 	s = sig_alloc(user->cc, SIG_USER, user, msg != NULL, sig, msg, 0);
138 	if (s == NULL)
139 		return (ENOMEM);
140 	TAILQ_INSERT_TAIL(&user->cc->sigs, s, link);
141 	cc_sig_log(user->cc, "queuing sig %s to user %p", cc_user_sigtab[sig],
142 	    user);
143 	return (0);
144 }
145 
146 /*
147  * Signal to connection
148  */
149 static int
sig_conn(struct ccconn * conn,enum conn_sig sig,u_int has_msg,void * arg)150 sig_conn(struct ccconn *conn, enum conn_sig sig, u_int has_msg, void *arg)
151 {
152 	struct ccsig *s;
153 	const struct ccreq *r = NULL;
154 
155 	s = sig_alloc(conn->cc, SIG_CONN, conn, has_msg, sig, arg, 0);
156 	if (s == NULL)
157 		return (ENOMEM);
158 
159 	if (conn->port != NULL) {
160 		/* argh */
161 		TAILQ_FOREACH(r, &conn->port->cookies, link)
162 			if (r->conn == conn)
163 				break;
164 	}
165 	if (r == NULL) {
166 		TAILQ_INSERT_TAIL(&conn->cc->sigs, s, link);
167 		cc_sig_log(conn->cc, "queuing sig %s to conn %p",
168 		    cc_conn_sigtab[sig], conn);
169 	} else {
170 		TAILQ_INSERT_TAIL(&conn->cc->def_sigs, s, link);
171 		cc_sig_log(conn->cc, "queuing defered sig %s to conn %p",
172 		    cc_conn_sigtab[sig], conn);
173 	}
174 	return (0);
175 }
176 
177 /*
178  * Queue a signal to a connection.
179  */
180 int
cc_conn_sig(struct ccconn * conn,enum conn_sig sig,void * arg1)181 cc_conn_sig(struct ccconn *conn, enum conn_sig sig, void *arg1)
182 {
183 
184 	return (sig_conn(conn, sig, 0, arg1));
185 }
186 
187 /*
188  * signal with message to connection
189  */
190 int
cc_conn_sig_msg(struct ccconn * conn,enum conn_sig sig,struct uni_msg * msg)191 cc_conn_sig_msg(struct ccconn *conn, enum conn_sig sig, struct uni_msg *msg)
192 {
193 
194 	return (sig_conn(conn, sig, (msg != NULL), msg));
195 }
196 int
cc_conn_sig_msg_nodef(struct ccconn * conn,enum conn_sig sig,struct uni_msg * msg)197 cc_conn_sig_msg_nodef(struct ccconn *conn, enum conn_sig sig,
198     struct uni_msg *msg)
199 {
200 	struct ccsig *s;
201 
202 	s = sig_alloc(conn->cc, SIG_CONN, conn, (msg != NULL), sig, msg, 0);
203 	if (s == NULL)
204 		return (ENOMEM);
205 
206 	TAILQ_INSERT_TAIL(&conn->cc->sigs, s, link);
207 	cc_sig_log(conn->cc, "queuing sig %s to conn %p",
208 	    cc_conn_sigtab[sig], conn);
209 
210 	return (0);
211 }
212 
213 /*
214  * Queue a response signal to a connection.
215  */
216 int
cc_conn_resp(struct ccconn * conn,enum conn_sig sig,u_int cookie __unused,u_int reason,u_int state)217 cc_conn_resp(struct ccconn *conn, enum conn_sig sig, u_int cookie __unused,
218     u_int reason, u_int state)
219 {
220 	struct ccsig *s, *s1, *s2;
221 
222 	s = sig_alloc(conn->cc, SIG_CONN, conn, 0, sig, NULL,
223 	     ((reason & 0xffff) << 16) | (state & 0xffff));
224 	if (s == NULL)
225 		return (ENOMEM);
226 
227 	TAILQ_INSERT_TAIL(&conn->cc->sigs, s, link);
228 
229 	cc_sig_log(conn->cc, "queuing response %s to conn %p",
230 	    cc_conn_sigtab[sig], conn);
231 
232 	s1 = TAILQ_FIRST(&conn->cc->def_sigs);
233 	while (s1 != NULL) {
234 		s2 = TAILQ_NEXT(s1, link);
235 		if (s1->type == SIG_CONN && s1->target == conn) {
236 			TAILQ_REMOVE(&conn->cc->def_sigs, s1, link);
237 			TAILQ_INSERT_AFTER(&conn->cc->sigs, s, s1, link);
238 			cc_sig_log(conn->cc, "undefering sig %s to conn %p",
239 			    cc_conn_sigtab[s1->sig], conn);
240 			s = s1;
241 		}
242 		s1 = s2;
243 	}
244 
245 	return (0);
246 }
247 
248 /*
249  * Flush all signals to a given target from both queues
250  */
251 static /* __inline */ void
sig_flush(struct ccdata * cc,u_int type,void * target)252 sig_flush(struct ccdata *cc, u_int type, void *target)
253 {
254 	struct ccsig *s, *s1;
255 
256 	s = TAILQ_FIRST(&cc->sigs);
257 	while (s != NULL) {
258 		s1 = TAILQ_NEXT(s, link);
259 		if (s->type == type && s->target == target) {
260 			if (s->has_msg)
261 				uni_msg_destroy((struct uni_msg *)s->arg1);
262 			TAILQ_REMOVE(&cc->sigs, s, link);
263 			TAILQ_INSERT_HEAD(&cc->free_sigs, s, link);
264 		}
265 		s = s1;
266 	}
267 
268 	s = TAILQ_FIRST(&cc->def_sigs);
269 	while (s != NULL) {
270 		s1 = TAILQ_NEXT(s, link);
271 		if (s->type == type && s->target == target) {
272 			if (s->has_msg)
273 				uni_msg_destroy((struct uni_msg *)s->arg1);
274 			TAILQ_REMOVE(&cc->def_sigs, s, link);
275 			TAILQ_INSERT_HEAD(&cc->free_sigs, s, link);
276 		}
277 		s = s1;
278 	}
279 }
280 
281 /*
282  * Flush all signals to this user
283  */
284 void
cc_user_sig_flush(struct ccuser * user)285 cc_user_sig_flush(struct ccuser *user)
286 {
287 
288 	cc_sig_log(user->cc, "flushing signals to user %p", user);
289 	sig_flush(user->cc, SIG_USER, user);
290 }
291 
292 /*
293  * Flush all signals to this connection
294  */
295 void
cc_conn_sig_flush(struct ccconn * conn)296 cc_conn_sig_flush(struct ccconn *conn)
297 {
298 
299 	cc_sig_log(conn->cc, "flushing signals to conn %p", conn);
300 	sig_flush(conn->cc, SIG_CONN, conn);
301 }
302 
303 /*
304  * Do the work
305  */
306 void
cc_work(struct ccdata * cc)307 cc_work(struct ccdata *cc)
308 {
309 	struct ccsig *s;
310 
311 	cc_sig_log(cc, "start %s", "work");
312 	while ((s = TAILQ_FIRST(&cc->sigs)) != NULL) {
313 		TAILQ_REMOVE(&cc->sigs, s, link);
314 		if (s->type == SIG_USER)
315 			cc_user_sig_handle(s->target, s->sig, s->arg1, s->arg2);
316 		else {
317 			cc_conn_sig_handle(s->target, s->sig, s->arg1, s->arg2);
318 			if (s->has_msg)
319 				uni_msg_destroy(s->arg1);
320 		}
321 		TAILQ_INSERT_HEAD(&cc->free_sigs, s, link);
322 	}
323 	cc_sig_log(cc, "end %s", "work");
324 }
325 
326 /*
327  * flush all signals
328  */
329 void
cc_sig_flush_all(struct ccdata * cc)330 cc_sig_flush_all(struct ccdata *cc)
331 {
332 	struct ccsig *s;
333 
334 	while ((s = TAILQ_FIRST(&cc->sigs)) != NULL) {
335 		if (s->has_msg)
336 			uni_msg_destroy((struct uni_msg *)s->arg1);
337 		TAILQ_REMOVE(&cc->sigs, s, link);
338 		CCFREE(s);
339 	}
340 	while ((s = TAILQ_FIRST(&cc->def_sigs)) != NULL) {
341 		if (s->has_msg)
342 			uni_msg_destroy((struct uni_msg *)s->arg1);
343 		TAILQ_REMOVE(&cc->def_sigs, s, link);
344 		CCFREE(s);
345 	}
346 	while ((s = TAILQ_FIRST(&cc->free_sigs)) != NULL) {
347 		TAILQ_REMOVE(&cc->free_sigs, s, link);
348 		CCFREE(s);
349 	}
350 }
351