1131826Sharti/*
2171364Sharti * Copyright (c) 2003-2007
3131826Sharti *	Hartmut Brandt
4131826Sharti *	All rights reserved.
5131826Sharti *
6131826Sharti * Copyright (c) 2001-2002
7131826Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
8131826Sharti *	All rights reserved.
9131826Sharti *
10131826Sharti * Author: Harti Brandt <harti@freebsd.org>
11131826Sharti *
12131826Sharti * Redistribution of this software and documentation and use in source and
13131826Sharti * binary forms, with or without modification, are permitted provided that
14131826Sharti * the following conditions are met:
15131826Sharti *
16131826Sharti * 1. Redistributions of source code or documentation must retain the above
17131826Sharti *    copyright notice, this list of conditions and the following disclaimer.
18131826Sharti * 2. Redistributions in binary form must reproduce the above copyright
19131826Sharti *    notice, this list of conditions and the following disclaimer in the
20131826Sharti *    documentation and/or other materials provided with the distribution.
21131826Sharti *
22131826Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
23131826Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24131826Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
25131826Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
26131826Sharti * THE AUTHOR OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
27131826Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28131826Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29131826Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30131826Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31131826Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32131826Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33131826Sharti *
34171364Sharti * $Id: cc_conn.c 1291 2007-07-10 10:35:38Z brandt_h $
35131826Sharti *
36131826Sharti * ATM API as defined per af-saa-0108
37131826Sharti *
38131826Sharti * Lower half - connection handling
39131826Sharti */
40131826Sharti#include <netnatm/unimsg.h>
41131826Sharti#include <netnatm/msg/unistruct.h>
42131826Sharti#include <netnatm/msg/unimsglib.h>
43131826Sharti#include <netnatm/api/unisap.h>
44131826Sharti#include <netnatm/sig/unidef.h>
45131826Sharti#include <netnatm/api/atmapi.h>
46131826Sharti#include <netnatm/api/ccatm.h>
47131826Sharti#include <netnatm/api/ccpriv.h>
48131826Sharti
49131826Shartistatic const char *stab[] = {
50131826Sharti#define DEF(N) [N] = #N,
51131826Sharti	CONN_STATES
52131826Sharti#undef DEF
53131826Sharti};
54131826Sharti
55131826Shartistatic const char *ptab[] = {
56131826Sharti#define DEF(N) [PARTY_##N] = #N,
57131826Sharti	PARTY_STATES
58131826Sharti#undef DEF
59131826Sharti};
60131826Sharti
61131826Sharticonst char *
62131826Sharticc_conn_state2str(u_int s)
63131826Sharti{
64131826Sharti	if (s >= sizeof(stab) / sizeof(stab[0]) || stab[s] == NULL)
65131826Sharti		return ("?");
66131826Sharti	return (stab[s]);
67131826Sharti}
68131826Sharti
69171364Shartivoid
70131826Sharticc_conn_set_state(struct ccconn *conn, enum conn_state ns)
71131826Sharti{
72131826Sharti	if (conn->state != ns) {
73131826Sharti		if (conn->cc->log & CCLOG_CONN_STATE)
74131826Sharti			cc_conn_log(conn, "%s -> %s",
75131826Sharti			    stab[conn->state], stab[ns]);
76131826Sharti		conn->state = ns;
77131826Sharti	}
78131826Sharti}
79131826Sharti
80131826Sharticonst char *
81131826Sharticc_party_state2str(u_int s)
82131826Sharti{
83131826Sharti	if (s >= sizeof(ptab) / sizeof(ptab[0]) || ptab[s] == NULL)
84131826Sharti		return ("?");
85131826Sharti	return (ptab[s]);
86131826Sharti}
87131826Sharti
88171364Shartivoid
89131826Sharticc_party_set_state(struct ccparty *party, enum party_state ns)
90131826Sharti{
91131826Sharti
92131826Sharti	if (party->state != ns) {
93131826Sharti		if (party->conn->cc->log & CCLOG_PARTY_STATE)
94131826Sharti			cc_party_log(party, "%s -> %s",
95131826Sharti			    ptab[party->state], ptab[ns]);
96131826Sharti		party->state = ns;
97131826Sharti	}
98131826Sharti}
99131826Sharti
100131826Sharti/*
101131826Sharti * Remove connection from its user's queue
102131826Sharti */
103171364Shartivoid
104131826Sharticc_disconnect_from_user(struct ccconn *conn)
105131826Sharti{
106131826Sharti
107131826Sharti	if (conn->user == NULL)
108131826Sharti		cc_conn_log(conn, "no %s", "user");
109131826Sharti	else {
110131826Sharti		TAILQ_REMOVE(&conn->user->connq, conn, connq_link);
111131826Sharti		conn->user->queue_act--;
112131826Sharti		conn->user = NULL;
113131826Sharti	}
114131826Sharti}
115131826Sharti
116131826Sharti/*
117131826Sharti * Put connection on user queue
118131826Sharti */
119171364Shartivoid
120131826Sharticc_connect_to_user(struct ccconn *conn, struct ccuser *user)
121131826Sharti{
122131826Sharti
123131826Sharti	if (conn->user != NULL)
124131826Sharti		cc_conn_log(conn, "still connected to %p", conn->user);
125131826Sharti	conn->user = user;
126131826Sharti	TAILQ_INSERT_TAIL(&user->connq, conn, connq_link);
127131826Sharti	conn->user->queue_act++;
128131826Sharti}
129131826Sharti
130131826Sharti/*
131131826Sharti * Send a signal to the UNI stack for this connection
132131826Sharti */
133131826Shartistatic void
134131826Sharticc_send_uni(struct ccconn *conn, u_int op, struct uni_msg *msg)
135131826Sharti{
136131826Sharti	struct ccreq *r;
137131826Sharti
138131826Sharti	r = CCZALLOC(sizeof(*r));
139131826Sharti	if (r == NULL) {
140131826Sharti		if (msg != NULL)
141131826Sharti			uni_msg_destroy(msg);
142133492Sharti		cc_conn_log(conn, "no memory for cookie op=%u", op);
143131826Sharti		return;
144131826Sharti	}
145131826Sharti
146131826Sharti	if ((r->cookie = ++conn->port->cc->cookie) == 0)
147131826Sharti		r->cookie = ++conn->port->cc->cookie;
148131826Sharti	r->req = op;
149131826Sharti	r->conn = conn;
150131826Sharti
151131826Sharti	TAILQ_INSERT_TAIL(&conn->port->cookies, r, link);
152131826Sharti
153131826Sharti	conn->port->cc->funcs->send_uni(conn, conn->port->uarg, op,
154131826Sharti	    r->cookie, msg);
155131826Sharti}
156131826Sharti
157131826Sharti/*
158131826Sharti * Send a RELEASE.request for this connection.
159131826Sharti */
160131826Shartistatic void
161131826Shartido_release_request(struct ccconn *conn, const struct uni_ie_cause cause[2])
162131826Sharti{
163131826Sharti	struct uni_msg *u;
164131826Sharti	struct uniapi_release_request *req;
165131826Sharti
166131826Sharti	if ((u = uni_msg_alloc(sizeof(*req))) == NULL)
167131826Sharti		return;
168131826Sharti	req = uni_msg_wptr(u, struct uniapi_release_request *);
169131826Sharti	memset(req, 0, sizeof(*req));
170131826Sharti	u->b_wptr += sizeof(struct uniapi_release_request);
171131826Sharti
172131826Sharti	req->release.hdr.cref = conn->cref;
173131826Sharti	req->release.hdr.act = UNI_MSGACT_DEFAULT;
174131826Sharti
175131826Sharti	if (cause == NULL) {
176131826Sharti		IE_SETPRESENT(req->release.cause[0]);
177131826Sharti		req->release.cause[0].h.act = UNI_IEACT_DEFAULT;
178131826Sharti		req->release.cause[0].loc = UNI_CAUSE_LOC_USER;
179131826Sharti		req->release.cause[0].cause = UNI_CAUSE_UNSPEC;
180131826Sharti	} else {
181131826Sharti		req->release.cause[0] = cause[0];
182131826Sharti		req->release.cause[1] = cause[1];
183131826Sharti	}
184131826Sharti
185131826Sharti	cc_send_uni(conn, UNIAPI_RELEASE_request, u);
186131826Sharti}
187131826Sharti
188131826Sharti/*
189131826Sharti * Make a RELEASE.response for this connection
190131826Sharti */
191131826Shartistatic void
192131826Shartido_release_response(struct ccconn *conn, uint8_t cause, struct uni_ie_cause *ie)
193131826Sharti{
194131826Sharti	struct uni_msg *u;
195131826Sharti	struct uniapi_release_response *resp;
196131826Sharti
197131826Sharti	if ((u = uni_msg_alloc(sizeof(*resp))) == NULL)
198131826Sharti		return;
199131826Sharti	resp = uni_msg_wptr(u, struct uniapi_release_response *);
200131826Sharti	memset(resp, 0, sizeof(*resp));
201131826Sharti	u->b_wptr += sizeof(struct uniapi_release_response);
202131826Sharti
203131826Sharti	resp->release_compl.hdr.cref = conn->cref;
204131826Sharti	resp->release_compl.hdr.act = UNI_MSGACT_DEFAULT;
205131826Sharti
206131826Sharti	if (ie != NULL)
207131826Sharti		resp->release_compl.cause[0] = *ie;
208131826Sharti
209131826Sharti	if (cause != 0) {
210131826Sharti		IE_SETPRESENT(resp->release_compl.cause[0]);
211131826Sharti		resp->release_compl.cause[0].h.act = UNI_IEACT_DEFAULT;
212131826Sharti		resp->release_compl.cause[0].loc = UNI_CAUSE_LOC_USER;
213131826Sharti		resp->release_compl.cause[0].cause = cause;
214131826Sharti	}
215131826Sharti
216131826Sharti	cc_send_uni(conn, UNIAPI_RELEASE_response, u);
217131826Sharti}
218131826Sharti
219131826Sharti/**********************************************************************
220131826Sharti *
221131826Sharti * INSTANCE handling
222131826Sharti */
223131826Shartistruct ccconn *
224131826Sharticc_conn_create(struct ccdata *cc)
225131826Sharti{
226131826Sharti	struct ccconn *conn;
227131826Sharti
228131826Sharti	conn = CCZALLOC(sizeof(*conn));
229131826Sharti	if (conn == NULL)
230131826Sharti		return (NULL);
231131826Sharti
232131826Sharti	conn->state = CONN_NULL;
233131826Sharti	conn->port = NULL;
234131826Sharti	conn->cc = cc;
235131826Sharti	LIST_INIT(&conn->parties);
236131826Sharti
237131826Sharti	LIST_INSERT_HEAD(&cc->orphaned_conns, conn, port_link);
238131826Sharti
239131826Sharti	if (conn->cc->log & CCLOG_CONN_INST)
240131826Sharti		cc_conn_log(conn, "created %s", "orphaned");
241131826Sharti
242131826Sharti	return (conn);
243131826Sharti}
244131826Sharti
245131826Sharti/*
246131826Sharti * assign to port
247131826Sharti */
248131826Shartivoid
249131826Sharticc_conn_ins_port(struct ccconn *conn, struct ccport *port)
250131826Sharti{
251131826Sharti
252131826Sharti	if (conn->port != NULL) {
253131826Sharti		cc_conn_log(conn, "conn is already on port %u",
254131826Sharti		    conn->port->param.port);
255131826Sharti		cc_conn_rem_port(conn);
256131826Sharti	}
257131826Sharti	LIST_REMOVE(conn, port_link);
258131826Sharti
259131826Sharti	conn->port = port;
260131826Sharti	LIST_INSERT_HEAD(&port->conn_list, conn, port_link);
261131826Sharti
262131826Sharti}
263131826Sharti
264131826Sharti/*
265131826Sharti * remove from port
266131826Sharti */
267131826Shartivoid
268131826Sharticc_conn_rem_port(struct ccconn *conn)
269131826Sharti{
270131826Sharti
271131826Sharti	if (conn->port == NULL) {
272131826Sharti		cc_conn_log(conn, "conn not on any %s", "port");
273131826Sharti		return;
274131826Sharti	}
275131826Sharti	LIST_REMOVE(conn, port_link);
276131826Sharti	conn->port = NULL;
277131826Sharti	LIST_INSERT_HEAD(&conn->cc->orphaned_conns, conn, port_link);
278131826Sharti}
279131826Sharti
280131826Shartistatic void
281131826Sharticc_conn_flush_cookies(struct ccconn *conn)
282131826Sharti{
283131826Sharti	struct ccreq *r, *r1;
284131826Sharti
285131826Sharti	if (conn->port == NULL)
286131826Sharti		return;
287131826Sharti	TAILQ_FOREACH_SAFE(r, &conn->port->cookies, link, r1) {
288131826Sharti		if (r->conn == conn) {
289131826Sharti			TAILQ_REMOVE(&conn->port->cookies, r, link);
290131826Sharti			CCFREE(r);
291131826Sharti		}
292131826Sharti	}
293131826Sharti}
294131826Sharti
295171364Shartivoid
296131826Sharticc_conn_reset_acceptor(struct ccconn *conn)
297131826Sharti{
298131826Sharti	if (conn->acceptor != NULL) {
299131826Sharti		conn->acceptor->accepted = NULL;
300131826Sharti		conn->acceptor = NULL;
301131826Sharti	}
302131826Sharti}
303131826Sharti
304131826Sharti/*
305131826Sharti * Destroy a connection
306131826Sharti */
307131826Shartivoid
308131826Sharticc_conn_destroy(struct ccconn *conn)
309131826Sharti{
310131826Sharti	struct ccparty *p;
311131826Sharti
312131826Sharti	if (conn->cc->log & CCLOG_CONN_INST)
313131826Sharti		cc_conn_log(conn, "destroy%s", "");
314131826Sharti
315131826Sharti	if (conn->user != NULL) {
316131826Sharti		cc_conn_log(conn, "still connected to user %p\n", conn->user);
317131826Sharti		conn->user->queue_act--;
318131826Sharti		TAILQ_REMOVE(&conn->user->connq, conn, connq_link);
319131826Sharti	}
320131826Sharti
321131826Sharti	if (conn->acceptor != NULL)
322131826Sharti		conn->acceptor->accepted = NULL;
323131826Sharti
324131826Sharti	cc_conn_flush_cookies(conn);
325131826Sharti	cc_conn_sig_flush(conn);
326131826Sharti
327131826Sharti	LIST_REMOVE(conn, port_link);
328131826Sharti	while ((p = LIST_FIRST(&conn->parties)) != NULL) {
329131826Sharti		LIST_REMOVE(p, link);
330131826Sharti		CCFREE(p);
331131826Sharti	}
332131826Sharti
333131826Sharti	CCFREE(conn);
334131826Sharti}
335131826Sharti
336131826Shartistruct ccparty *
337131826Sharticc_party_create(struct ccconn *conn, u_int ident, u_int flag)
338131826Sharti{
339131826Sharti	struct ccparty *party;
340131826Sharti
341131826Sharti	party = CCZALLOC(sizeof(*party));
342131826Sharti	if (party == NULL)
343131826Sharti		return (NULL);
344131826Sharti
345131826Sharti	party->conn = conn;
346131826Sharti	party->state = PARTY_NULL;
347131826Sharti	IE_SETPRESENT(party->epref);
348131826Sharti	party->epref.flag = flag;
349131826Sharti	party->epref.epref = ident;
350131826Sharti	LIST_INSERT_HEAD(&conn->parties, party, link);
351131826Sharti
352131826Sharti	if (party->conn->cc->log & CCLOG_PARTY_INST)
353131826Sharti		cc_party_log(party, "created %u.%u", flag, ident);
354131826Sharti
355131826Sharti	return (party);
356131826Sharti}
357131826Sharti
358131826Shartistatic void
359131826Sharticc_party_destroy(struct ccparty *party)
360131826Sharti{
361131826Sharti
362131826Sharti	if (party->conn->cc->log & CCLOG_PARTY_INST)
363131826Sharti		cc_party_log(party, "destroyed %u.%u", party->epref.flag,
364131826Sharti		    party->epref.epref);
365131826Sharti
366131826Sharti	LIST_REMOVE(party, link);
367131826Sharti	CCFREE(party);
368131826Sharti}
369131826Sharti
370131826Shartistatic struct ccparty *
371131826Sharticc_party_find(struct ccconn *conn, u_int ident)
372131826Sharti{
373131826Sharti	struct ccparty *party;
374131826Sharti
375131826Sharti	LIST_FOREACH(party, &conn->parties, link)
376131826Sharti		if (party->epref.epref == ident)
377131826Sharti			return (party);
378131826Sharti	return (NULL);
379131826Sharti}
380131826Sharti/*
381131826Sharti * Abort connection from down stream (because of the UNI hook beeing
382131826Sharti * disconnected). This is called from two places:
383131826Sharti *  1) the shutdown code.
384131826Sharti *	In this case the connections should be already dissociated from
385131826Sharti *	users and be only in states waiting for the UNI stack.
386131826Sharti *  2) from the disconnect code.
387131826Sharti */
388131826Shartivoid
389131826Sharticc_conn_abort(struct ccconn *conn, int shutdown)
390131826Sharti{
391131826Sharti	struct ccuser *u = conn->user;
392131826Sharti	struct ccparty *p, *p1;
393131826Sharti
394131826Sharti	if (shutdown) {
395131826Sharti		CCASSERT(u == NULL, ("still in use"));
396131826Sharti		CCASSERT(conn->acceptor == NULL, ("still in use"));
397131826Sharti		cc_conn_destroy(conn);
398131826Sharti		return;
399131826Sharti	}
400131826Sharti
401131826Sharti	/*
402131826Sharti	 * Look whether any parties are blocked waiting for a response
403131826Sharti	 * from the stack. We don't use extra party states to handle
404131826Sharti	 * user aborts, so check that there is a user before using it.
405131826Sharti	 */
406131826Sharti	if (u == NULL) {
407131826Sharti		while ((p = LIST_FIRST(&conn->parties)) != NULL)
408131826Sharti			cc_party_destroy(p);
409131826Sharti	} else {
410131826Sharti		LIST_FOREACH_SAFE(p, &conn->parties, link, p1) {
411131826Sharti			switch (p->state) {
412131826Sharti
413131826Sharti			  case PARTY_NULL:		/* P0 */
414131826Sharti				/* should not happen */
415131826Sharti				goto dpty;
416131826Sharti
417131826Sharti			  case PARTY_ACTIVE:		/* P1 */
418131826Sharti				/* don't send a drop - user'll get a rel */
419131826Sharti				goto dpty;
420131826Sharti
421131826Sharti			  case PARTY_ADD_WAIT_CREATE:	/* P2 */
422131826Sharti			  case PARTY_ADD_WAIT_OK:	/* P3 */
423131826Sharti				/* we're adding - synthesise an error */
424131826Sharti				cc_user_sig(u, USER_SIG_ADD_PARTY_ERR,
425131826Sharti				    NULL, ATMERR_BAD_PORT);
426131826Sharti				goto dpty;
427131826Sharti
428131826Sharti			  case PARTY_ADD_WAIT_ACK:	/* P4 */
429131826Sharti				/* don't send a drop - user'll get a rel */
430131826Sharti				goto dpty;
431131826Sharti
432131826Sharti			  case PARTY_DROP_WAIT_OK:	/* P5 */
433131826Sharti			  case PARTY_DROP_WAIT_ACK:	/* P6 */
434131826Sharti			  case PARTY_ADD_DROP_WAIT_OK:	/* P11 */
435131826Sharti				/* we're dropping - synthesis an ok */
436131826Sharti				cc_user_sig(u, USER_SIG_DROP_PARTY_OK,
437131826Sharti				    NULL, p->epref.epref);
438131826Sharti				goto dpty;
439131826Sharti
440131826Sharti			  case PARTY_WAIT_DESTROY:	/* P7 */
441131826Sharti				goto dpty;
442131826Sharti
443131826Sharti			  case PARTY_WAIT_SETUP_COMPL:	/* P8 */
444131826Sharti			  case PARTY_WAIT_SETUP_CONF:	/* P10 */
445131826Sharti				/* first party - nothing to do */
446131826Sharti				goto dpty;
447131826Sharti
448131826Sharti			  case PARTY_WAIT_DROP_ACK_OK:	/* P9 */
449131826Sharti			  case PARTY_ADD_DROPACK_WAIT_OK:/* P12 */
450131826Sharti				/* we're dropping - nothing to do */
451131826Sharti				goto dpty;
452131826Sharti			}
453131826Sharti			cc_party_log(p, "bad uabort for party in state %s",
454131826Sharti			    ptab[p->state]);
455131826Sharti    dpty:
456131826Sharti			cc_party_destroy(p);
457131826Sharti		}
458131826Sharti	}
459131826Sharti
460131826Sharti	/*
461131826Sharti	 * Now do what the connection needs
462131826Sharti	 */
463131826Sharti	switch (conn->state) {
464131826Sharti
465131826Sharti	  case CONN_NULL:		/* 0 */
466131826Sharti	  case CONN_OUT_PREPARING: 	/* 1 */
467131826Sharti		/* may not happen because we're not associated with
468131826Sharti		 * aport yet */
469131826Sharti		break;
470131826Sharti
471131826Sharti	  case CONN_OUT_WAIT_CREATE: 	/* 2 */
472131826Sharti	  case CONN_OUT_WAIT_OK:	/* 3 */
473131826Sharti	  case CONN_OUT_WAIT_DESTROY:	/* 37 */
474131826Sharti		/* return an error to the user, go back to C1/U1
475131826Sharti		 * reset cref (for C37, C3) and cookie */
476131826Sharti		conn->cref.flag = 0;
477131826Sharti		conn->cref.cref = 0;
478131826Sharti		cc_conn_flush_cookies(conn);
479131826Sharti		cc_conn_set_state(conn, CONN_OUT_PREPARING);
480131826Sharti		cc_conn_rem_port(conn);
481131826Sharti		cc_user_sig(u, USER_SIG_CONNECT_OUTGOING_ERR,
482131826Sharti		    NULL, ATMERR_BAD_PORT);
483131826Sharti		return;
484131826Sharti
485131826Sharti	  case CONN_OUT_WAIT_CONF:	/* 4 */
486131826Sharti	  case CONN_ACTIVE:		/* 5 */
487131826Sharti	  case CONN_IN_WAIT_COMPL:	/* 13 */
488131826Sharti		/* emulate a RELEASE.confirm */
489131826Sharti		memset(&u->cause, 0, sizeof(u->cause));
490131826Sharti		cc_user_sig(u, USER_SIG_RELEASE_CONFIRM, NULL, 0);
491131826Sharti		cc_disconnect_from_user(conn);
492131826Sharti		cc_conn_destroy(conn);
493131826Sharti		return;
494131826Sharti
495131826Sharti	  case CONN_IN_PREPARING:	/* 10 */
496131826Sharti	  case CONN_AB_WAIT_REQ_OK:	/* 33 */
497131826Sharti	  case CONN_AB_WAIT_RESP_OK:	/* 34 */
498131826Sharti	  case CONN_AB_FLUSH_IND:	/* 35 */
499131826Sharti		/* no user - destroy */
500131826Sharti		cc_conn_destroy(conn);
501131826Sharti		return;
502131826Sharti
503131826Sharti	  case CONN_IN_ARRIVED:		/* 11 */
504131826Sharti		u->aborted = 1;
505131826Sharti		cc_disconnect_from_user(conn);
506131826Sharti		cc_conn_destroy(conn);
507131826Sharti		return;
508131826Sharti
509131826Sharti	  case CONN_IN_WAIT_ACCEPT_OK:	/* 12 */
510131826Sharti		/* return ACCEPT error */
511131826Sharti		cc_disconnect_from_user(conn);
512131826Sharti		cc_conn_reset_acceptor(conn);
513131826Sharti		cc_user_sig(u, USER_SIG_ACCEPT_ERR,
514131826Sharti		    u, ATMERR_PREVIOUSLY_ABORTED);
515131826Sharti		cc_conn_destroy(conn);
516131826Sharti		return;
517131826Sharti
518131826Sharti	  case CONN_REJ_WAIT_OK:	/* 14 */
519131826Sharti		/* return REJECT ok */
520131826Sharti		cc_disconnect_from_user(conn);
521131826Sharti		cc_conn_destroy(conn);
522131826Sharti		cc_user_sig(u, USER_SIG_REJECT_OK, NULL, 0);
523131826Sharti		return;
524131826Sharti
525131826Sharti	  case CONN_REL_IN_WAIT_OK:	/* 15 */
526131826Sharti	  case CONN_REL_WAIT_OK:	/* 20 */
527131826Sharti		/* confirm destroy */
528131826Sharti		if (u != NULL) {
529131826Sharti			/* connection not aborted */
530131826Sharti			memset(&u->cause, 0, sizeof(u->cause));
531131826Sharti			cc_user_sig(u, USER_SIG_RELEASE_CONFIRM, NULL, 0);
532131826Sharti			cc_disconnect_from_user(conn);
533131826Sharti		}
534131826Sharti		cc_conn_destroy(conn);
535131826Sharti		return;
536131826Sharti
537131826Sharti	  case CONN_IN_WAITING:		/* 21 */
538131826Sharti		/* user has not seen the connection - destroy */
539131826Sharti		cc_disconnect_from_user(conn);
540131826Sharti		cc_conn_destroy(conn);
541131826Sharti		return;
542131826Sharti	}
543131826Sharti	cc_conn_log(conn, "bad state %s", stab[conn->state]);
544131826Sharti}
545131826Sharti
546131826Sharti#ifdef DEBUG_MATCH
547131826Shartistatic void
548131826Shartiprint_sap(const struct uni_sap *sap)
549131826Sharti{
550131826Sharti	static const char *const tags[] = {
551131826Sharti		[UNISVE_ABSENT] "absent",
552131826Sharti		[UNISVE_PRESENT]"present",
553131826Sharti		[UNISVE_ANY]	"any",
554131826Sharti	};
555131826Sharti	u_int i;
556131826Sharti
557131826Sharti	printf("addr={%s", tags[sap->addr.tag]);
558131826Sharti	if (sap->addr.tag == UNISVE_PRESENT) {
559131826Sharti		printf(",%d-%d", sap->addr.type, sap->addr.plan);
560131826Sharti		for (i = 0; i < sap->addr.len; i++)
561131826Sharti			printf("%c%02x", ",:"[i!=0], sap->addr.addr[i]);
562131826Sharti	}
563131826Sharti	printf("}\n");
564131826Sharti
565131826Sharti	printf("selector={%s", tags[sap->selector.tag]);
566131826Sharti	if (sap->selector.tag == UNISVE_PRESENT)
567131826Sharti		printf(",%02x", sap->selector.selector);
568131826Sharti	printf("}\n");
569131826Sharti
570131826Sharti	printf("blli_id2={%s", tags[sap->blli_id2.tag]);
571131826Sharti	if (sap->blli_id2.tag == UNISVE_PRESENT)
572131826Sharti		printf(",%02x,%02x", sap->blli_id2.proto, sap->blli_id2.user);
573131826Sharti	printf("}\n");
574131826Sharti
575131826Sharti	printf("blli_id3={%s", tags[sap->blli_id3.tag]);
576131826Sharti	if (sap->blli_id3.tag == UNISVE_PRESENT)
577131826Sharti		printf(",%02x,%02x,%02x,%06x,%04x,%d",
578131826Sharti		    sap->blli_id3.proto, sap->blli_id3.user,
579131826Sharti		    sap->blli_id3.ipi, sap->blli_id3.oui,
580131826Sharti		    sap->blli_id3.pid, sap->blli_id3.noipi);
581131826Sharti	printf("}\n");
582131826Sharti
583131826Sharti	printf("bhli={%s", tags[sap->bhli.tag]);
584131826Sharti	if (sap->bhli.tag == UNISVE_PRESENT) {
585131826Sharti		printf(",%d", sap->bhli.type);
586131826Sharti		for (i = 0; i < sap->bhli.len; i++)
587131826Sharti			printf("%c%02x", ",:"[i!=0], sap->bhli.info[i]);
588131826Sharti	}
589131826Sharti	printf("}\n");
590131826Sharti}
591131826Sharti#endif
592131826Sharti
593131826Sharti/*********************************************************************
594131826Sharti *
595131826Sharti * DISPATCH incoming call
596131826Sharti */
597131826Shartivoid
598131826Sharticc_conn_dispatch(struct ccconn *conn)
599131826Sharti{
600131826Sharti	struct ccdata *priv = conn->port->cc;
601131826Sharti	struct ccuser *user;
602131826Sharti	u_int blli_index;
603131826Sharti
604131826Sharti#ifdef DEBUG_MATCH
605131826Sharti	static char buf[1000];
606131826Sharti	static struct unicx cx;
607131826Sharti	static int init = 1;
608131826Sharti
609131826Sharti	if (init) {
610131826Sharti		uni_initcx(&cx);
611131826Sharti		init = 0;
612131826Sharti	}
613131826Sharti#endif
614131826Sharti
615131826Sharti	/*
616131826Sharti	 * Do call dispatching according to 4.6
617131826Sharti	 */
618131826Sharti#ifdef DEBUG_MATCH
619131826Sharti	printf("+++++ DISPATCH++++++\n");
620131826Sharti#endif
621131826Sharti	for (blli_index = 0; blli_index < UNI_NUM_IE_BLLI; blli_index++) {
622131826Sharti		if (blli_index > 0 && !IE_ISGOOD(conn->blli[blli_index]))
623131826Sharti			break;
624131826Sharti#ifdef DEBUG_MATCH
625131826Sharti		if (IE_ISPRESENT(conn->called)) {
626131826Sharti			uni_print_ie(buf, sizeof(buf), UNI_IE_CALLED,
627131826Sharti			    (union uni_ieall *)&conn->called, &cx);
628131826Sharti			printf("called=%s\n", buf);
629131826Sharti		}
630131826Sharti		if (IE_ISPRESENT(conn->bhli)) {
631131826Sharti			uni_print_ie(buf, sizeof(buf), UNI_IE_BHLI,
632131826Sharti			    (union uni_ieall *)&conn->bhli, &cx);
633131826Sharti			printf("bhli=%s\n", buf);
634131826Sharti		}
635131826Sharti		if (IE_ISPRESENT(conn->blli[blli_index])) {
636131826Sharti			uni_print_ie(buf, sizeof(buf), UNI_IE_BLLI,
637131826Sharti			    (union uni_ieall *)&conn->blli[blli_index], &cx);
638131826Sharti			printf("%s\n", buf);
639131826Sharti		}
640131826Sharti#endif
641131826Sharti		LIST_FOREACH(user, &priv->user_list, node_link) {
642131826Sharti			if ((user->state == USER_IN_WAITING ||
643131826Sharti			    user->state == USER_IN_ARRIVED ||
644131826Sharti			    user->state == USER_IN_WAIT_ACC ||
645131826Sharti			    user->state == USER_IN_WAIT_REJ) &&
646131826Sharti			    !unisve_is_catchall(user->sap)) {
647131826Sharti#ifdef DEBUG_MATCH
648131826Sharti				printf("TRYING user=%p\n", user);
649131826Sharti				print_sap(user->sap);
650131826Sharti#endif
651131826Sharti				if (unisve_match(user->sap, &conn->called,
652131826Sharti				    &conn->blli[blli_index], &conn->bhli))
653131826Sharti					goto found;
654131826Sharti			}
655131826Sharti		}
656131826Sharti	}
657131826Sharti#ifdef DEBUG_MATCH
658131826Sharti	printf("TRYING CATCHALL\n");
659131826Sharti#endif
660131826Sharti	blli_index = 0;
661131826Sharti	LIST_FOREACH(user, &priv->user_list, node_link) {
662131826Sharti		if ((user->state == USER_IN_WAITING ||
663131826Sharti		    user->state == USER_IN_ARRIVED ||
664131826Sharti		    user->state == USER_IN_WAIT_ACC ||
665131826Sharti		    user->state == USER_IN_WAIT_REJ) &&
666131826Sharti		    unisve_is_catchall(user->sap))
667131826Sharti			goto found;
668131826Sharti	}
669131826Sharti#ifdef DEBUG_MATCH
670131826Sharti	printf("SORRY\n");
671131826Sharti#endif
672131826Sharti
673131826Sharti	/*
674131826Sharti	 * No application found - reject call.
675131826Sharti	 */
676131826Sharti	do_release_response(conn, UNI_CAUSE_INCOMP, NULL);
677131826Sharti	cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
678131826Sharti	return;
679131826Sharti
680131826Sharti  found:
681131826Sharti#ifdef DEBUG_MATCH
682131826Sharti	printf("MATCH\n");
683131826Sharti#endif
684131826Sharti	if (user->queue_max == user->queue_act) {
685131826Sharti		do_release_response(conn, UNI_CAUSE_BUSY, NULL);
686131826Sharti		cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
687131826Sharti		return;
688131826Sharti	}
689131826Sharti
690131826Sharti	if (blli_index == 0 && !IE_ISGOOD(conn->blli[blli_index]))
691131826Sharti		conn->blli_selector = 0;
692131826Sharti	else
693131826Sharti		conn->blli_selector = blli_index + 1;
694131826Sharti
695131826Sharti	cc_conn_set_state(conn, CONN_IN_WAITING);
696131826Sharti	cc_connect_to_user(conn, user);
697131826Sharti
698131826Sharti	cc_user_sig(user, USER_SIG_SETUP_IND, NULL, 0);
699131826Sharti}
700131826Sharti
701131826Shartistatic void
702131826Sharticc_party_setup_conf(struct ccconn *conn)
703131826Sharti{
704131826Sharti	struct ccparty *party;
705131826Sharti
706131826Sharti	party = cc_party_find(conn, conn->epref.epref);
707131826Sharti	if (party == NULL) {
708131826Sharti		cc_party_log(party, "no party for %s",
709131826Sharti		    cc_conn_sigtab[CONN_SIG_SETUP_CONFIRM]);
710131826Sharti		return;
711131826Sharti	}
712131826Sharti	if (party->state != PARTY_WAIT_SETUP_CONF) {
713131826Sharti		cc_party_log(party, "bad state=%s for signal=%s",
714131826Sharti		    ptab[party->state], cc_conn_sigtab[CONN_SIG_SETUP_CONFIRM]);
715131826Sharti		return;
716131826Sharti	}
717131826Sharti	cc_party_set_state(party, PARTY_ACTIVE);
718131826Sharti}
719131826Sharti
720131826Shartistatic void
721131826Sharticc_party_add_ack_ind(struct ccconn *conn, const struct uni_ie_epref *epref)
722131826Sharti{
723131826Sharti	struct ccparty *party;
724131826Sharti
725131826Sharti	party = cc_party_find(conn, epref->epref);
726131826Sharti	if (party == NULL) {
727131826Sharti		cc_party_log(party, "no party for %s",
728131826Sharti		    cc_conn_sigtab[CONN_SIG_PARTY_ADD_ACK_IND]);
729131826Sharti	}
730131826Sharti	if (party->state != PARTY_ADD_WAIT_ACK) {
731131826Sharti		cc_party_log(party, "bad state=%s for signal=%s",
732131826Sharti		    ptab[party->state],
733131826Sharti		    cc_conn_sigtab[CONN_SIG_PARTY_ADD_ACK_IND]);
734131826Sharti		return;
735131826Sharti	}
736131826Sharti	cc_party_set_state(party, PARTY_ACTIVE);
737131826Sharti	cc_user_sig(conn->user, USER_SIG_ADD_PARTY_ACK,
738131826Sharti	    NULL, epref->epref);
739131826Sharti}
740131826Sharti
741131826Shartistatic void
742131826Sharticc_party_add_rej_ind(struct ccconn *conn, const struct uni_ie_epref *epref)
743131826Sharti{
744131826Sharti	struct ccparty *party;
745131826Sharti
746131826Sharti	party = cc_party_find(conn, epref->epref);
747131826Sharti	if (party == NULL) {
748131826Sharti		cc_party_log(party, "no party for %s",
749131826Sharti		    cc_conn_sigtab[CONN_SIG_PARTY_ADD_REJ_IND]);
750131826Sharti		return;
751131826Sharti	}
752131826Sharti	if (party->state != PARTY_ADD_WAIT_ACK) {
753131826Sharti		cc_party_log(party, "bad state=%s for signal=%s",
754131826Sharti		    ptab[party->state],
755131826Sharti		    cc_conn_sigtab[CONN_SIG_PARTY_ADD_REJ_IND]);
756131826Sharti		return;
757131826Sharti	}
758131826Sharti	cc_party_set_state(party, PARTY_WAIT_DESTROY);
759131826Sharti	cc_user_sig(conn->user, USER_SIG_ADD_PARTY_REJ, NULL, epref->epref);
760131826Sharti}
761131826Sharti
762131826Shartistatic void
763131826Sharticc_party_drop_ack_ind(struct ccconn *conn,
764131826Sharti    const struct uni_drop_party *drop)
765131826Sharti{
766131826Sharti	struct ccparty *party;
767131826Sharti
768131826Sharti	party = cc_party_find(conn, drop->epref.epref);
769131826Sharti	if (party == NULL) {
770131826Sharti		cc_party_log(party, "no party for %s",
771201818Strasz		    cc_conn_sigtab[CONN_SIG_DROP_PARTY_ACK_IND]);
772131826Sharti		return;
773131826Sharti	}
774131826Sharti	switch (party->state) {
775131826Sharti
776131826Sharti	  case PARTY_ACTIVE:			/* P1 */
777131826Sharti		memset(&conn->user->cause[1], 0, sizeof(conn->user->cause[1]));
778131826Sharti		conn->user->cause[0] = drop->cause;
779131826Sharti		cc_party_set_state(party, PARTY_WAIT_DESTROY);
780131826Sharti		cc_user_sig(conn->user, USER_SIG_DROP_PARTY_IND,
781131826Sharti		    NULL, party->epref.epref);
782131826Sharti		break;
783131826Sharti
784131826Sharti	  case PARTY_ADD_WAIT_ACK:		/* P4 */
785131826Sharti		memset(&conn->user->cause[1], 0, sizeof(conn->user->cause[1]));
786131826Sharti		conn->user->cause[0] = drop->cause;
787131826Sharti		cc_party_set_state(party, PARTY_WAIT_DESTROY);
788131826Sharti		cc_user_sig(conn->user, USER_SIG_ADD_PARTY_REJ,
789131826Sharti		    NULL, party->epref.epref);
790131826Sharti		break;
791131826Sharti
792131826Sharti	  case PARTY_DROP_WAIT_ACK:		/* P6 */
793131826Sharti		cc_party_set_state(party, PARTY_WAIT_DESTROY);
794131826Sharti		cc_user_sig(conn->user, USER_SIG_DROP_PARTY_OK, NULL, 0);
795131826Sharti		break;
796131826Sharti
797131826Sharti	  case PARTY_WAIT_SETUP_COMPL:		/* P8 */
798131826Sharti	  case PARTY_WAIT_SETUP_CONF:		/* P10 */
799131826Sharti		cc_party_set_state(party, PARTY_WAIT_DESTROY);
800131826Sharti		break;
801131826Sharti
802131826Sharti	  default:
803131826Sharti		cc_party_log(party, "bad state=%s for signal=%s",
804131826Sharti		    ptab[party->state],
805131826Sharti		    cc_conn_sigtab[CONN_SIG_DROP_PARTY_ACK_IND]);
806131826Sharti		break;
807131826Sharti	}
808131826Sharti}
809131826Sharti
810131826Sharti/*
811131826Sharti * Handle a signal to this connection
812131826Sharti */
813131826Shartivoid
814131826Sharticc_conn_sig_handle(struct ccconn *conn, enum conn_sig sig,
815131826Sharti    void *arg, u_int iarg)
816131826Sharti{
817131826Sharti	struct ccparty *party;
818131826Sharti
819131826Sharti	if (conn->cc->log & CCLOG_CONN_SIG)
820131826Sharti		cc_conn_log(conn, "signal %s in state %s", cc_conn_sigtab[sig],
821131826Sharti		    stab[conn->state]);
822131826Sharti
823131826Sharti	switch (sig) {
824131826Sharti
825131826Sharti	  case CONN_SIG_CONNECT_OUTGOING:
826131826Sharti		/* Do SETUP */
827131826Sharti	    {
828131826Sharti		struct uni_msg *u;
829131826Sharti		struct uniapi_setup_request *setup;
830131826Sharti
831131826Sharti		if (conn->state != CONN_OUT_PREPARING)
832131826Sharti			goto bad_state;
833131826Sharti
834131826Sharti		if (IE_ISGOOD(conn->bearer) &&
835131826Sharti		    conn->bearer.cfg == UNI_BEARER_MP) {
836131826Sharti			IE_SETPRESENT(conn->epref);
837131826Sharti			conn->epref.flag = 0;
838131826Sharti			conn->epref.epref = 0;
839131826Sharti		}
840131826Sharti
841131826Sharti		/*
842131826Sharti		 * Construct message to UNI.
843131826Sharti		 */
844131826Sharti		u = uni_msg_alloc(sizeof(struct uniapi_setup_request));
845131826Sharti		if (u == NULL) {
846131826Sharti			cc_user_sig(conn->user, USER_SIG_CONNECT_OUTGOING_ERR,
847131826Sharti			    NULL, ATMERR_NOMEM);
848131826Sharti			return;
849131826Sharti		}
850131826Sharti		setup = uni_msg_wptr(u, struct uniapi_setup_request *);
851131826Sharti		memset(setup, 0, sizeof(*setup));
852131826Sharti		u->b_wptr += sizeof(struct uniapi_setup_request);
853131826Sharti
854131826Sharti		setup->setup.hdr.act = UNI_MSGACT_DEFAULT;
855131826Sharti		memcpy(setup->setup.blli, conn->blli, sizeof(conn->blli));
856131826Sharti		setup->setup.bearer = conn->bearer;
857131826Sharti		setup->setup.traffic = conn->traffic;
858131826Sharti		setup->setup.qos = conn->qos;
859131826Sharti		setup->setup.exqos = conn->exqos;
860131826Sharti		setup->setup.called = conn->called;
861131826Sharti		setup->setup.calledsub[0] = conn->calledsub;
862131826Sharti		setup->setup.aal = conn->aal;
863131826Sharti		setup->setup.epref = conn->epref;
864131826Sharti		setup->setup.eetd = conn->eetd;
865131826Sharti		setup->setup.abrsetup = conn->abrsetup;
866131826Sharti		setup->setup.abradd = conn->abradd;
867131826Sharti		setup->setup.calling = conn->calling;
868131826Sharti		setup->setup.callingsub[0] = conn->callingsub;
869131826Sharti		setup->setup.connid = conn->connid;
870131826Sharti		memcpy(setup->setup.tns, conn->tns, sizeof(conn->tns));
871131826Sharti		setup->setup.atraffic = conn->atraffic;
872131826Sharti		setup->setup.mintraffic = conn->mintraffic;
873131826Sharti		setup->setup.cscope = conn->cscope;
874131826Sharti		setup->setup.bhli = conn->bhli;
875131826Sharti		setup->setup.mdcr = conn->mdcr;
876131826Sharti
877131826Sharti		cc_conn_set_state(conn, CONN_OUT_WAIT_CREATE);
878131826Sharti		cc_send_uni(conn, UNIAPI_SETUP_request, u);
879131826Sharti
880131826Sharti		break;
881131826Sharti	    }
882131826Sharti
883131826Sharti
884131826Sharti	  case CONN_SIG_ARRIVAL:
885131826Sharti		/* user informed of arrival of this call */
886131826Sharti		if (conn->state != CONN_IN_WAITING)
887131826Sharti			goto bad_state;
888131826Sharti		cc_conn_set_state(conn, CONN_IN_ARRIVED);
889131826Sharti		break;
890131826Sharti
891131826Sharti
892131826Sharti	  case CONN_SIG_RELEASE:
893131826Sharti	    {
894131826Sharti		/* Release this call */
895131826Sharti		struct uni_msg *u;
896131826Sharti		struct uniapi_release_request *req;
897131826Sharti
898131826Sharti		if (conn->state != CONN_ACTIVE &&
899131826Sharti		    conn->state != CONN_IN_WAIT_COMPL)
900131826Sharti			goto bad_state;
901131826Sharti
902131826Sharti		if ((u = uni_msg_alloc(sizeof(*req))) == NULL)
903131826Sharti			return;
904131826Sharti
905131826Sharti		req = uni_msg_wptr(u, struct uniapi_release_request *);
906131826Sharti		memset(req, 0, sizeof(*req));
907131826Sharti		u->b_wptr += sizeof(struct uniapi_release_request);
908131826Sharti
909131826Sharti		req->release.hdr.cref = conn->cref;
910131826Sharti		req->release.hdr.act = UNI_MSGACT_DEFAULT;
911131826Sharti
912131826Sharti		req->release.cause[0] = conn->cause[0];
913131826Sharti		req->release.cause[1] = conn->cause[1];
914131826Sharti
915131826Sharti		if (conn->state == CONN_ACTIVE)
916131826Sharti			cc_conn_set_state(conn, CONN_REL_WAIT_OK);
917131826Sharti		else
918131826Sharti			cc_conn_set_state(conn, CONN_REL_IN_WAIT_OK);
919131826Sharti
920131826Sharti		cc_send_uni(conn, UNIAPI_RELEASE_request, u);
921131826Sharti		break;
922131826Sharti	    }
923131826Sharti
924131826Sharti	  case CONN_SIG_REJECT:
925131826Sharti	    {
926131826Sharti		/* reject from user */
927131826Sharti		struct ccuser *user = conn->user;
928131826Sharti
929131826Sharti		if (conn->state != CONN_IN_ARRIVED) {
930131826Sharti			cc_user_sig(user, USER_SIG_REJECT_ERR,
931131826Sharti			    NULL, ATMERR_BAD_STATE);
932131826Sharti			break;
933131826Sharti		}
934131826Sharti		cc_conn_set_state(conn, CONN_REJ_WAIT_OK);
935131826Sharti		do_release_response(conn, 0, conn->cause);
936131826Sharti		break;
937131826Sharti	    }
938131826Sharti
939131826Sharti
940131826Sharti	  case CONN_SIG_ACCEPT:
941131826Sharti	    {
942131826Sharti		 /* User accepts. */
943131826Sharti    		struct ccuser *newep = arg;
944131826Sharti		struct uni_msg *u;
945131826Sharti		struct uniapi_setup_response *resp;
946131826Sharti		struct ccuser *user = conn->user;
947131826Sharti
948131826Sharti		if (conn->state != CONN_IN_ARRIVED) {
949131826Sharti			cc_user_sig(user, USER_SIG_ACCEPT_ERR,
950131826Sharti			    NULL, ATMERR_PREVIOUSLY_ABORTED);
951131826Sharti			break;
952131826Sharti		}
953131826Sharti
954131826Sharti		u = uni_msg_alloc(sizeof(struct uniapi_setup_response));
955131826Sharti		if (u == NULL) {
956131826Sharti			cc_user_sig(user, USER_SIG_ACCEPT_ERR,
957131826Sharti			    NULL, ATMERR_NOMEM);
958131826Sharti			return;
959131826Sharti		}
960131826Sharti
961131826Sharti		/*
962131826Sharti		 * Link to the new endpoint
963131826Sharti		 */
964131826Sharti		conn->acceptor = newep;
965131826Sharti		newep->accepted = conn;
966131826Sharti
967131826Sharti		/*
968131826Sharti		 * Construct connect message
969131826Sharti		 */
970131826Sharti		resp = uni_msg_wptr(u, struct uniapi_setup_response *);
971131826Sharti		memset(resp, 0, sizeof(*resp));
972131826Sharti		u->b_wptr += sizeof(*resp);
973131826Sharti
974131826Sharti		resp->connect.hdr.act = UNI_MSGACT_DEFAULT;
975131826Sharti		resp->connect.hdr.cref = conn->cref;
976131826Sharti
977131826Sharti		/*
978131826Sharti		 * attributes
979131826Sharti		 */
980213788Srpaulo		if (conn->dirty_attr & CCDIRTY_AAL)
981131826Sharti			resp->connect.aal = conn->aal;
982213788Srpaulo		if (conn->dirty_attr & CCDIRTY_BLLI)
983131826Sharti			resp->connect.blli =
984131826Sharti			    conn->blli[conn->blli_selector - 1];
985213788Srpaulo		if (conn->dirty_attr & CCDIRTY_CONNID)
986131826Sharti			resp->connect.connid = conn->connid;
987131826Sharti		/* XXX NOTIFY */
988213788Srpaulo		if (conn->dirty_attr & CCDIRTY_EETD)
989131826Sharti			resp->connect.eetd = conn->eetd;
990131826Sharti		/* XXX GIT */
991131826Sharti		/* XXX UU */
992213788Srpaulo		if (conn->dirty_attr & CCDIRTY_TRAFFIC)
993131826Sharti			resp->connect.traffic = conn->traffic;
994213788Srpaulo		if (conn->dirty_attr & CCDIRTY_EXQOS)
995131826Sharti			resp->connect.exqos = conn->exqos;
996213788Srpaulo		if (conn->dirty_attr & CCDIRTY_ABRSETUP)
997131826Sharti			resp->connect.abrsetup = conn->abrsetup;
998213788Srpaulo		if (conn->dirty_attr & CCDIRTY_ABRADD)
999131826Sharti			resp->connect.abradd = conn->abradd;
1000131826Sharti
1001131826Sharti		/*
1002131826Sharti		 * If the SETUP had an endpoint reference - echo it back
1003131826Sharti		 */
1004131826Sharti		if (IE_ISPRESENT(conn->epref)) {
1005131826Sharti			resp->connect.epref = conn->epref;
1006131826Sharti			resp->connect.epref.flag = !resp->connect.epref.flag;
1007131826Sharti		}
1008131826Sharti
1009131826Sharti		cc_conn_set_state(conn, CONN_IN_WAIT_ACCEPT_OK);
1010131826Sharti		cc_send_uni(conn, UNIAPI_SETUP_response, u);
1011131826Sharti		break;
1012131826Sharti	    }
1013131826Sharti
1014131826Sharti
1015131826Sharti	  case CONN_SIG_ADD_PARTY:
1016131826Sharti	    {
1017131826Sharti		/* request to add party from user */
1018131826Sharti		struct uni_msg *u;
1019131826Sharti		struct uniapi_add_party_request *req;
1020131826Sharti
1021131826Sharti		if (conn->state != CONN_ACTIVE)
1022131826Sharti			goto bad_state;
1023131826Sharti
1024131826Sharti		/* create the party */
1025131826Sharti		party = cc_party_create(conn, (u_int)(uintptr_t)arg, 0);
1026131826Sharti		if (party == NULL) {
1027131826Sharti			cc_user_sig(conn->user, USER_SIG_ADD_PARTY_ERR,
1028131826Sharti			    NULL, ATMERR_NOMEM);
1029131826Sharti			return;
1030131826Sharti		}
1031131826Sharti		party->called = conn->called;
1032131826Sharti
1033131826Sharti		/* Construct message to UNI. */
1034131826Sharti		u = uni_msg_alloc(sizeof(struct uniapi_setup_request));
1035131826Sharti		if (u == NULL) {
1036131826Sharti			cc_party_destroy(party);
1037131826Sharti			cc_user_sig(conn->user, USER_SIG_ADD_PARTY_ERR,
1038131826Sharti			    NULL, ATMERR_NOMEM);
1039131826Sharti			return;
1040131826Sharti		}
1041131826Sharti
1042131826Sharti		req = uni_msg_wptr(u, struct uniapi_add_party_request *);
1043131826Sharti		memset(req, 0, sizeof(*req));
1044131826Sharti		u->b_wptr += sizeof(struct uniapi_add_party_request);
1045131826Sharti
1046131826Sharti		req->add.hdr.act = UNI_MSGACT_DEFAULT;
1047131826Sharti		req->add.hdr.cref = conn->cref;
1048131826Sharti		req->add.epref = party->epref;
1049131826Sharti		req->add.called = party->called;
1050131826Sharti
1051131826Sharti		cc_party_set_state(party, PARTY_ADD_WAIT_CREATE);
1052131826Sharti		cc_send_uni(conn, UNIAPI_ADD_PARTY_request, u);
1053131826Sharti		break;
1054131826Sharti	    }
1055131826Sharti
1056131826Sharti
1057131826Sharti	  case CONN_SIG_DROP_PARTY:
1058131826Sharti	    {
1059131826Sharti		/* user request to drop a party */
1060131826Sharti		struct uni_msg *u;
1061131826Sharti		struct uniapi_drop_party_request *req;
1062131826Sharti
1063131826Sharti		if (conn->state != CONN_ACTIVE)
1064131826Sharti			goto bad_state;
1065131826Sharti
1066131826Sharti		party = cc_party_find(conn, (u_int)(uintptr_t)arg);
1067131826Sharti		if (party == NULL) {
1068131826Sharti			cc_user_sig(conn->user, USER_SIG_DROP_PARTY_ERR,
1069131826Sharti			    NULL, ATMERR_BAD_PARTY);
1070131826Sharti			return;
1071131826Sharti		}
1072131826Sharti
1073131826Sharti		switch (party->state) {
1074131826Sharti
1075131826Sharti		  case PARTY_ACTIVE:
1076131826Sharti		  case PARTY_ADD_WAIT_ACK:
1077131826Sharti			break;
1078131826Sharti
1079131826Sharti		  default:
1080131826Sharti			cc_user_sig(conn->user, USER_SIG_DROP_PARTY_ERR,
1081131826Sharti			    NULL, ATMERR_BAD_STATE);
1082131826Sharti			return;
1083131826Sharti
1084131826Sharti		}
1085131826Sharti		/*
1086131826Sharti		 * Construct message to UNI.
1087131826Sharti		 */
1088131826Sharti		u = uni_msg_alloc(sizeof(*req));
1089131826Sharti		if (u == NULL) {
1090131826Sharti			cc_user_sig(conn->user, USER_SIG_DROP_PARTY_ERR,
1091131826Sharti			    NULL, ATMERR_NOMEM);
1092131826Sharti			return;
1093131826Sharti		}
1094131826Sharti
1095131826Sharti		req = uni_msg_wptr(u, struct uniapi_drop_party_request *);
1096131826Sharti		memset(req, 0, sizeof(*req));
1097131826Sharti		u->b_wptr += sizeof(struct uniapi_drop_party_request);
1098131826Sharti
1099131826Sharti		req->drop.hdr.act = UNI_MSGACT_DEFAULT;
1100131826Sharti		req->drop.hdr.cref = conn->cref;
1101131826Sharti		req->drop.epref = party->epref;
1102131826Sharti		req->drop.cause = conn->cause[0];
1103131826Sharti
1104131826Sharti		if (party->state == PARTY_ACTIVE)
1105131826Sharti			cc_party_set_state(party, PARTY_DROP_WAIT_OK);
1106131826Sharti		else
1107131826Sharti			cc_party_set_state(party, PARTY_ADD_DROP_WAIT_OK);
1108131826Sharti		cc_send_uni(conn, UNIAPI_DROP_PARTY_request, u);
1109131826Sharti		break;
1110131826Sharti	    }
1111131826Sharti
1112131826Sharti	  case CONN_SIG_DROP_PARTY_ACK_IND:
1113131826Sharti	    {
1114131826Sharti		struct uni_msg *msg = arg;
1115131826Sharti		struct uniapi_drop_party_ack_indication *ind = uni_msg_rptr(msg,
1116131826Sharti		    struct uniapi_drop_party_ack_indication *);
1117131826Sharti
1118131826Sharti		cc_party_drop_ack_ind(conn, &ind->drop);
1119131826Sharti		break;
1120131826Sharti	    }
1121131826Sharti
1122131826Sharti
1123131826Sharti	  case CONN_SIG_USER_ABORT:
1124131826Sharti		/*
1125131826Sharti		 * Aborting a connection. This is callable in all states.
1126131826Sharti		 * The connection is already disconnected from the user.
1127131826Sharti		 * The cause is in cause[].
1128131826Sharti		 */
1129131826Sharti		switch (conn->state) {
1130131826Sharti
1131131826Sharti		  case CONN_NULL:		/* C0 */
1132131826Sharti		  case CONN_OUT_PREPARING:	/* C1 */
1133131826Sharti			cc_conn_destroy(conn);
1134131826Sharti			break;
1135131826Sharti
1136131826Sharti		  case CONN_OUT_WAIT_CONF:	/* C4 */
1137131826Sharti		  case CONN_ACTIVE:		/* C5 */
1138131826Sharti			do_release_request(conn, conn->cause);
1139131826Sharti			cc_conn_set_state(conn, CONN_AB_WAIT_REQ_OK);
1140131826Sharti			break;
1141131826Sharti
1142131826Sharti		  case CONN_IN_WAITING:		/* C21 */
1143131826Sharti			/* that should not happen */
1144131826Sharti			goto bad_state;
1145131826Sharti			break;
1146131826Sharti
1147131826Sharti		  case CONN_IN_ARRIVED:		/* C11 */
1148131826Sharti			/*
1149131826Sharti			 * This is called only for the first connection
1150131826Sharti			 * of the user - the others are re-dispatched.
1151131826Sharti			 */
1152131826Sharti			do_release_response(conn, 0, conn->cause);
1153131826Sharti			cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
1154131826Sharti			break;
1155131826Sharti
1156131826Sharti		  case CONN_IN_WAIT_COMPL:	/* C13 */
1157131826Sharti			do_release_request(conn, conn->cause);
1158131826Sharti			cc_conn_set_state(conn, CONN_AB_WAIT_REQ_OK);
1159131826Sharti			break;
1160131826Sharti
1161131826Sharti		  case CONN_OUT_WAIT_DESTROY:	/* C20 */
1162131826Sharti			cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1163131826Sharti			break;
1164131826Sharti
1165131826Sharti		  case CONN_IN_WAIT_ACCEPT_OK:	/* C12 */
1166131826Sharti		  case CONN_AB_WAIT_REQ_OK:	/* C33 */
1167131826Sharti		  case CONN_AB_WAIT_RESP_OK:	/* C34 */
1168131826Sharti		  case CONN_AB_FLUSH_IND:	/* C35 */
1169131826Sharti			/* just ignore */
1170131826Sharti			break;
1171131826Sharti
1172131826Sharti		/*
1173131826Sharti		 * The following states may not happen, because
1174131826Sharti		 * we're waiting for a response from the UNI stack.
1175131826Sharti		 * As soon as the response comes the ABORT is undefered
1176131826Sharti		 * and will hit us (but in another state).
1177131826Sharti		 */
1178131826Sharti		  case CONN_OUT_WAIT_CREATE:	/* C2 */
1179131826Sharti		  case CONN_OUT_WAIT_OK:	/* C3 */
1180131826Sharti		  case CONN_IN_PREPARING:	/* C10 */
1181131826Sharti		  case CONN_REJ_WAIT_OK:	/* C14 */
1182131826Sharti		  case CONN_REL_IN_WAIT_OK:	/* C15 */
1183131826Sharti		  case CONN_REL_WAIT_OK:	/* C20 */
1184131826Sharti			goto bad_state;
1185131826Sharti		}
1186131826Sharti		break;
1187131826Sharti
1188131826Sharti
1189131826Sharti	  case CONN_SIG_CREATED:
1190131826Sharti	    {
1191131826Sharti		/*
1192131826Sharti		 * CALL_CREATED message from UNI. This can happen for either
1193131826Sharti		 * incoming or outgoing connections.
1194131826Sharti		 */
1195131826Sharti		struct uni_msg *msg = arg;
1196131826Sharti		struct uniapi_call_created *cr = uni_msg_rptr(msg,
1197131826Sharti		    struct uniapi_call_created *);
1198131826Sharti
1199131826Sharti		switch (conn->state) {
1200131826Sharti
1201131826Sharti		  case CONN_OUT_WAIT_CREATE:
1202131826Sharti			conn->cref = cr->cref;
1203131826Sharti			cc_conn_set_state(conn, CONN_OUT_WAIT_OK);
1204131826Sharti			break;
1205131826Sharti
1206131826Sharti		  case CONN_NULL:
1207131826Sharti			conn->cref = cr->cref;
1208131826Sharti			cc_conn_set_state(conn, CONN_IN_PREPARING);
1209131826Sharti			break;
1210131826Sharti
1211131826Sharti		  default:
1212131826Sharti			goto bad_state;
1213131826Sharti		}
1214131826Sharti		break;
1215131826Sharti	    }
1216131826Sharti
1217131826Sharti	  case CONN_SIG_DESTROYED:
1218131826Sharti		/*
1219131826Sharti		 * CALL_DESTROYED message from UNI.
1220131826Sharti		 */
1221131826Sharti		switch (conn->state) {
1222131826Sharti
1223131826Sharti		  case CONN_OUT_WAIT_DESTROY:
1224131826Sharti			cc_conn_rem_port(conn);
1225131826Sharti			cc_conn_set_state(conn, CONN_OUT_PREPARING);
1226131826Sharti			if (conn->user != NULL)
1227131826Sharti				cc_user_sig(conn->user,
1228131826Sharti				    USER_SIG_CONNECT_OUTGOING_ERR,
1229131826Sharti				    NULL, ATM_MKUNIERR(conn->reason));
1230131826Sharti			break;
1231131826Sharti
1232131826Sharti		  case CONN_AB_FLUSH_IND:
1233131826Sharti			cc_conn_destroy(conn);
1234131826Sharti			break;
1235131826Sharti
1236131826Sharti		  case CONN_IN_PREPARING:
1237131826Sharti			cc_conn_destroy(conn);
1238131826Sharti			break;
1239131826Sharti
1240131826Sharti		  default:
1241131826Sharti			goto bad_state;
1242131826Sharti		}
1243131826Sharti		break;
1244131826Sharti
1245131826Sharti
1246131826Sharti	  case CONN_SIG_SETUP_CONFIRM:
1247131826Sharti		/* Setup confirm from the UNI. */
1248131826Sharti	    {
1249131826Sharti		struct uni_msg *msg = arg;
1250131826Sharti		struct uniapi_setup_confirm *conf = uni_msg_rptr(msg,
1251131826Sharti		    struct uniapi_setup_confirm *);
1252131826Sharti
1253131826Sharti		switch (conn->state) {
1254131826Sharti
1255131826Sharti		  case CONN_OUT_WAIT_CONF:
1256131826Sharti			/*
1257131826Sharti			 * Shuffle attributes and inform the user.
1258131826Sharti			 * Negotiable attributes are condititionally shuffled,
1259131826Sharti			 * because not returning it means accepting it
1260131826Sharti			 * (in case of blli the first instance of it).
1261131826Sharti			 * All others are shuffled unconditionally.
1262131826Sharti			 * Here we should also open the VCI in the driver. (XXX)
1263131826Sharti			 */
1264131826Sharti#define SHUFFLE(ATTR)	conn->ATTR = conf->connect.ATTR
1265131826Sharti#define COND_SHUFFLE(ATTR) if (IE_ISPRESENT(conf->connect.ATTR)) SHUFFLE(ATTR)
1266131826Sharti
1267131826Sharti			COND_SHUFFLE(aal);
1268131826Sharti			(void)memset(conn->blli + 1, 0,
1269131826Sharti			    sizeof(conn->blli) - sizeof(conn->blli[0]));
1270131826Sharti			if (IE_ISPRESENT(conf->connect.blli))
1271131826Sharti				conn->blli[0] = conf->connect.blli;
1272131826Sharti			conn->blli_selector = 1;
1273131826Sharti			COND_SHUFFLE(epref);
1274131826Sharti			SHUFFLE(conned);
1275131826Sharti			SHUFFLE(connedsub);
1276131826Sharti			SHUFFLE(eetd);
1277131826Sharti			COND_SHUFFLE(traffic);
1278131826Sharti			COND_SHUFFLE(exqos);
1279131826Sharti			COND_SHUFFLE(abrsetup);
1280131826Sharti			COND_SHUFFLE(abradd);
1281131826Sharti			COND_SHUFFLE(connid);
1282131826Sharti#undef SHUFFLE
1283131826Sharti#undef COND_SHUFFLE
1284131826Sharti			if (IE_ISGOOD(conn->epref))
1285131826Sharti				cc_party_setup_conf(conn);
1286131826Sharti
1287131826Sharti			cc_conn_set_state(conn, CONN_ACTIVE);
1288131826Sharti			cc_user_sig(conn->user, USER_SIG_SETUP_CONFIRM,
1289131826Sharti			    NULL, 0);
1290131826Sharti			break;
1291131826Sharti
1292131826Sharti		  case CONN_AB_FLUSH_IND:
1293131826Sharti		  case CONN_AB_WAIT_RESP_OK:
1294131826Sharti			break;
1295131826Sharti
1296131826Sharti		  default:
1297131826Sharti			goto bad_state;
1298131826Sharti		}
1299131826Sharti		break;
1300131826Sharti	    }
1301131826Sharti
1302131826Sharti	  case CONN_SIG_SETUP_IND:
1303131826Sharti	    {
1304131826Sharti		/* SETUP indication */
1305131826Sharti		struct uni_msg *msg = arg;
1306131826Sharti		struct uniapi_setup_indication *ind = uni_msg_rptr(msg,
1307131826Sharti		    struct uniapi_setup_indication *);
1308131826Sharti		u_int i;
1309131826Sharti
1310131826Sharti		if (conn->state != CONN_IN_PREPARING)
1311131826Sharti			goto bad_state;
1312131826Sharti
1313131826Sharti		/*
1314131826Sharti		 * Shuffle information elements.
1315131826Sharti		 */
1316131826Sharti		for (i = 0; i < UNI_NUM_IE_BLLI; i++)
1317131826Sharti			conn->blli[i] = ind->setup.blli[i];
1318131826Sharti		conn->bearer = ind->setup.bearer;
1319131826Sharti		conn->traffic = ind->setup.traffic;
1320131826Sharti		conn->qos = ind->setup.qos;
1321131826Sharti		conn->exqos = ind->setup.exqos;
1322131826Sharti		conn->called = ind->setup.called;
1323131826Sharti		conn->calledsub = ind->setup.calledsub[0];
1324131826Sharti		conn->aal = ind->setup.aal;
1325131826Sharti		conn->epref = ind->setup.epref;
1326131826Sharti		conn->eetd = ind->setup.eetd;
1327131826Sharti		conn->abrsetup = ind->setup.abrsetup;
1328131826Sharti		conn->abradd = ind->setup.abradd;
1329131826Sharti		conn->calling = ind->setup.calling;
1330131826Sharti		conn->callingsub = ind->setup.callingsub[0];
1331131826Sharti		conn->connid = ind->setup.connid;
1332131826Sharti		for (i = 0; i < UNI_NUM_IE_TNS; i++)
1333131826Sharti			conn->tns[i] = ind->setup.tns[i];
1334131826Sharti		conn->atraffic = ind->setup.atraffic;
1335131826Sharti		conn->mintraffic = ind->setup.mintraffic;
1336131826Sharti		conn->cscope = ind->setup.cscope;
1337131826Sharti		conn->bhli = ind->setup.bhli;
1338131826Sharti		conn->mdcr = ind->setup.mdcr;
1339131826Sharti
1340131826Sharti		cc_conn_dispatch(conn);
1341131826Sharti		break;
1342131826Sharti	    }
1343131826Sharti
1344131826Sharti
1345131826Sharti	  case CONN_SIG_SETUP_COMPL:
1346131826Sharti	    {
1347131826Sharti		struct uni_msg *msg = arg;
1348131826Sharti		struct uniapi_setup_indication *ind __unused =
1349131826Sharti		    uni_msg_rptr(msg, struct uniapi_setup_indication *);
1350131826Sharti
1351131826Sharti		/* SETUP_COMPLETE.indication from UNI */
1352131826Sharti		if (conn->state == CONN_AB_FLUSH_IND ||
1353131826Sharti		    conn->state == CONN_AB_WAIT_RESP_OK)
1354131826Sharti			break;
1355131826Sharti
1356131826Sharti		if (conn->state != CONN_IN_WAIT_COMPL)
1357131826Sharti			goto bad_state;
1358131826Sharti
1359131826Sharti		cc_conn_set_state(conn, CONN_ACTIVE);
1360131826Sharti
1361131826Sharti		LIST_FOREACH(party, &conn->parties, link) {
1362131826Sharti			if (party->state == PARTY_WAIT_SETUP_COMPL)
1363131826Sharti				cc_party_set_state(party, PARTY_ACTIVE);
1364131826Sharti			else
1365131826Sharti				cc_party_log(party, "bad state=%s for sig=%s",
1366131826Sharti				    ptab[party->state],
1367131826Sharti				    cc_conn_sigtab[CONN_SIG_SETUP_COMPL]);
1368131826Sharti		}
1369131826Sharti
1370131826Sharti		cc_user_sig(conn->user, USER_SIG_SETUP_COMPL, NULL, 0);
1371131826Sharti		break;
1372131826Sharti	    }
1373131826Sharti
1374131826Sharti
1375131826Sharti	  case CONN_SIG_PROC_IND:
1376131826Sharti	    {
1377131826Sharti		/*
1378131826Sharti		 * ALERTING.indication and PROCEEDING.indication are entirly
1379131826Sharti		 * ignored by the specification. We need to at least save the
1380131826Sharti		 * connid information element.
1381131826Sharti		 */
1382131826Sharti		struct uni_msg *msg = arg;
1383131826Sharti		struct uniapi_proceeding_indication *ind = uni_msg_rptr(msg,
1384131826Sharti		    struct uniapi_proceeding_indication *);
1385131826Sharti
1386131826Sharti		switch (conn->state) {
1387131826Sharti
1388131826Sharti		  case CONN_OUT_WAIT_CONF:
1389131826Sharti			if (IE_ISGOOD(ind->call_proc.connid))
1390131826Sharti				conn->connid = ind->call_proc.connid;
1391131826Sharti			break;
1392131826Sharti
1393131826Sharti		  case CONN_AB_FLUSH_IND:
1394131826Sharti		  case CONN_AB_WAIT_RESP_OK:
1395131826Sharti			break;
1396131826Sharti
1397131826Sharti		  default:
1398131826Sharti			goto bad_state;
1399131826Sharti		}
1400131826Sharti		break;
1401131826Sharti	    }
1402131826Sharti
1403131826Sharti	  case CONN_SIG_ALERTING_IND:
1404131826Sharti	    {
1405131826Sharti		struct uni_msg *msg = arg;
1406131826Sharti		struct uniapi_alerting_indication *ind = uni_msg_rptr(msg,
1407131826Sharti		    struct uniapi_alerting_indication *);
1408131826Sharti
1409131826Sharti		switch (conn->state) {
1410131826Sharti
1411131826Sharti		  case CONN_OUT_WAIT_CONF:
1412131826Sharti			if (IE_ISGOOD(ind->alerting.connid))
1413131826Sharti				conn->connid = ind->alerting.connid;
1414131826Sharti			break;
1415131826Sharti
1416131826Sharti		  case CONN_AB_FLUSH_IND:
1417131826Sharti		  case CONN_AB_WAIT_RESP_OK:
1418131826Sharti			break;
1419131826Sharti
1420131826Sharti		  default:
1421131826Sharti			goto bad_state;
1422131826Sharti		}
1423131826Sharti		break;
1424131826Sharti	  }
1425131826Sharti
1426131826Sharti	  case CONN_SIG_REL_CONF:
1427131826Sharti	    {
1428131826Sharti		/* RELEASE.confirm from UNI */
1429131826Sharti		struct uni_msg *msg = arg;
1430131826Sharti		struct uniapi_release_confirm *conf = uni_msg_rptr(msg,
1431131826Sharti		    struct uniapi_release_confirm *);
1432131826Sharti
1433131826Sharti		switch (conn->state) {
1434131826Sharti
1435131826Sharti		  case CONN_OUT_WAIT_CONF:
1436131826Sharti		  case CONN_ACTIVE:
1437131826Sharti			cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1438131826Sharti			memcpy(conn->user->cause, conf->release.cause,
1439131826Sharti			    sizeof(conn->user->cause));
1440131826Sharti			/*
1441131826Sharti			 * If any party is in P6, ok the user
1442131826Sharti			 */
1443131826Sharti			LIST_FOREACH(party, &conn->parties, link) {
1444131826Sharti				if (party->state == PARTY_DROP_WAIT_ACK) {
1445131826Sharti					cc_party_set_state(party,
1446131826Sharti					    PARTY_WAIT_DESTROY);
1447131826Sharti					cc_user_sig(conn->user,
1448131826Sharti					    USER_SIG_DROP_PARTY_OK,
1449131826Sharti					    NULL, party->epref.epref);
1450131826Sharti				}
1451131826Sharti			}
1452131826Sharti			cc_user_sig(conn->user, USER_SIG_RELEASE_CONFIRM,
1453131826Sharti			    NULL, 0);
1454131826Sharti			cc_disconnect_from_user(conn);
1455131826Sharti			break;
1456131826Sharti
1457131826Sharti		  case CONN_AB_FLUSH_IND:
1458131826Sharti		  case CONN_AB_WAIT_RESP_OK:
1459131826Sharti			break;
1460131826Sharti
1461131826Sharti		  case CONN_IN_WAITING:
1462131826Sharti			cc_disconnect_from_user(conn);
1463131826Sharti			cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1464131826Sharti			break;
1465131826Sharti
1466131826Sharti		  case CONN_IN_ARRIVED:
1467131826Sharti			conn->user->aborted = 1;
1468131826Sharti			memcpy(conn->user->cause, conf->release.cause,
1469131826Sharti			    sizeof(conn->user->cause));
1470131826Sharti			cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1471131826Sharti			cc_disconnect_from_user(conn);
1472131826Sharti			break;
1473131826Sharti
1474131826Sharti		  case CONN_IN_WAIT_COMPL:
1475131826Sharti			cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1476131826Sharti			memcpy(conn->user->cause, conf->release.cause,
1477131826Sharti			    sizeof(conn->user->cause));
1478131826Sharti			cc_user_sig(conn->user, USER_SIG_RELEASE_CONFIRM,
1479131826Sharti			    NULL, 0);
1480131826Sharti			cc_disconnect_from_user(conn);
1481131826Sharti			break;
1482131826Sharti
1483131826Sharti		  default:
1484131826Sharti			goto bad_state;
1485131826Sharti		}
1486131826Sharti		break;
1487131826Sharti	    }
1488131826Sharti
1489131826Sharti	  case CONN_SIG_REL_IND:
1490131826Sharti	    {
1491131826Sharti		/* RELEASE.ind from UNI */
1492131826Sharti		struct uni_msg *msg = arg;
1493131826Sharti		struct uniapi_release_indication *conf = uni_msg_rptr(msg,
1494131826Sharti		    struct uniapi_release_indication *);
1495131826Sharti
1496131826Sharti		switch (conn->state) {
1497131826Sharti
1498131826Sharti		  case CONN_OUT_WAIT_CONF:
1499131826Sharti		  case CONN_ACTIVE:
1500131826Sharti			do_release_response(conn, 0, NULL);
1501131826Sharti			cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
1502131826Sharti			memcpy(conn->user->cause, conf->release.cause,
1503131826Sharti			    sizeof(conn->user->cause));
1504131826Sharti			/*
1505131826Sharti			 * If any party is in P6, ok the user
1506131826Sharti			 */
1507131826Sharti			LIST_FOREACH(party, &conn->parties, link) {
1508131826Sharti				if (party->state == PARTY_DROP_WAIT_ACK) {
1509131826Sharti					cc_party_set_state(party,
1510131826Sharti					    PARTY_WAIT_DESTROY);
1511131826Sharti					cc_user_sig(conn->user,
1512131826Sharti					    USER_SIG_DROP_PARTY_OK,
1513131826Sharti					    NULL, party->epref.epref);
1514131826Sharti				}
1515131826Sharti			}
1516131826Sharti			cc_user_sig(conn->user, USER_SIG_RELEASE_CONFIRM,
1517131826Sharti			    NULL, 0);
1518131826Sharti			cc_disconnect_from_user(conn);
1519131826Sharti			break;
1520131826Sharti
1521131826Sharti		  case CONN_AB_FLUSH_IND:
1522131826Sharti		  case CONN_AB_WAIT_RESP_OK:
1523131826Sharti			break;
1524131826Sharti
1525131826Sharti		  case CONN_IN_WAITING:
1526131826Sharti			cc_disconnect_from_user(conn);
1527131826Sharti			do_release_response(conn, 0, NULL);
1528131826Sharti			cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
1529131826Sharti			break;
1530131826Sharti
1531131826Sharti		  case CONN_IN_ARRIVED:
1532131826Sharti			conn->user->aborted = 1;
1533131826Sharti			cc_disconnect_from_user(conn);
1534131826Sharti			do_release_response(conn, 0, NULL);
1535131826Sharti			cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
1536131826Sharti			break;
1537131826Sharti
1538131826Sharti		  case CONN_IN_WAIT_COMPL:
1539131826Sharti			do_release_response(conn, 0, NULL);
1540131826Sharti			cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
1541131826Sharti			memcpy(conn->user->cause, conf->release.cause,
1542131826Sharti			    sizeof(conn->user->cause));
1543131826Sharti			cc_user_sig(conn->user, USER_SIG_RELEASE_CONFIRM,
1544131826Sharti			    NULL, 0);
1545131826Sharti			cc_disconnect_from_user(conn);
1546131826Sharti			break;
1547131826Sharti		  default:
1548131826Sharti			goto bad_state;
1549131826Sharti			break;
1550131826Sharti		}
1551131826Sharti		break;
1552131826Sharti	    }
1553131826Sharti
1554131826Sharti	  case CONN_SIG_PARTY_ALERTING_IND:
1555131826Sharti		/* party alerting from UNI */
1556131826Sharti		if (conn->state == CONN_AB_FLUSH_IND)
1557131826Sharti			break;
1558131826Sharti		if (conn->state != CONN_ACTIVE)
1559131826Sharti			goto bad_state;
1560131826Sharti		/* ignore */
1561131826Sharti		break;
1562131826Sharti
1563131826Sharti	  case CONN_SIG_PARTY_ADD_ACK_IND:
1564131826Sharti	    {
1565131826Sharti		/* ADD PARTY ACKNOWLEDGE from UNI */
1566131826Sharti		struct uni_msg *msg = arg;
1567131826Sharti		struct uniapi_add_party_ack_indication *ind = uni_msg_rptr(msg,
1568131826Sharti		    struct uniapi_add_party_ack_indication *);
1569131826Sharti
1570131826Sharti		if (conn->state == CONN_AB_FLUSH_IND)
1571131826Sharti			break;
1572131826Sharti		if (conn->state != CONN_ACTIVE)
1573131826Sharti			goto bad_state;
1574131826Sharti
1575131826Sharti		cc_party_add_ack_ind(conn, &ind->ack.epref);
1576131826Sharti		break;
1577131826Sharti	    }
1578131826Sharti
1579131826Sharti
1580131826Sharti	 case CONN_SIG_PARTY_ADD_REJ_IND:
1581131826Sharti	    {
1582131826Sharti		/* ADD PARTY REJECT indication */
1583131826Sharti		struct uni_msg *msg = arg;
1584131826Sharti		struct uniapi_add_party_rej_indication *ind = uni_msg_rptr(msg,
1585131826Sharti		    struct uniapi_add_party_rej_indication *);
1586131826Sharti
1587131826Sharti		if (conn->state == CONN_AB_FLUSH_IND)
1588131826Sharti			break;
1589131826Sharti		if (conn->state != CONN_ACTIVE)
1590131826Sharti			goto bad_state;
1591131826Sharti
1592131826Sharti		memset(&conn->user->cause[1], 0, sizeof(conn->user->cause[1]));
1593131826Sharti		conn->user->cause[0] = ind->rej.cause;
1594131826Sharti
1595131826Sharti		cc_party_add_rej_ind(conn, &ind->rej.epref);
1596131826Sharti		break;
1597131826Sharti	    }
1598131826Sharti
1599131826Sharti
1600131826Sharti	  case CONN_SIG_DROP_PARTY_IND:
1601131826Sharti	    {
1602131826Sharti		/* DROP_PARTY.indication from UNI */
1603131826Sharti		struct uni_msg *msg = arg;
1604131826Sharti		struct uniapi_drop_party_indication *ind = uni_msg_rptr(msg,
1605131826Sharti		    struct uniapi_drop_party_indication *);
1606131826Sharti		struct uniapi_drop_party_ack_request *req;
1607131826Sharti		struct uni_msg *u;
1608131826Sharti
1609131826Sharti		if (conn->state == CONN_AB_FLUSH_IND)
1610131826Sharti			break;
1611131826Sharti		if (conn->state != CONN_ACTIVE)
1612131826Sharti			goto bad_state;
1613131826Sharti
1614131826Sharti		party = cc_party_find(conn, ind->drop.epref.epref);
1615131826Sharti		if (party == NULL) {
1616131826Sharti			cc_party_log(party, "no party for %s",
1617131826Sharti			    cc_conn_sigtab[sig]);
1618131826Sharti			break;
1619131826Sharti		}
1620131826Sharti
1621131826Sharti		u = uni_msg_alloc(sizeof(*req));
1622131826Sharti		if (u == NULL)
1623131826Sharti			return;
1624131826Sharti
1625131826Sharti		memset(&conn->user->cause[1], 0, sizeof(conn->user->cause[1]));
1626131826Sharti		conn->user->cause[0] = ind->drop.cause;
1627131826Sharti
1628131826Sharti		switch (party->state) {
1629131826Sharti
1630131826Sharti		  default:
1631131826Sharti			cc_party_log(party, "bad state %s for DROP.ind",
1632131826Sharti			    ptab[party->state]);
1633131826Sharti			/* FALLTHRU */
1634131826Sharti
1635131826Sharti		  case PARTY_ACTIVE:		/* P1 -> P9 */
1636131826Sharti			cc_party_set_state(party, PARTY_WAIT_DROP_ACK_OK);
1637131826Sharti			break;
1638131826Sharti
1639131826Sharti		  case PARTY_ADD_WAIT_ACK:	/* P4 -> P12 */
1640131826Sharti			cc_party_set_state(party, PARTY_ADD_DROPACK_WAIT_OK);
1641131826Sharti			break;
1642131826Sharti		}
1643131826Sharti
1644131826Sharti		/*
1645131826Sharti		 * Construct message to UNI.
1646131826Sharti		 */
1647131826Sharti		req = uni_msg_wptr(u, struct uniapi_drop_party_ack_request *);
1648131826Sharti		memset(req, 0, sizeof(*req));
1649131826Sharti		u->b_wptr += sizeof(*req);
1650131826Sharti
1651131826Sharti		IE_SETPRESENT(req->ack.epref);
1652131826Sharti		req->ack.hdr.act = UNI_MSGACT_DEFAULT;
1653131826Sharti		req->ack.hdr.cref = conn->cref;
1654131826Sharti
1655131826Sharti		req->ack.epref.flag = 0;
1656131826Sharti		req->ack.epref.epref = ind->drop.epref.epref;
1657131826Sharti
1658131826Sharti		cc_send_uni(conn, UNIAPI_DROP_PARTY_ACK_request, u);
1659131826Sharti		break;
1660131826Sharti	    }
1661131826Sharti
1662131826Sharti	  case CONN_SIG_OK:
1663131826Sharti	    {
1664131826Sharti 		/* OK response from UNI */
1665131826Sharti		struct ccuser *user = conn->user;
1666131826Sharti
1667131826Sharti		switch (conn->state) {
1668131826Sharti
1669131826Sharti		  case CONN_OUT_WAIT_OK:		/* C3 */
1670131826Sharti			cc_conn_set_state(conn, CONN_OUT_WAIT_CONF);
1671131826Sharti			if (conn->user != NULL)
1672131826Sharti				cc_user_sig(conn->user,
1673131826Sharti				    USER_SIG_CONNECT_OUTGOING_OK, NULL, 0);
1674131826Sharti			break;
1675131826Sharti
1676131826Sharti		  case CONN_AB_WAIT_RESP_OK:		/* C33 */
1677131826Sharti		  case CONN_AB_WAIT_REQ_OK:		/* C34 */
1678131826Sharti			cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1679131826Sharti			break;
1680131826Sharti
1681131826Sharti		  case CONN_REL_WAIT_OK:		/* C20 */
1682131826Sharti		  case CONN_REL_IN_WAIT_OK:		/* C15 */
1683131826Sharti			cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1684131826Sharti			if (conn->user != NULL) {
1685131826Sharti				/* connection has not been aborted */
1686131826Sharti				memset(&conn->user->cause, 0,
1687131826Sharti				    sizeof(conn->user->cause));
1688131826Sharti				cc_user_sig(conn->user,
1689131826Sharti				    USER_SIG_RELEASE_CONFIRM, NULL, 0);
1690131826Sharti				cc_disconnect_from_user(conn);
1691131826Sharti			}
1692131826Sharti			break;
1693131826Sharti
1694131826Sharti		  case CONN_IN_WAIT_ACCEPT_OK:		/* C12 */
1695131826Sharti			if (user == NULL) {
1696131826Sharti				/* has been aborted */
1697131826Sharti				do_release_request(conn, NULL);
1698131826Sharti				cc_conn_set_state(conn, CONN_AB_WAIT_REQ_OK);
1699131826Sharti				break;
1700131826Sharti			}
1701131826Sharti			cc_conn_set_state(conn, CONN_IN_WAIT_COMPL);
1702131826Sharti			cc_disconnect_from_user(conn);
1703131826Sharti			cc_user_sig(user, USER_SIG_ACCEPT_OK, NULL, 0);
1704131826Sharti			if (conn->acceptor == NULL) {
1705131826Sharti				do_release_request(conn, NULL);
1706131826Sharti				cc_conn_set_state(conn, CONN_AB_WAIT_REQ_OK);
1707131826Sharti				break;
1708131826Sharti			}
1709131826Sharti			cc_connect_to_user(conn, conn->acceptor);
1710131826Sharti			cc_conn_reset_acceptor(conn);
1711131826Sharti			cc_user_sig(conn->user, USER_SIG_ACCEPTING, NULL, 0);
1712131826Sharti			break;
1713131826Sharti
1714131826Sharti		  case CONN_REJ_WAIT_OK:		/* C14 */
1715131826Sharti			cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1716131826Sharti			if (user != NULL) {
1717131826Sharti				cc_disconnect_from_user(conn);
1718131826Sharti				cc_user_sig(user, USER_SIG_REJECT_OK, NULL, 0);
1719131826Sharti			}
1720131826Sharti			break;
1721131826Sharti
1722131826Sharti		  default:
1723131826Sharti			/* maybe it's for a party */
1724131826Sharti			LIST_FOREACH(party, &conn->parties, link) {
1725131826Sharti				switch (party->state) {
1726131826Sharti
1727131826Sharti				  case PARTY_ADD_WAIT_OK:	/* P3 */
1728131826Sharti					if (user != NULL)
1729131826Sharti						cc_user_sig(user,
1730131826Sharti						    USER_SIG_ADD_PARTY_OK,
1731131826Sharti						    NULL, 0);
1732131826Sharti					cc_party_set_state(party,
1733131826Sharti					    PARTY_ADD_WAIT_ACK);
1734131826Sharti					goto ex_party_ok;
1735131826Sharti
1736131826Sharti				  case PARTY_DROP_WAIT_OK:	/* P5 */
1737131826Sharti					cc_party_set_state(party,
1738131826Sharti					    PARTY_DROP_WAIT_ACK);
1739131826Sharti					goto ex_party_ok;
1740131826Sharti
1741131826Sharti				  case PARTY_WAIT_DROP_ACK_OK:	/* P9 */
1742131826Sharti				  case PARTY_ADD_DROPACK_WAIT_OK:/* P12 */
1743131826Sharti				     {
1744131826Sharti					struct ccparty *p1;
1745131826Sharti
1746131826Sharti					cc_party_set_state(party,
1747131826Sharti					    PARTY_WAIT_DESTROY);
1748131826Sharti					/* signal to user only if there are any other parties */
1749131826Sharti					LIST_FOREACH(p1, &conn->parties, link)
1750131826Sharti						if (p1 != party)
1751131826Sharti							break;
1752131826Sharti					if (p1 != NULL && user != NULL)
1753131826Sharti						cc_user_sig(user,
1754131826Sharti						    USER_SIG_DROP_PARTY_IND,
1755131826Sharti						    NULL,
1756131826Sharti						    party->epref.epref);
1757131826Sharti
1758131826Sharti					goto ex_party_ok;
1759131826Sharti				    }
1760131826Sharti
1761131826Sharti				  case PARTY_ADD_DROP_WAIT_OK:	/* P11 */
1762131826Sharti					cc_party_set_state(party,
1763131826Sharti					    PARTY_DROP_WAIT_ACK);
1764131826Sharti					goto ex_party_ok;
1765131826Sharti
1766131826Sharti				  default:
1767131826Sharti					break;
1768131826Sharti				}
1769131826Sharti			}
1770131826Sharti			goto bad_state;
1771131826Sharti		    ex_party_ok:
1772131826Sharti			break;
1773131826Sharti		}
1774131826Sharti		break;
1775131826Sharti	    }
1776131826Sharti
1777131826Sharti	  case CONN_SIG_ERROR:
1778131826Sharti	    {
1779131826Sharti		/* error response from UNI */
1780131826Sharti		u_int reason = (iarg >> 16) & 0xffff;
1781131826Sharti		u_int state = iarg & 0xffff;
1782131826Sharti		struct ccuser *user = conn->user;
1783131826Sharti
1784131826Sharti		switch (conn->state) {
1785131826Sharti
1786131826Sharti		  case CONN_OUT_WAIT_CREATE:		/* C2 */
1787131826Sharti			cc_conn_rem_port(conn);
1788131826Sharti			cc_conn_set_state(conn, CONN_OUT_PREPARING);
1789131826Sharti			if (conn->user != NULL)
1790131826Sharti				cc_user_sig(conn->user,
1791131826Sharti				    USER_SIG_CONNECT_OUTGOING_ERR,
1792131826Sharti				    NULL, ATM_MKUNIERR(reason));
1793131826Sharti			break;
1794131826Sharti
1795131826Sharti		  case CONN_OUT_WAIT_OK:		/* C3 */
1796131826Sharti			cc_conn_set_state(conn, CONN_OUT_WAIT_DESTROY);
1797131826Sharti			conn->reason = reason;
1798131826Sharti			break;
1799131826Sharti
1800131826Sharti		  case CONN_AB_WAIT_REQ_OK:		/* C33 */
1801131826Sharti			if (state == UNI_CALLSTATE_U12) {
1802131826Sharti				do_release_response(conn, 0, conn->cause);
1803131826Sharti				cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
1804131826Sharti				break;
1805131826Sharti			}
1806131826Sharti			cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1807131826Sharti			break;
1808131826Sharti
1809131826Sharti		  case CONN_AB_WAIT_RESP_OK:		/* C34 */
1810131826Sharti			cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1811131826Sharti			break;
1812131826Sharti
1813131826Sharti		  case CONN_REL_WAIT_OK:		/* C20 */
1814131826Sharti			if (user == NULL) {
1815131826Sharti				/* connection has been aborted. */
1816131826Sharti				if (state == UNI_CALLSTATE_U10) {
1817131826Sharti					/* do what we can */
1818131826Sharti					do_release_request(conn, conn->cause);
1819131826Sharti					cc_conn_set_state(conn,
1820131826Sharti					    CONN_AB_WAIT_REQ_OK);
1821131826Sharti				} else if (state == UNI_CALLSTATE_U12) {
1822131826Sharti					do_release_response(conn, 0, NULL);
1823131826Sharti					cc_conn_set_state(conn,
1824131826Sharti					    CONN_AB_WAIT_RESP_OK);
1825131826Sharti				} else {
1826131826Sharti					cc_conn_set_state(conn,
1827131826Sharti					    CONN_AB_FLUSH_IND);
1828131826Sharti				}
1829131826Sharti				break;
1830131826Sharti			}
1831131826Sharti			if (state == UNI_CALLSTATE_U10) {
1832131826Sharti				cc_conn_set_state(conn, CONN_ACTIVE);
1833131826Sharti				cc_user_sig(conn->user, USER_SIG_RELEASE_ERR,
1834131826Sharti				    NULL, reason);
1835131826Sharti			} else if (state == UNI_CALLSTATE_U12) {
1836131826Sharti				do_release_response(conn, 0, NULL);
1837131826Sharti				cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
1838131826Sharti				memset(&conn->user->cause, 0,
1839131826Sharti				    sizeof(conn->user->cause));
1840131826Sharti				cc_user_sig(conn->user,
1841131826Sharti				    USER_SIG_RELEASE_CONFIRM, NULL, 0);
1842131826Sharti				cc_disconnect_from_user(conn);
1843131826Sharti			} else {
1844131826Sharti				cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1845131826Sharti				memset(&conn->user->cause, 0,
1846131826Sharti				    sizeof(conn->user->cause));
1847131826Sharti				cc_user_sig(conn->user,
1848131826Sharti				    USER_SIG_RELEASE_CONFIRM, NULL, 0);
1849131826Sharti				cc_disconnect_from_user(conn);
1850131826Sharti			}
1851131826Sharti			break;
1852131826Sharti
1853131826Sharti		  case CONN_IN_WAIT_ACCEPT_OK:		/* C12 */
1854131826Sharti			if (user == NULL) {
1855131826Sharti				/* connection was aborted */
1856131826Sharti				if (state == UNI_CALLSTATE_U6 ||
1857131826Sharti				    state == UNI_CALLSTATE_U7 ||
1858131826Sharti				    state == UNI_CALLSTATE_U9 ||
1859131826Sharti				    state == UNI_CALLSTATE_U12) {
1860131826Sharti					do_release_response(conn, 0, NULL);
1861131826Sharti					cc_conn_set_state(conn,
1862131826Sharti					    CONN_AB_WAIT_RESP_OK);
1863131826Sharti				} else {
1864131826Sharti					cc_conn_set_state(conn,
1865131826Sharti					    CONN_AB_FLUSH_IND);
1866131826Sharti				}
1867131826Sharti				break;
1868131826Sharti			}
1869131826Sharti			cc_conn_reset_acceptor(conn);
1870131826Sharti			if (state == UNI_CALLSTATE_U6 ||
1871131826Sharti			    state == UNI_CALLSTATE_U9 ||
1872131826Sharti			    state == UNI_CALLSTATE_U7) {
1873131826Sharti				cc_user_sig(user, USER_SIG_ACCEPT_ERR,
1874131826Sharti				    NULL, ATM_MKUNIERR(reason));
1875131826Sharti				cc_conn_set_state(conn, CONN_IN_ARRIVED);
1876131826Sharti			} else if (state == UNI_CALLSTATE_U12) {
1877131826Sharti				do_release_response(conn, 0, NULL);
1878131826Sharti				cc_disconnect_from_user(conn);
1879131826Sharti				cc_user_sig(user, USER_SIG_ACCEPT_ERR,
1880131826Sharti				    user, ATMERR_PREVIOUSLY_ABORTED);
1881131826Sharti				cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
1882131826Sharti			} else {
1883131826Sharti				cc_disconnect_from_user(conn);
1884131826Sharti				cc_user_sig(user, USER_SIG_ACCEPT_ERR,
1885131826Sharti				    user, ATMERR_PREVIOUSLY_ABORTED);
1886131826Sharti				cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1887131826Sharti			}
1888131826Sharti			break;
1889131826Sharti
1890131826Sharti		  case CONN_REJ_WAIT_OK:		/* C14 */
1891131826Sharti			if (user == NULL) {
1892131826Sharti				/* connection has been aborted. */
1893131826Sharti				if (state == UNI_CALLSTATE_U6 ||
1894131826Sharti				    state == UNI_CALLSTATE_U7 ||
1895131826Sharti				    state == UNI_CALLSTATE_U9 ||
1896131826Sharti				    state == UNI_CALLSTATE_U12) {
1897131826Sharti					/* do what we can */
1898131826Sharti					do_release_response(conn, 0, NULL);
1899131826Sharti					cc_conn_set_state(conn,
1900131826Sharti					    CONN_AB_WAIT_RESP_OK);
1901131826Sharti				} else {
1902131826Sharti					cc_conn_set_state(conn,
1903131826Sharti					    CONN_AB_FLUSH_IND);
1904131826Sharti				}
1905131826Sharti				break;
1906131826Sharti			}
1907131826Sharti			if (state == UNI_CALLSTATE_U6 ||
1908131826Sharti			    state == UNI_CALLSTATE_U9 ||
1909131826Sharti			    state == UNI_CALLSTATE_U7) {
1910131826Sharti				cc_user_sig(user, USER_SIG_REJECT_ERR,
1911131826Sharti				    NULL, ATM_MKUNIERR(reason));
1912131826Sharti				cc_conn_set_state(conn, CONN_IN_ARRIVED);
1913131826Sharti			} else {
1914131826Sharti				cc_disconnect_from_user(conn);
1915131826Sharti				cc_user_sig(user, USER_SIG_REJECT_OK, NULL, 0);
1916131826Sharti				cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1917131826Sharti			}
1918131826Sharti			break;
1919131826Sharti
1920131826Sharti		  case CONN_REL_IN_WAIT_OK:		/* C15 */
1921131826Sharti			if (user == NULL) {
1922131826Sharti				/* connection has been aborted. */
1923131826Sharti				if (state == UNI_CALLSTATE_U8) {
1924131826Sharti					/* do what we can */
1925131826Sharti					do_release_request(conn, conn->cause);
1926131826Sharti					cc_conn_set_state(conn,
1927131826Sharti					    CONN_AB_WAIT_REQ_OK);
1928131826Sharti				} else if (state == UNI_CALLSTATE_U12) {
1929131826Sharti					do_release_response(conn, 0, NULL);
1930131826Sharti					cc_conn_set_state(conn,
1931131826Sharti					    CONN_AB_WAIT_RESP_OK);
1932131826Sharti				} else {
1933131826Sharti					cc_conn_set_state(conn,
1934131826Sharti					    CONN_AB_FLUSH_IND);
1935131826Sharti				}
1936131826Sharti				break;
1937131826Sharti			}
1938131826Sharti			if (state == UNI_CALLSTATE_U8) {
1939131826Sharti				cc_conn_set_state(conn, CONN_IN_WAIT_COMPL);
1940131826Sharti				cc_user_sig(conn->user, USER_SIG_RELEASE_ERR,
1941131826Sharti				    NULL, reason);
1942131826Sharti			} else if (state == UNI_CALLSTATE_U12) {
1943131826Sharti				do_release_response(conn, 0, NULL);
1944131826Sharti				cc_conn_set_state(conn, CONN_AB_WAIT_RESP_OK);
1945131826Sharti				memset(&conn->user->cause, 0,
1946131826Sharti				    sizeof(conn->user->cause));
1947131826Sharti				cc_user_sig(conn->user,
1948131826Sharti				    USER_SIG_RELEASE_CONFIRM, NULL, 0);
1949131826Sharti				cc_disconnect_from_user(conn);
1950131826Sharti			} else {
1951131826Sharti				cc_conn_set_state(conn, CONN_AB_FLUSH_IND);
1952131826Sharti				memset(&conn->user->cause, 0,
1953131826Sharti				    sizeof(conn->user->cause));
1954131826Sharti				cc_user_sig(conn->user,
1955131826Sharti				    USER_SIG_RELEASE_CONFIRM, NULL, 0);
1956131826Sharti				cc_disconnect_from_user(conn);
1957131826Sharti			}
1958131826Sharti			break;
1959131826Sharti
1960131826Sharti		  default:
1961131826Sharti			/* maybe it's for a party */
1962131826Sharti			LIST_FOREACH(party, &conn->parties, link) {
1963131826Sharti				switch (party->state) {
1964131826Sharti
1965131826Sharti				  case PARTY_ADD_WAIT_CREATE:	/* P2 */
1966131826Sharti					cc_party_destroy(party);
1967131826Sharti					if (user != NULL)
1968131826Sharti						cc_user_sig(user,
1969131826Sharti						    USER_SIG_ADD_PARTY_ERR,
1970131826Sharti						    NULL, ATM_MKUNIERR(reason));
1971131826Sharti					goto ex_party_err;
1972131826Sharti
1973131826Sharti				  case PARTY_ADD_WAIT_OK:	/* P3 */
1974131826Sharti					cc_party_set_state(party,
1975131826Sharti					    PARTY_WAIT_DESTROY);
1976131826Sharti					if (user != NULL)
1977131826Sharti						cc_user_sig(user,
1978131826Sharti						    USER_SIG_ADD_PARTY_ERR,
1979131826Sharti						    NULL, ATM_MKUNIERR(reason));
1980131826Sharti					goto ex_party_err;
1981131826Sharti
1982131826Sharti				  case PARTY_DROP_WAIT_OK:	/* P5 */
1983131826Sharti					cc_party_set_state(party,
1984131826Sharti					    PARTY_ACTIVE);
1985131826Sharti					if (user != NULL)
1986131826Sharti						cc_user_sig(user,
1987131826Sharti						    USER_SIG_DROP_PARTY_ERR,
1988131826Sharti						    NULL, ATM_MKUNIERR(reason));
1989131826Sharti					goto ex_party_err;
1990131826Sharti
1991131826Sharti				  case PARTY_WAIT_DROP_ACK_OK:	/* P9 */
1992131826Sharti					cc_party_set_state(party,
1993131826Sharti					    PARTY_ACTIVE);
1994131826Sharti					goto ex_party_err;
1995131826Sharti
1996131826Sharti				  case PARTY_ADD_DROP_WAIT_OK:	/* P11 */
1997131826Sharti					cc_party_set_state(party,
1998131826Sharti					    PARTY_ADD_WAIT_ACK);
1999131826Sharti					if (user != NULL)
2000131826Sharti						cc_user_sig(user,
2001131826Sharti						    USER_SIG_DROP_PARTY_ERR,
2002131826Sharti						    NULL, ATM_MKUNIERR(reason));
2003131826Sharti					goto ex_party_err;
2004131826Sharti
2005131826Sharti				  case PARTY_ADD_DROPACK_WAIT_OK:/* P12 */
2006131826Sharti					cc_party_set_state(party,
2007131826Sharti					    PARTY_ADD_WAIT_ACK);
2008131826Sharti					goto ex_party_err;
2009131826Sharti
2010131826Sharti				  default:
2011131826Sharti					break;
2012131826Sharti				}
2013131826Sharti			}
2014131826Sharti			cc_conn_log(conn, "unexpected reason=%u ustate=%u "
2015131826Sharti			    "state=%s\n", reason, state, stab[conn->state]);
2016131826Sharti		  ex_party_err:
2017131826Sharti			break;
2018131826Sharti		}
2019131826Sharti		break;
2020131826Sharti	    }
2021131826Sharti
2022131826Sharti	  case CONN_SIG_PARTY_CREATED:
2023131826Sharti	    {
2024131826Sharti		struct uni_msg *msg = arg;
2025131826Sharti		struct uniapi_party_created *pcr = uni_msg_rptr(msg,
2026131826Sharti		    struct uniapi_party_created *);
2027131826Sharti
2028131826Sharti		party = cc_party_find(conn, pcr->epref.epref);
2029131826Sharti		if (party == NULL) {
2030131826Sharti			/* for incoming connections we see the party-created
2031131826Sharti			 * immediately after the call-create so that we
2032131826Sharti			 * must be in C10 */
2033131826Sharti			switch (conn->state) {
2034131826Sharti
2035131826Sharti			  case CONN_IN_PREPARING:
2036131826Sharti				party = cc_party_create(conn,
2037131826Sharti				    pcr->epref.epref, 1);
2038131826Sharti				if (party == NULL)
2039131826Sharti					break;
2040131826Sharti				cc_party_set_state(party,
2041131826Sharti				    PARTY_WAIT_SETUP_COMPL);
2042131826Sharti				break;
2043131826Sharti
2044131826Sharti			  case CONN_OUT_WAIT_OK:
2045131826Sharti				party = cc_party_create(conn,
2046131826Sharti				    pcr->epref.epref, 0);
2047131826Sharti				if (party == NULL)
2048131826Sharti					break;
2049131826Sharti				cc_party_set_state(party,
2050131826Sharti				    PARTY_WAIT_SETUP_CONF);
2051131826Sharti				break;
2052131826Sharti
2053131826Sharti			  default:
2054131826Sharti				goto bad_state;
2055131826Sharti			}
2056131826Sharti			break;
2057131826Sharti		}
2058131826Sharti		/* this is for an ADD-PARTY */
2059131826Sharti		if (conn->state != CONN_ACTIVE)
2060131826Sharti			goto bad_state;
2061131826Sharti		if (party->state != PARTY_ADD_WAIT_CREATE)
2062131826Sharti			goto bad_party_state;
2063131826Sharti		cc_party_set_state(party, PARTY_ADD_WAIT_OK);
2064131826Sharti		break;
2065131826Sharti	    }
2066131826Sharti
2067131826Sharti	  case CONN_SIG_PARTY_DESTROYED:
2068131826Sharti	    {
2069131826Sharti		struct uni_msg *msg = arg;
2070131826Sharti		struct uniapi_party_destroyed *pcr = uni_msg_rptr(msg,
2071131826Sharti		    struct uniapi_party_destroyed *);
2072131826Sharti
2073131826Sharti		party = cc_party_find(conn, pcr->epref.epref);
2074131826Sharti		if (party == NULL) {
2075131826Sharti			cc_conn_log(conn, "no party to destroy %u/%u",
2076131826Sharti			    pcr->epref.flag, pcr->epref.epref);
2077131826Sharti			break;
2078131826Sharti		}
2079131826Sharti		cc_party_destroy(party);
2080131826Sharti		break;
2081131826Sharti	    }
2082131826Sharti
2083131826Sharti	}
2084131826Sharti
2085131826Sharti	return;
2086131826Sharti
2087131826Sharti  bad_state:
2088131826Sharti	cc_conn_log(conn, "bad state=%s for signal=%s",
2089131826Sharti	    stab[conn->state], cc_conn_sigtab[sig]);
2090131826Sharti	return;
2091131826Sharti
2092131826Sharti  bad_party_state:
2093131826Sharti	cc_conn_log(conn, "bad party state=%s for signal=%s",
2094131826Sharti	    ptab[party->state], cc_conn_sigtab[sig]);
2095131826Sharti	return;
2096131826Sharti}
2097