1131826Sharti/*
2131826Sharti* Copyright (c) 2004
3131826Sharti*	Hartmut Brandt
4131826Sharti*	All rights reserved.
5131826Sharti*
6131826Sharti* Author: Harti Brandt <harti@freebsd.org>
7131826Sharti*
8131826Sharti* Redistribution of this software and documentation and use in source and
9131826Sharti* binary forms, with or without modification, are permitted provided that
10131826Sharti* the following conditions are met:
11131826Sharti*
12131826Sharti* 1. Redistributions of source code or documentation must retain the above
13131826Sharti*    copyright notice, this list of conditions and the following disclaimer.
14131826Sharti* 2. Redistributions in binary form must reproduce the above copyright
15131826Sharti*    notice, this list of conditions and the following disclaimer in the
16131826Sharti*    documentation and/or other materials provided with the distribution.
17131826Sharti*
18131826Sharti* THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
19131826Sharti* AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20131826Sharti* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21131826Sharti* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
22131826Sharti* THE AUTHOR OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
23131826Sharti* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24131826Sharti* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25131826Sharti* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26131826Sharti* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27131826Sharti* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28131826Sharti* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29131826Sharti*
30131826Sharti* $Begemot: libunimsg/netnatm/api/cc_sig.c,v 1.1 2004/07/08 08:21:54 brandt Exp $
31131826Sharti*
32131826Sharti* ATM API as defined per af-saa-0108
33131826Sharti*
34131826Sharti* Generic signal handling
35131826Sharti*/
36131826Sharti#include <netnatm/unimsg.h>
37131826Sharti#include <netnatm/msg/unistruct.h>
38131826Sharti#include <netnatm/msg/unimsglib.h>
39131826Sharti#include <netnatm/api/unisap.h>
40131826Sharti#include <netnatm/sig/unidef.h>
41131826Sharti#include <netnatm/api/atmapi.h>
42131826Sharti#include <netnatm/api/ccatm.h>
43131826Sharti#include <netnatm/api/ccpriv.h>
44131826Sharti
45131826Shartienum {
46131826Sharti	SIG_USER,
47131826Sharti	SIG_CONN,
48131826Sharti};
49131826Sharti
50131826Shartistruct ccsig {
51131826Sharti	u_char	type;		/* type of target */
52131826Sharti	u_char	has_msg;	/* arg1 is a message */
53131826Sharti	void	*target;	/* target instance */
54131826Sharti	u_int	sig;		/* signal */
55131826Sharti	void	*arg1;		/* argument */
56131826Sharti	u_int	arg2;		/* argument */
57131826Sharti	TAILQ_ENTRY(ccsig) link;
58131826Sharti};
59131826Sharti
60131826Sharti#if defined(__GNUC__) && __GNUC__ < 3
61131826Sharti#define	cc_sig_log(CC, FMT, ARGS...) do {				\
62131826Sharti	if ((CC)->log & CCLOG_SIGS)					\
63131826Sharti		(CC)->funcs->log("%s: " FMT, __FUNCTION__ , ## ARGS);	\
64131826Sharti    } while (0)
65131826Sharti#else
66131826Sharti#define	cc_sig_log(CC, FMT, ...) do {					\
67131826Sharti	if ((CC)->log & CCLOG_SIGS)					\
68131826Sharti		(CC)->funcs->log("%s: " FMT, __func__, __VA_ARGS__);	\
69131826Sharti    } while (0)
70131826Sharti#endif
71131826Sharti
72131826Sharti
73131826Sharticonst char *const cc_user_sigtab[] = {
74131826Sharti#define	DEF(N) [USER_SIG_##N] = #N,
75131826ShartiUSER_SIGS
76131826Sharti#undef DEF
77131826Sharti};
78131826Sharti
79131826Sharticonst char *const cc_conn_sigtab[] = {
80131826Sharti#define	DEF(N) [CONN_SIG_##N] = #N,
81131826ShartiCONN_SIGS
82131826Sharti#undef DEF
83131826Sharti};
84131826Sharti
85131826Sharti
86131826Sharti/*
87131826Sharti * Allocate and populate a signal
88131826Sharti */
89131826Shartistatic /* __inline */ struct ccsig *
90131826Shartisig_alloc(struct ccdata *cc, u_int type, void *target, u_int has_msg,
91131826Sharti    u_int sig, void *arg1, u_int arg2)
92131826Sharti{
93131826Sharti	struct ccsig *s;
94131826Sharti
95131826Sharti	if ((s = TAILQ_FIRST(&cc->free_sigs)) == NULL) {
96131826Sharti		s = CCZALLOC(sizeof(struct ccsig));
97131826Sharti		if (s == NULL) {
98131826Sharti			cc_log(cc, "signal %u/%u lost - ENOMEM", type, sig);
99131826Sharti			return (NULL);
100131826Sharti		}
101131826Sharti	} else
102131826Sharti		TAILQ_REMOVE(&cc->free_sigs, s, link);
103131826Sharti
104131826Sharti	s->type = type;
105131826Sharti	s->has_msg = has_msg;
106131826Sharti	s->target = target;
107131826Sharti	s->sig = sig;
108131826Sharti	s->arg1 = arg1;
109131826Sharti	s->arg2 = arg2;
110131826Sharti
111131826Sharti	return (s);
112131826Sharti}
113131826Sharti
114131826Sharti/*
115131826Sharti * Queue a signal to this user
116131826Sharti */
117131826Shartiint
118131826Sharticc_user_sig(struct ccuser *user, enum user_sig sig, void *arg1, u_int arg2)
119131826Sharti{
120131826Sharti	struct ccsig *s;
121131826Sharti
122131826Sharti	s = sig_alloc(user->cc, SIG_USER, user, 0, sig, arg1, arg2);
123131826Sharti	if (s == NULL)
124131826Sharti		return (ENOMEM);
125131826Sharti	TAILQ_INSERT_TAIL(&user->cc->sigs, s, link);
126131826Sharti	cc_sig_log(user->cc, "queuing sig %s to user %p", cc_user_sigtab[sig],
127131826Sharti	    user);
128131826Sharti	return (0);
129131826Sharti}
130131826Sharti
131131826Sharti/* Queue a signal with message to this user */
132131826Shartiint
133131826Sharticc_user_sig_msg(struct ccuser *user, enum user_sig sig, struct uni_msg *msg)
134131826Sharti{
135131826Sharti	struct ccsig *s;
136131826Sharti
137131826Sharti	s = sig_alloc(user->cc, SIG_USER, user, msg != NULL, sig, msg, 0);
138131826Sharti	if (s == NULL)
139131826Sharti		return (ENOMEM);
140131826Sharti	TAILQ_INSERT_TAIL(&user->cc->sigs, s, link);
141131826Sharti	cc_sig_log(user->cc, "queuing sig %s to user %p", cc_user_sigtab[sig],
142131826Sharti	    user);
143131826Sharti	return (0);
144131826Sharti}
145131826Sharti
146131826Sharti/*
147131826Sharti * Signal to connection
148131826Sharti */
149131826Shartistatic int
150131826Shartisig_conn(struct ccconn *conn, enum conn_sig sig, u_int has_msg, void *arg)
151131826Sharti{
152131826Sharti	struct ccsig *s;
153131826Sharti	const struct ccreq *r = NULL;
154131826Sharti
155131826Sharti	s = sig_alloc(conn->cc, SIG_CONN, conn, has_msg, sig, arg, 0);
156131826Sharti	if (s == NULL)
157131826Sharti		return (ENOMEM);
158131826Sharti
159131826Sharti	if (conn->port != NULL) {
160131826Sharti		/* argh */
161131826Sharti		TAILQ_FOREACH(r, &conn->port->cookies, link)
162131826Sharti			if (r->conn == conn)
163131826Sharti				break;
164131826Sharti	}
165131826Sharti	if (r == NULL) {
166131826Sharti		TAILQ_INSERT_TAIL(&conn->cc->sigs, s, link);
167131826Sharti		cc_sig_log(conn->cc, "queuing sig %s to conn %p",
168131826Sharti		    cc_conn_sigtab[sig], conn);
169131826Sharti	} else {
170131826Sharti		TAILQ_INSERT_TAIL(&conn->cc->def_sigs, s, link);
171131826Sharti		cc_sig_log(conn->cc, "queuing defered sig %s to conn %p",
172131826Sharti		    cc_conn_sigtab[sig], conn);
173131826Sharti	}
174131826Sharti	return (0);
175131826Sharti}
176131826Sharti
177131826Sharti/*
178131826Sharti * Queue a signal to a connection.
179131826Sharti */
180131826Shartiint
181131826Sharticc_conn_sig(struct ccconn *conn, enum conn_sig sig, void *arg1)
182131826Sharti{
183131826Sharti
184131826Sharti	return (sig_conn(conn, sig, 0, arg1));
185131826Sharti}
186131826Sharti
187131826Sharti/*
188131826Sharti * signal with message to connection
189131826Sharti */
190131826Shartiint
191131826Sharticc_conn_sig_msg(struct ccconn *conn, enum conn_sig sig, struct uni_msg *msg)
192131826Sharti{
193131826Sharti
194131826Sharti	return (sig_conn(conn, sig, (msg != NULL), msg));
195131826Sharti}
196131826Shartiint
197131826Sharticc_conn_sig_msg_nodef(struct ccconn *conn, enum conn_sig sig,
198131826Sharti    struct uni_msg *msg)
199131826Sharti{
200131826Sharti	struct ccsig *s;
201131826Sharti
202131826Sharti	s = sig_alloc(conn->cc, SIG_CONN, conn, (msg != NULL), sig, msg, 0);
203131826Sharti	if (s == NULL)
204131826Sharti		return (ENOMEM);
205131826Sharti
206131826Sharti	TAILQ_INSERT_TAIL(&conn->cc->sigs, s, link);
207131826Sharti	cc_sig_log(conn->cc, "queuing sig %s to conn %p",
208131826Sharti	    cc_conn_sigtab[sig], conn);
209131826Sharti
210131826Sharti	return (0);
211131826Sharti}
212131826Sharti
213131826Sharti/*
214131826Sharti * Queue a response signal to a connection.
215131826Sharti */
216131826Shartiint
217131826Sharticc_conn_resp(struct ccconn *conn, enum conn_sig sig, u_int cookie __unused,
218131826Sharti    u_int reason, u_int state)
219131826Sharti{
220131826Sharti	struct ccsig *s, *s1, *s2;
221131826Sharti
222131826Sharti	s = sig_alloc(conn->cc, SIG_CONN, conn, 0, sig, NULL,
223131826Sharti	     ((reason & 0xffff) << 16) | (state & 0xffff));
224131826Sharti	if (s == NULL)
225131826Sharti		return (ENOMEM);
226131826Sharti
227131826Sharti	TAILQ_INSERT_TAIL(&conn->cc->sigs, s, link);
228131826Sharti
229131826Sharti	cc_sig_log(conn->cc, "queuing response %s to conn %p",
230131826Sharti	    cc_conn_sigtab[sig], conn);
231131826Sharti
232131826Sharti	s1 = TAILQ_FIRST(&conn->cc->def_sigs);
233131826Sharti	while (s1 != NULL) {
234131826Sharti		s2 = TAILQ_NEXT(s1, link);
235131826Sharti		if (s1->type == SIG_CONN && s1->target == conn) {
236131826Sharti			TAILQ_REMOVE(&conn->cc->def_sigs, s1, link);
237131826Sharti			TAILQ_INSERT_AFTER(&conn->cc->sigs, s, s1, link);
238131826Sharti			cc_sig_log(conn->cc, "undefering sig %s to conn %p",
239131826Sharti			    cc_conn_sigtab[s1->sig], conn);
240131826Sharti			s = s1;
241131826Sharti		}
242131826Sharti		s1 = s2;
243131826Sharti	}
244131826Sharti
245131826Sharti	return (0);
246131826Sharti}
247131826Sharti
248131826Sharti/*
249131826Sharti * Flush all signals to a given target from both queues
250131826Sharti */
251131826Shartistatic /* __inline */ void
252131826Shartisig_flush(struct ccdata *cc, u_int type, void *target)
253131826Sharti{
254131826Sharti	struct ccsig *s, *s1;
255131826Sharti
256131826Sharti	s = TAILQ_FIRST(&cc->sigs);
257131826Sharti	while (s != NULL) {
258131826Sharti		s1 = TAILQ_NEXT(s, link);
259131826Sharti		if (s->type == type && s->target == target) {
260131826Sharti			if (s->has_msg)
261131826Sharti				uni_msg_destroy((struct uni_msg *)s->arg1);
262131826Sharti			TAILQ_REMOVE(&cc->sigs, s, link);
263131826Sharti			TAILQ_INSERT_HEAD(&cc->free_sigs, s, link);
264131826Sharti		}
265131826Sharti		s = s1;
266131826Sharti	}
267131826Sharti
268131826Sharti	s = TAILQ_FIRST(&cc->def_sigs);
269131826Sharti	while (s != NULL) {
270131826Sharti		s1 = TAILQ_NEXT(s, link);
271131826Sharti		if (s->type == type && s->target == target) {
272131826Sharti			if (s->has_msg)
273131826Sharti				uni_msg_destroy((struct uni_msg *)s->arg1);
274131826Sharti			TAILQ_REMOVE(&cc->def_sigs, s, link);
275131826Sharti			TAILQ_INSERT_HEAD(&cc->free_sigs, s, link);
276131826Sharti		}
277131826Sharti		s = s1;
278131826Sharti	}
279131826Sharti}
280131826Sharti
281131826Sharti/*
282131826Sharti * Flush all signals to this user
283131826Sharti */
284131826Shartivoid
285131826Sharticc_user_sig_flush(struct ccuser *user)
286131826Sharti{
287131826Sharti
288131826Sharti	cc_sig_log(user->cc, "flushing signals to user %p", user);
289131826Sharti	sig_flush(user->cc, SIG_USER, user);
290131826Sharti}
291131826Sharti
292131826Sharti/*
293131826Sharti * Flush all signals to this connection
294131826Sharti */
295131826Shartivoid
296131826Sharticc_conn_sig_flush(struct ccconn *conn)
297131826Sharti{
298131826Sharti
299131826Sharti	cc_sig_log(conn->cc, "flushing signals to conn %p", conn);
300131826Sharti	sig_flush(conn->cc, SIG_CONN, conn);
301131826Sharti}
302131826Sharti
303131826Sharti/*
304131826Sharti * Do the work
305131826Sharti */
306131826Shartivoid
307131826Sharticc_work(struct ccdata *cc)
308131826Sharti{
309131826Sharti	struct ccsig *s;
310131826Sharti
311131826Sharti	cc_sig_log(cc, "start %s", "work");
312131826Sharti	while ((s = TAILQ_FIRST(&cc->sigs)) != NULL) {
313131826Sharti		TAILQ_REMOVE(&cc->sigs, s, link);
314131826Sharti		if (s->type == SIG_USER)
315131826Sharti			cc_user_sig_handle(s->target, s->sig, s->arg1, s->arg2);
316131826Sharti		else {
317131826Sharti			cc_conn_sig_handle(s->target, s->sig, s->arg1, s->arg2);
318131826Sharti			if (s->has_msg)
319131826Sharti				uni_msg_destroy(s->arg1);
320131826Sharti		}
321131826Sharti		TAILQ_INSERT_HEAD(&cc->free_sigs, s, link);
322131826Sharti	}
323131826Sharti	cc_sig_log(cc, "end %s", "work");
324131826Sharti}
325131826Sharti
326131826Sharti/*
327131826Sharti * flush all signals
328131826Sharti */
329131826Shartivoid
330131826Sharticc_sig_flush_all(struct ccdata *cc)
331131826Sharti{
332131826Sharti	struct ccsig *s;
333131826Sharti
334131826Sharti	while ((s = TAILQ_FIRST(&cc->sigs)) != NULL) {
335131826Sharti		if (s->has_msg)
336131826Sharti			uni_msg_destroy((struct uni_msg *)s->arg1);
337131826Sharti		TAILQ_REMOVE(&cc->sigs, s, link);
338131826Sharti		CCFREE(s);
339131826Sharti	}
340131826Sharti	while ((s = TAILQ_FIRST(&cc->def_sigs)) != NULL) {
341131826Sharti		if (s->has_msg)
342131826Sharti			uni_msg_destroy((struct uni_msg *)s->arg1);
343131826Sharti		TAILQ_REMOVE(&cc->def_sigs, s, link);
344131826Sharti		CCFREE(s);
345131826Sharti	}
346131826Sharti	while ((s = TAILQ_FIRST(&cc->free_sigs)) != NULL) {
347131826Sharti		TAILQ_REMOVE(&cc->free_sigs, s, link);
348131826Sharti		CCFREE(s);
349131826Sharti	}
350131826Sharti}
351