1/* 2* Copyright (c) 2004 3* Hartmut Brandt 4* All rights reserved. 5* 6* Author: Harti Brandt <harti@freebsd.org> 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 45enum { 46 SIG_USER, 47 SIG_CONN, 48}; 49 50struct 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 73const char *const cc_user_sigtab[] = { 74#define DEF(N) [USER_SIG_##N] = #N, 75USER_SIGS 76#undef DEF 77}; 78 79const char *const cc_conn_sigtab[] = { 80#define DEF(N) [CONN_SIG_##N] = #N, 81CONN_SIGS 82#undef DEF 83}; 84 85 86/* 87 * Allocate and populate a signal 88 */ 89static /* __inline */ struct ccsig * 90sig_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 */ 117int 118cc_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 */ 132int 133cc_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 */ 149static int 150sig_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 */ 180int 181cc_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 */ 190int 191cc_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} 196int 197cc_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 */ 216int 217cc_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 */ 251static /* __inline */ void 252sig_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 */ 284void 285cc_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 */ 295void 296cc_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 */ 306void 307cc_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 */ 329void 330cc_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