1131826Sharti/*
2131826Sharti * Copyright (c) 2003-2004
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 *
34133492Sharti * $Begemot: libunimsg/netnatm/api/cc_user.c,v 1.3 2004/07/16 18:46:55 brandt Exp $
35131826Sharti *
36131826Sharti * ATM API as defined per af-saa-0108
37131826Sharti *
38131826Sharti * User side (upper half)
39131826Sharti */
40131826Sharti
41131826Sharti#include <netnatm/unimsg.h>
42131826Sharti#include <netnatm/msg/unistruct.h>
43131826Sharti#include <netnatm/msg/unimsglib.h>
44131826Sharti#include <netnatm/api/unisap.h>
45131826Sharti#include <netnatm/sig/unidef.h>
46131826Sharti#include <netnatm/api/atmapi.h>
47131826Sharti#include <netnatm/api/ccatm.h>
48131826Sharti#include <netnatm/api/ccpriv.h>
49131826Sharti
50131826Sharti/*
51131826Sharti* This file handles messages to a USER.
52131826Sharti*/
53131826Shartistatic const char *stab[] = {
54131826Sharti#define DEF(N) [N] = #N,
55131826Sharti	USER_STATES
56131826Sharti#undef DEF
57131826Sharti};
58131826Sharti
59131826Sharticonst char *
60131826Sharticc_user_state2str(u_int s)
61131826Sharti{
62131826Sharti	if (s >= sizeof(stab) / sizeof(stab[0]) || stab[s] == NULL)
63131826Sharti		return ("?");
64131826Sharti	return (stab[s]);
65131826Sharti}
66131826Sharti
67131826Shartistatic __inline void
68131826Shartiset_state(struct ccuser *user, enum user_state ns)
69131826Sharti{
70131826Sharti	if (user->state != ns) {
71131826Sharti		if (user->cc->log & CCLOG_USER_STATE)
72131826Sharti			cc_user_log(user, "%s -> %s",
73131826Sharti			    stab[user->state], stab[ns]);
74131826Sharti		user->state = ns;
75131826Sharti	}
76131826Sharti}
77131826Sharti
78131826Shartistatic __inline void
79131826Sharticc_user_send(struct ccuser *user, u_int op, void *arg, size_t len)
80131826Sharti{
81131826Sharti	user->cc->funcs->send_user(user, user->uarg, op, arg, len);
82131826Sharti}
83131826Sharti
84131826Shartistatic __inline void
85131826Sharticc_user_ok(struct ccuser *user, u_int data, void *arg, size_t len)
86131826Sharti{
87131826Sharti	user->cc->funcs->respond_user(user, user->uarg,
88131826Sharti	    ATMERR_OK, data, arg, len);
89131826Sharti}
90131826Sharti
91131826Shartistatic __inline void
92131826Sharticc_user_err(struct ccuser *user, int err)
93131826Sharti{
94131826Sharti	user->cc->funcs->respond_user(user, user->uarg,
95131826Sharti	    err, ATMRESP_NONE, NULL, 0);
96131826Sharti}
97131826Sharti
98131826Sharti
99131826Sharti/**********************************************************************
100131826Sharti*
101131826Sharti* INSTANCE MANAGEMENT
102131826Sharti*/
103131826Sharti/*
104131826Sharti* New endpoint created
105131826Sharti*/
106131826Shartistruct ccuser *
107131826Sharticc_user_create(struct ccdata *cc, void *uarg, const char *name)
108131826Sharti{
109131826Sharti	struct ccuser *user;
110131826Sharti
111131826Sharti	user = CCZALLOC(sizeof(*user));
112131826Sharti	if (user == NULL)
113131826Sharti		return (NULL);
114131826Sharti
115131826Sharti	user->cc = cc;
116131826Sharti	user->state = USER_NULL;
117131826Sharti	user->uarg = uarg;
118131826Sharti	strncpy(user->name, name, sizeof(user->name));
119131826Sharti	user->name[sizeof(user->name) - 1] = '\0';
120131826Sharti	TAILQ_INIT(&user->connq);
121131826Sharti	LIST_INSERT_HEAD(&cc->user_list, user, node_link);
122131826Sharti
123131826Sharti	if (user->cc->log & CCLOG_USER_INST)
124131826Sharti		cc_user_log(user, "created with name '%s'", name);
125131826Sharti
126131826Sharti	return (user);
127131826Sharti}
128131826Sharti
129131826Sharti/*
130131826Sharti * Reset a user instance
131131826Sharti */
132131826Shartistatic void
133131826Sharticc_user_reset(struct ccuser *user)
134131826Sharti{
135131826Sharti
136131826Sharti	CCASSERT(TAILQ_EMPTY(&user->connq), ("connq not empty"));
137131826Sharti
138131826Sharti	if (user->sap != NULL) {
139131826Sharti		CCFREE(user->sap);
140131826Sharti		user->sap = NULL;
141131826Sharti	}
142131826Sharti
143131826Sharti	if (user->accepted != NULL) {
144131826Sharti		user->accepted->acceptor = NULL;
145131826Sharti		user->accepted = NULL;
146131826Sharti	}
147131826Sharti	user->config = USER_P2P;
148131826Sharti	user->queue_act = 0;
149131826Sharti	user->queue_max = 0;
150131826Sharti	user->aborted = 0;
151131826Sharti
152131826Sharti	set_state(user, USER_NULL);
153131826Sharti
154131826Sharti	cc_user_sig_flush(user);
155131826Sharti}
156131826Sharti
157131826Shartistatic void
158131826Sharticc_user_abort(struct ccuser *user, const struct uni_ie_cause *cause)
159131826Sharti{
160131826Sharti	struct ccconn *conn;
161131826Sharti
162131826Sharti	/*
163131826Sharti	 * Although the standard state that 'all connections
164131826Sharti	 * associated with this endpoint are aborted' we only
165131826Sharti	 * have to abort the head one, because in state A6
166131826Sharti	 * (call present) the endpoint is only associated to the
167131826Sharti	 * head connection - the others are 'somewhere else' and
168131826Sharti	 * need to be redispatched.
169131826Sharti	 *
170131826Sharti	 * First bring user into a state that the connections
171131826Sharti	 * are not dispatched back to it.
172131826Sharti	 */
173131826Sharti	set_state(user, USER_NULL);
174131826Sharti	if (!user->aborted) {
175131826Sharti		if ((conn = TAILQ_FIRST(&user->connq)) != NULL) {
176131826Sharti			memset(conn->cause, 0, sizeof(conn->cause));
177131826Sharti			if (cause != NULL)
178131826Sharti				conn->cause[0] = *cause;
179131826Sharti			cc_conn_reset_acceptor(conn);
180131826Sharti			cc_disconnect_from_user(conn);
181131826Sharti			cc_conn_sig(conn, CONN_SIG_USER_ABORT, NULL);
182131826Sharti		}
183131826Sharti	}
184131826Sharti
185131826Sharti	while ((conn = TAILQ_FIRST(&user->connq)) != NULL) {
186131826Sharti		/* these should be in C21 */
187131826Sharti		cc_disconnect_from_user(conn);
188131826Sharti		cc_conn_dispatch(conn);
189131826Sharti	}
190131826Sharti
191131826Sharti	cc_user_reset(user);
192131826Sharti}
193131826Sharti
194131826Sharti/*
195131826Sharti * Application has closed this endpoint. Clean up all user resources and
196131826Sharti * abort all connections. This can be called in any state.
197131826Sharti */
198131826Shartivoid
199131826Sharticc_user_destroy(struct ccuser *user)
200131826Sharti{
201131826Sharti
202131826Sharti	if (user->cc->log & CCLOG_USER_INST)
203131826Sharti		cc_user_log(user, "destroy '%s'", user->name);
204131826Sharti
205131826Sharti	cc_user_abort(user, NULL);
206131826Sharti
207131826Sharti	if (user->sap != NULL)
208131826Sharti		CCFREE(user->sap);
209131826Sharti
210131826Sharti	cc_user_sig_flush(user);
211131826Sharti
212131826Sharti	LIST_REMOVE(user, node_link);
213131826Sharti	CCFREE(user);
214131826Sharti}
215131826Sharti
216131826Sharti/**********************************************************************
217131826Sharti *
218131826Sharti * OUTGOING CALLS
219131826Sharti */
220131826Sharti/*
221131826Sharti * Return true when the calling address of the connection matches the address.
222131826Sharti */
223131826Shartistatic int
224131826Shartiaddr_matches(const struct ccaddr *addr, const struct ccconn *conn)
225131826Sharti{
226131826Sharti
227131826Sharti	if (!IE_ISPRESENT(conn->calling))
228131826Sharti		return (0);
229131826Sharti
230131826Sharti	return (addr->addr.type == conn->calling.addr.type &&
231131826Sharti	    addr->addr.plan == conn->calling.addr.plan &&
232131826Sharti	    addr->addr.len == conn->calling.addr.len &&
233131826Sharti	    memcmp(addr->addr.addr, conn->calling.addr.addr,
234131826Sharti	    addr->addr.len) == 0);
235131826Sharti}
236131826Sharti
237131826Sharti/*
238131826Sharti * Check if the user's SAP (given he is in the right state) and
239131826Sharti * the given SAP overlap
240131826Sharti */
241131826Shartistatic int
242131826Sharticheck_overlap(struct ccuser *user, struct uni_sap *sap)
243131826Sharti{
244131826Sharti	return ((user->state == USER_IN_PREPARING ||
245131826Sharti	    user->state == USER_IN_WAITING) &&
246131826Sharti	    unisve_overlap_sap(user->sap, sap));
247131826Sharti}
248131826Sharti
249131826Sharti/*
250131826Sharti * Send arrival notification to user
251131826Sharti */
252131826Shartistatic void
253131826Shartido_arrival(struct ccuser *user)
254131826Sharti{
255131826Sharti	struct ccconn *conn;
256131826Sharti
257131826Sharti	user->aborted = 0;
258131826Sharti	if ((conn = TAILQ_FIRST(&user->connq)) != NULL) {
259131826Sharti		set_state(user, USER_IN_ARRIVED);
260131826Sharti		cc_user_send(user, ATMOP_ARRIVAL_OF_INCOMING_CALL, NULL, 0);
261131826Sharti		cc_conn_sig(conn, CONN_SIG_ARRIVAL, NULL);
262131826Sharti	}
263131826Sharti}
264131826Sharti
265131826Sharti/**********************************************************************
266131826Sharti *
267131826Sharti * ATTRIBUTES
268131826Sharti */
269131826Sharti/*
270131826Sharti * Query an attribute. This is possible only in some states: preparation
271131826Sharti * of an outgoing call, after an incoming call was offered to the application
272131826Sharti * and in the three active states (P2P, P2PLeaf, P2PRoot).
273131826Sharti */
274131826Shartistatic struct ccconn *
275131826Sharticc_query_check(struct ccuser *user)
276131826Sharti{
277131826Sharti
278131826Sharti	switch (user->state) {
279131826Sharti
280131826Sharti	  case USER_OUT_PREPARING:
281131826Sharti	  case USER_IN_ARRIVED:
282131826Sharti	  case USER_ACTIVE:
283131826Sharti		return (TAILQ_FIRST(&user->connq));
284131826Sharti
285131826Sharti	  case USER_NULL:
286131826Sharti		/* if we are waiting for the SETUP_confirm, we are in
287131826Sharti		 * the NULL state still (we are the new endpoint), but
288131826Sharti		 * have a connection in 'accepted' that is in the
289131826Sharti		 * CONN_IN_WAIT_ACCEPT_OK state.
290131826Sharti		 */
291131826Sharti		if (user->accepted != NULL &&
292131826Sharti		    user->accepted->state == CONN_IN_WAIT_ACCEPT_OK)
293131826Sharti			return (user->accepted);
294131826Sharti		/* FALLTHRU */
295131826Sharti
296131826Sharti	  default:
297131826Sharti		return (NULL);
298131826Sharti	}
299131826Sharti}
300131826Sharti
301131826Sharti/*
302131826Sharti * Query attributes
303131826Sharti */
304131826Shartistatic void
305131826Sharticc_attr_query(struct ccuser *user, struct ccconn *conn,
306131826Sharti    uint32_t *attr, u_int count)
307131826Sharti{
308131826Sharti	void *val, *ptr;
309131826Sharti	size_t total, len;
310131826Sharti	u_int i;
311131826Sharti	uint32_t *atab;
312131826Sharti
313131826Sharti	/* determine the length of the total attribute buffer */
314131826Sharti	total = sizeof(uint32_t) + count * sizeof(uint32_t);
315131826Sharti	for (i = 0; i < count; i++) {
316131826Sharti		len = 0;
317131826Sharti		switch ((enum atm_attribute)attr[i]) {
318131826Sharti
319131826Sharti		  case ATM_ATTR_NONE:
320131826Sharti			break;
321131826Sharti
322131826Sharti		  case ATM_ATTR_BLLI_SELECTOR:
323131826Sharti			len = sizeof(uint32_t);
324131826Sharti			break;
325131826Sharti
326131826Sharti		  case ATM_ATTR_BLLI:
327131826Sharti			len = sizeof(struct uni_ie_blli);
328131826Sharti			break;
329131826Sharti
330131826Sharti		  case ATM_ATTR_BEARER:
331131826Sharti			len = sizeof(struct uni_ie_bearer);
332131826Sharti			break;
333131826Sharti
334131826Sharti		  case ATM_ATTR_TRAFFIC:
335131826Sharti			len = sizeof(struct uni_ie_traffic);
336131826Sharti			break;
337131826Sharti
338131826Sharti		  case ATM_ATTR_QOS:
339131826Sharti			len = sizeof(struct uni_ie_qos);
340131826Sharti			break;
341131826Sharti
342131826Sharti		  case ATM_ATTR_EXQOS:
343131826Sharti			len = sizeof(struct uni_ie_exqos);
344131826Sharti			break;
345131826Sharti
346131826Sharti		  case ATM_ATTR_CALLED:
347131826Sharti			len = sizeof(struct uni_ie_called);
348131826Sharti			break;
349131826Sharti
350131826Sharti		  case ATM_ATTR_CALLEDSUB:
351131826Sharti			len = sizeof(struct uni_ie_calledsub);
352131826Sharti			break;
353131826Sharti
354131826Sharti		  case ATM_ATTR_CALLING:
355131826Sharti			len = sizeof(struct uni_ie_calling);
356131826Sharti			break;
357131826Sharti
358131826Sharti		  case ATM_ATTR_CALLINGSUB:
359131826Sharti			len = sizeof(struct uni_ie_callingsub);
360131826Sharti			break;
361131826Sharti
362131826Sharti		  case ATM_ATTR_AAL:
363131826Sharti			len = sizeof(struct uni_ie_aal);
364131826Sharti			break;
365131826Sharti
366131826Sharti		  case ATM_ATTR_EPREF:
367131826Sharti			len = sizeof(struct uni_ie_epref);
368131826Sharti			break;
369131826Sharti
370131826Sharti		  case ATM_ATTR_CONNED:
371131826Sharti			len = sizeof(struct uni_ie_conned);
372131826Sharti			break;
373131826Sharti
374131826Sharti		  case ATM_ATTR_CONNEDSUB:
375131826Sharti			len = sizeof(struct uni_ie_connedsub);
376131826Sharti			break;
377131826Sharti
378131826Sharti		  case ATM_ATTR_EETD:
379131826Sharti			len = sizeof(struct uni_ie_eetd);
380131826Sharti			break;
381131826Sharti
382131826Sharti		  case ATM_ATTR_ABRSETUP:
383131826Sharti			len = sizeof(struct uni_ie_abrsetup);
384131826Sharti			break;
385131826Sharti
386131826Sharti		  case ATM_ATTR_ABRADD:
387131826Sharti			len = sizeof(struct uni_ie_abradd);
388131826Sharti			break;
389131826Sharti
390131826Sharti		  case ATM_ATTR_CONNID:
391131826Sharti			len = sizeof(struct uni_ie_connid);
392131826Sharti			break;
393131826Sharti
394131826Sharti		  case ATM_ATTR_MDCR:
395131826Sharti			len = sizeof(struct uni_ie_mdcr);
396131826Sharti			break;
397131826Sharti		}
398131826Sharti		if (len == 0) {
399131826Sharti			cc_user_err(user, ATMERR_BAD_ATTR);
400131826Sharti			return;
401131826Sharti		}
402131826Sharti		total += len;
403131826Sharti	}
404131826Sharti
405131826Sharti	/* allocate buffer */
406131826Sharti	val = CCMALLOC(total);
407131826Sharti	if (val == NULL)
408131826Sharti		return;
409131826Sharti
410131826Sharti	atab = val;
411131826Sharti	atab[0] = count;
412131826Sharti
413131826Sharti	/* fill */
414131826Sharti	ptr = (u_char *)val + (sizeof(uint32_t) + count * sizeof(uint32_t));
415131826Sharti	for (i = 0; i < count; i++) {
416131826Sharti		len = 0;
417131826Sharti		atab[i + 1] = attr[i];
418131826Sharti		switch (attr[i]) {
419131826Sharti
420131826Sharti		  case ATM_ATTR_NONE:
421131826Sharti			break;
422131826Sharti
423131826Sharti		  case ATM_ATTR_BLLI_SELECTOR:
424131826Sharti			len = sizeof(uint32_t);
425131826Sharti			memcpy(ptr, &conn->blli_selector, len);
426131826Sharti			break;
427131826Sharti
428131826Sharti		  case ATM_ATTR_BLLI:
429131826Sharti			/* in A6 the blli_selector may be 0 when
430131826Sharti			 * there was no blli in the SETUP.
431131826Sharti			 */
432131826Sharti			len = sizeof(struct uni_ie_blli);
433131826Sharti			if (conn->blli_selector == 0)
434131826Sharti				memset(ptr, 0, len);
435131826Sharti			else
436131826Sharti				memcpy(ptr, &conn->blli[conn->blli_selector -
437131826Sharti				    1], len);
438131826Sharti			break;
439131826Sharti
440131826Sharti		  case ATM_ATTR_BEARER:
441131826Sharti			len = sizeof(struct uni_ie_bearer);
442131826Sharti			memcpy(ptr, &conn->bearer, len);
443131826Sharti			break;
444131826Sharti
445131826Sharti		  case ATM_ATTR_TRAFFIC:
446131826Sharti			len = sizeof(struct uni_ie_traffic);
447131826Sharti			memcpy(ptr, &conn->traffic, len);
448131826Sharti			break;
449131826Sharti
450131826Sharti		  case ATM_ATTR_QOS:
451131826Sharti			len = sizeof(struct uni_ie_qos);
452131826Sharti			memcpy(ptr, &conn->qos, len);
453131826Sharti			break;
454131826Sharti
455131826Sharti		  case ATM_ATTR_EXQOS:
456131826Sharti			len = sizeof(struct uni_ie_exqos);
457131826Sharti			memcpy(ptr, &conn->exqos, len);
458131826Sharti			break;
459131826Sharti
460131826Sharti		  case ATM_ATTR_CALLED:
461131826Sharti			len = sizeof(struct uni_ie_called);
462131826Sharti			memcpy(ptr, &conn->called, len);
463131826Sharti			break;
464131826Sharti
465131826Sharti		  case ATM_ATTR_CALLEDSUB:
466131826Sharti			len = sizeof(struct uni_ie_calledsub);
467131826Sharti			memcpy(ptr, &conn->calledsub, len);
468131826Sharti			break;
469131826Sharti
470131826Sharti		  case ATM_ATTR_CALLING:
471131826Sharti			len = sizeof(struct uni_ie_calling);
472131826Sharti			memcpy(ptr, &conn->calling, len);
473131826Sharti			break;
474131826Sharti
475131826Sharti		  case ATM_ATTR_CALLINGSUB:
476131826Sharti			len = sizeof(struct uni_ie_callingsub);
477131826Sharti			memcpy(ptr, &conn->callingsub, len);
478131826Sharti			break;
479131826Sharti
480131826Sharti		  case ATM_ATTR_AAL:
481131826Sharti			len = sizeof(struct uni_ie_aal);
482131826Sharti			memcpy(ptr, &conn->aal, len);
483131826Sharti			break;
484131826Sharti
485131826Sharti		  case ATM_ATTR_EPREF:
486131826Sharti			len = sizeof(struct uni_ie_epref);
487131826Sharti			memcpy(ptr, &conn->epref, len);
488131826Sharti			break;
489131826Sharti
490131826Sharti		  case ATM_ATTR_CONNED:
491131826Sharti			len = sizeof(struct uni_ie_conned);
492131826Sharti			memcpy(ptr, &conn->conned, len);
493131826Sharti			break;
494131826Sharti
495131826Sharti		  case ATM_ATTR_CONNEDSUB:
496131826Sharti			len = sizeof(struct uni_ie_connedsub);
497131826Sharti			memcpy(ptr, &conn->connedsub, len);
498131826Sharti			break;
499131826Sharti
500131826Sharti		  case ATM_ATTR_EETD:
501131826Sharti			len = sizeof(struct uni_ie_eetd);
502131826Sharti			memcpy(ptr, &conn->eetd, len);
503131826Sharti			break;
504131826Sharti
505131826Sharti		  case ATM_ATTR_ABRSETUP:
506131826Sharti			len = sizeof(struct uni_ie_abrsetup);
507131826Sharti			memcpy(ptr, &conn->abrsetup, len);
508131826Sharti			break;
509131826Sharti
510131826Sharti		  case ATM_ATTR_ABRADD:
511131826Sharti			len = sizeof(struct uni_ie_abradd);
512131826Sharti			memcpy(ptr, &conn->abradd, len);
513131826Sharti			break;
514131826Sharti
515131826Sharti		  case ATM_ATTR_CONNID:
516131826Sharti			len = sizeof(struct uni_ie_connid);
517131826Sharti			memcpy(ptr, &conn->connid, len);
518131826Sharti			break;
519131826Sharti
520131826Sharti		  case ATM_ATTR_MDCR:
521131826Sharti			len = sizeof(struct uni_ie_mdcr);
522131826Sharti			memcpy(ptr, &conn->mdcr, len);
523131826Sharti			break;
524131826Sharti		}
525131826Sharti		ptr = (u_char *)ptr + len;
526131826Sharti	}
527131826Sharti
528131826Sharti	cc_user_ok(user, ATMRESP_ATTRS, val, total);
529131826Sharti
530131826Sharti	CCFREE(val);
531131826Sharti}
532131826Sharti
533131826Sharti/*
534131826Sharti * Check whether the state is ok and return the connection
535131826Sharti */
536131826Shartistatic struct ccconn *
537131826Sharticc_set_check(struct ccuser *user)
538131826Sharti{
539131826Sharti	switch(user->state) {
540131826Sharti
541131826Sharti	  case USER_OUT_PREPARING:
542131826Sharti	  case USER_IN_ARRIVED:
543131826Sharti		return (TAILQ_FIRST(&user->connq));
544131826Sharti
545131826Sharti	  default:
546131826Sharti		return (NULL);
547131826Sharti	}
548131826Sharti}
549131826Sharti
550131826Sharti/*
551131826Sharti * Set connection attribute(s)
552131826Sharti */
553131826Shartistatic void
554131826Sharticc_attr_set(struct ccuser *user, struct ccconn *conn, uint32_t *attr,
555131826Sharti    u_int count, u_char *val, size_t vallen)
556131826Sharti{
557131826Sharti	size_t total, len;
558131826Sharti	u_int i;
559131826Sharti	u_char *ptr;
560131826Sharti
561131826Sharti	/* determine the length of the total attribute buffer */
562131826Sharti	total = 0;
563131826Sharti	ptr = val;
564131826Sharti	for (i = 0; i < count; i++) {
565131826Sharti		len = 0;
566131826Sharti		switch ((enum atm_attribute)attr[i]) {
567131826Sharti
568131826Sharti		  case ATM_ATTR_NONE:
569131826Sharti			break;
570131826Sharti
571131826Sharti		  case ATM_ATTR_BLLI_SELECTOR:
572131826Sharti		    {
573131826Sharti			uint32_t sel;
574131826Sharti
575131826Sharti			if (conn->state != CONN_OUT_PREPARING)
576131826Sharti				goto rdonly;
577131826Sharti			memcpy(&sel, ptr, sizeof(sel));
578131826Sharti			if (sel == 0 || sel > UNI_NUM_IE_BLLI)
579131826Sharti				goto bad_val;
580131826Sharti			len = sizeof(uint32_t);
581131826Sharti			break;
582131826Sharti		    }
583131826Sharti
584131826Sharti		  case ATM_ATTR_BLLI:
585131826Sharti			len = sizeof(struct uni_ie_blli);
586131826Sharti			break;
587131826Sharti
588131826Sharti		  case ATM_ATTR_BEARER:
589131826Sharti			if (conn->state != CONN_OUT_PREPARING)
590131826Sharti				goto rdonly;
591131826Sharti			len = sizeof(struct uni_ie_bearer);
592131826Sharti			break;
593131826Sharti
594131826Sharti		  case ATM_ATTR_TRAFFIC:
595131826Sharti			len = sizeof(struct uni_ie_traffic);
596131826Sharti			break;
597131826Sharti
598131826Sharti		  case ATM_ATTR_QOS:
599131826Sharti			if (conn->state != CONN_OUT_PREPARING)
600131826Sharti				goto rdonly;
601131826Sharti			len = sizeof(struct uni_ie_qos);
602131826Sharti			break;
603131826Sharti
604131826Sharti		  case ATM_ATTR_EXQOS:
605131826Sharti			len = sizeof(struct uni_ie_exqos);
606131826Sharti			break;
607131826Sharti
608131826Sharti		  case ATM_ATTR_CALLED:
609131826Sharti			goto rdonly;
610131826Sharti
611131826Sharti		  case ATM_ATTR_CALLEDSUB:
612131826Sharti			if (conn->state != CONN_OUT_PREPARING)
613131826Sharti				goto rdonly;
614131826Sharti			len = sizeof(struct uni_ie_calledsub);
615131826Sharti			break;
616131826Sharti
617131826Sharti		  case ATM_ATTR_CALLING:
618131826Sharti			if (conn->state != CONN_OUT_PREPARING)
619131826Sharti				goto rdonly;
620131826Sharti			len = sizeof(struct uni_ie_calling);
621131826Sharti			break;
622131826Sharti
623131826Sharti		  case ATM_ATTR_CALLINGSUB:
624131826Sharti			if (conn->state != CONN_OUT_PREPARING)
625131826Sharti				goto rdonly;
626131826Sharti			len = sizeof(struct uni_ie_callingsub);
627131826Sharti			break;
628131826Sharti
629131826Sharti		  case ATM_ATTR_AAL:
630131826Sharti			len = sizeof(struct uni_ie_aal);
631131826Sharti			break;
632131826Sharti
633131826Sharti		  case ATM_ATTR_EPREF:
634131826Sharti			goto rdonly;
635131826Sharti
636131826Sharti		  case ATM_ATTR_CONNED:
637131826Sharti			goto rdonly;
638131826Sharti
639131826Sharti		  case ATM_ATTR_CONNEDSUB:
640131826Sharti			goto rdonly;
641131826Sharti
642131826Sharti		  case ATM_ATTR_EETD:
643131826Sharti			len = sizeof(struct uni_ie_eetd);
644131826Sharti			break;
645131826Sharti
646131826Sharti		  case ATM_ATTR_ABRSETUP:
647131826Sharti			len = sizeof(struct uni_ie_abrsetup);
648131826Sharti			break;
649131826Sharti
650131826Sharti		  case ATM_ATTR_ABRADD:
651131826Sharti			len = sizeof(struct uni_ie_abradd);
652131826Sharti			break;
653131826Sharti
654131826Sharti		  case ATM_ATTR_CONNID:
655131826Sharti			len = sizeof(struct uni_ie_connid);
656131826Sharti			break;
657131826Sharti
658131826Sharti		  case ATM_ATTR_MDCR:
659131826Sharti			if (conn->state != CONN_OUT_PREPARING)
660131826Sharti				goto rdonly;
661131826Sharti			len = sizeof(struct uni_ie_mdcr);
662131826Sharti			break;
663131826Sharti		}
664131826Sharti		if (len == 0) {
665131826Sharti			cc_user_err(user, ATMERR_BAD_ATTR);
666131826Sharti			return;
667131826Sharti		}
668131826Sharti		total += len;
669131826Sharti		ptr += len;
670131826Sharti	}
671131826Sharti
672131826Sharti	/* check the length */
673131826Sharti	if (vallen != total) {
674131826Sharti		cc_user_err(user, ATMERR_BAD_ARGS);
675131826Sharti		return;
676131826Sharti	}
677131826Sharti
678131826Sharti	ptr = val;
679131826Sharti	for (i = 0; i < count; i++) {
680131826Sharti		len = 0;
681131826Sharti		switch ((enum atm_attribute)attr[i]) {
682131826Sharti
683131826Sharti		  case ATM_ATTR_NONE:
684131826Sharti			break;
685131826Sharti
686131826Sharti		  case ATM_ATTR_BLLI_SELECTOR:
687131826Sharti		    {
688131826Sharti			uint32_t sel;
689131826Sharti
690131826Sharti			memcpy(&sel, ptr, sizeof(sel));
691131826Sharti			conn->blli_selector = sel;
692131826Sharti			len = sizeof(uint32_t);
693131826Sharti			break;
694131826Sharti		    }
695131826Sharti
696131826Sharti		  case ATM_ATTR_BLLI:
697131826Sharti			len = sizeof(struct uni_ie_blli);
698131826Sharti			memcpy(&conn->blli[conn->blli_selector - 1], ptr, len);
699131826Sharti			conn->dirty_attr |= CCDIRTY_BLLI;
700131826Sharti			break;
701131826Sharti
702131826Sharti		  case ATM_ATTR_BEARER:
703131826Sharti			len = sizeof(struct uni_ie_bearer);
704131826Sharti			memcpy(&conn->bearer, ptr, len);
705131826Sharti			break;
706131826Sharti
707131826Sharti		  case ATM_ATTR_TRAFFIC:
708131826Sharti			len = sizeof(struct uni_ie_traffic);
709131826Sharti			memcpy(&conn->traffic, ptr, len);
710131826Sharti			conn->dirty_attr |= CCDIRTY_TRAFFIC;
711131826Sharti			break;
712131826Sharti
713131826Sharti		  case ATM_ATTR_QOS:
714131826Sharti			len = sizeof(struct uni_ie_qos);
715131826Sharti			memcpy(&conn->qos, ptr, len);
716131826Sharti			break;
717131826Sharti
718131826Sharti		  case ATM_ATTR_EXQOS:
719131826Sharti			len = sizeof(struct uni_ie_exqos);
720131826Sharti			memcpy(&conn->exqos, ptr, len);
721131826Sharti			conn->dirty_attr |= CCDIRTY_EXQOS;
722131826Sharti			break;
723131826Sharti
724131826Sharti		  case ATM_ATTR_CALLED:
725131826Sharti			len = sizeof(struct uni_ie_called);
726131826Sharti			break;
727131826Sharti
728131826Sharti		  case ATM_ATTR_CALLEDSUB:
729131826Sharti			len = sizeof(struct uni_ie_calledsub);
730131826Sharti			memcpy(&conn->calledsub, ptr, len);
731131826Sharti			break;
732131826Sharti
733131826Sharti		  case ATM_ATTR_CALLING:
734131826Sharti			len = sizeof(struct uni_ie_calling);
735131826Sharti			memcpy(&conn->calling, ptr, len);
736131826Sharti			break;
737131826Sharti
738131826Sharti		  case ATM_ATTR_CALLINGSUB:
739131826Sharti			len = sizeof(struct uni_ie_callingsub);
740131826Sharti			memcpy(&conn->callingsub, ptr, len);
741131826Sharti			break;
742131826Sharti
743131826Sharti		  case ATM_ATTR_AAL:
744131826Sharti			len = sizeof(struct uni_ie_aal);
745131826Sharti			memcpy(&conn->aal, ptr, len);
746131826Sharti			conn->dirty_attr |= CCDIRTY_AAL;
747131826Sharti			break;
748131826Sharti
749131826Sharti		  case ATM_ATTR_EPREF:
750131826Sharti			len = sizeof(struct uni_ie_epref);
751131826Sharti			break;
752131826Sharti
753131826Sharti		  case ATM_ATTR_CONNED:
754131826Sharti			len = sizeof(struct uni_ie_conned);
755131826Sharti			break;
756131826Sharti
757131826Sharti		  case ATM_ATTR_CONNEDSUB:
758131826Sharti			len = sizeof(struct uni_ie_connedsub);
759131826Sharti			break;
760131826Sharti
761131826Sharti		  case ATM_ATTR_EETD:
762131826Sharti			len = sizeof(struct uni_ie_eetd);
763131826Sharti			memcpy(&conn->eetd, ptr, len);
764131826Sharti			conn->dirty_attr |= CCDIRTY_EETD;
765131826Sharti			break;
766131826Sharti
767131826Sharti		  case ATM_ATTR_ABRSETUP:
768131826Sharti			len = sizeof(struct uni_ie_abrsetup);
769131826Sharti			memcpy(&conn->abrsetup, ptr, len);
770131826Sharti			conn->dirty_attr |= CCDIRTY_ABRSETUP;
771131826Sharti			break;
772131826Sharti
773131826Sharti		  case ATM_ATTR_ABRADD:
774131826Sharti			len = sizeof(struct uni_ie_abradd);
775131826Sharti			memcpy(&conn->abradd, ptr, len);
776131826Sharti			conn->dirty_attr |= CCDIRTY_ABRADD;
777131826Sharti			break;
778131826Sharti
779131826Sharti		  case ATM_ATTR_CONNID:
780131826Sharti			len = sizeof(struct uni_ie_connid);
781131826Sharti			memcpy(&conn->connid, ptr, len);
782131826Sharti			conn->dirty_attr |= CCDIRTY_CONNID;
783131826Sharti			break;
784131826Sharti
785131826Sharti		  case ATM_ATTR_MDCR:
786131826Sharti			len = sizeof(struct uni_ie_mdcr);
787131826Sharti			memcpy(&conn->mdcr, ptr, len);
788131826Sharti			break;
789131826Sharti		}
790131826Sharti		ptr += len;
791131826Sharti	}
792131826Sharti
793131826Sharti	cc_user_ok(user, ATMRESP_NONE, NULL, 0);
794131826Sharti	return;
795131826Sharti
796131826Sharti  bad_val:
797131826Sharti	cc_user_err(user, ATMERR_BAD_VALUE);
798131826Sharti	return;
799131826Sharti
800131826Sharti  rdonly:
801131826Sharti	cc_user_err(user, ATMERR_RDONLY);
802131826Sharti	return;
803131826Sharti}
804131826Sharti
805131826Sharti#ifdef CCATM_DEBUG
806131826Shartistatic const char *op_names[] = {
807131826Sharti#define	S(OP)	[ATMOP_##OP] = #OP
808131826Sharti	S(RESP),
809131826Sharti	S(ABORT_CONNECTION),
810131826Sharti	S(ACCEPT_INCOMING_CALL),
811131826Sharti	S(ADD_PARTY),
812131826Sharti	S(ADD_PARTY_REJECT),
813131826Sharti	S(ADD_PARTY_SUCCESS),
814131826Sharti	S(ARRIVAL_OF_INCOMING_CALL),
815131826Sharti	S(CALL_RELEASE),
816131826Sharti	S(CONNECT_OUTGOING_CALL),
817131826Sharti	S(DROP_PARTY),
818131826Sharti	S(GET_LOCAL_PORT_INFO),
819131826Sharti	S(P2MP_CALL_ACTIVE),
820131826Sharti	S(P2P_CALL_ACTIVE),
821131826Sharti	S(PREPARE_INCOMING_CALL),
822131826Sharti	S(PREPARE_OUTGOING_CALL),
823131826Sharti	S(QUERY_CONNECTION_ATTRIBUTES),
824131826Sharti	S(REJECT_INCOMING_CALL),
825131826Sharti	S(SET_CONNECTION_ATTRIBUTES),
826131826Sharti	S(WAIT_ON_INCOMING_CALL),
827131826Sharti	S(SET_CONNECTION_ATTRIBUTES_X),
828131826Sharti	S(QUERY_CONNECTION_ATTRIBUTES_X),
829131826Sharti	S(QUERY_STATE),
830131826Sharti#undef S
831131826Sharti};
832131826Sharti#endif
833131826Sharti
834131826Sharti/*
835131826Sharti * Signal from user - map this to our internal signals and queue
836131826Sharti * the mapped signal.
837131826Sharti */
838131826Shartiint
839131826Sharticc_user_signal(struct ccuser *user, enum atmop sig, struct uni_msg *msg)
840131826Sharti{
841131826Sharti	size_t len = uni_msg_len(msg);
842131826Sharti	int err = EINVAL;
843131826Sharti
844131826Sharti	if (user->cc->log & CCLOG_USER_SIG)
845131826Sharti		cc_user_log(user, "signal %s to user", op_names[sig]);
846131826Sharti
847131826Sharti	if ((u_int)sig > ATMOP_QUERY_STATE)
848131826Sharti		goto bad_signal;
849131826Sharti
850131826Sharti	switch (sig) {
851131826Sharti
852131826Sharti	  case ATMOP_ABORT_CONNECTION:
853131826Sharti		if (len != sizeof(struct atm_abort_connection))
854131826Sharti			goto bad_len;
855131826Sharti		err = cc_user_sig_msg(user, USER_SIG_ABORT_CONNECTION, msg);
856131826Sharti		break;
857131826Sharti
858131826Sharti	  case ATMOP_ACCEPT_INCOMING_CALL:
859131826Sharti		if (len != sizeof(struct atm_accept_incoming_call))
860131826Sharti			goto bad_len;
861131826Sharti		err = cc_user_sig_msg(user, USER_SIG_ACCEPT_INCOMING, msg);
862131826Sharti		break;
863131826Sharti
864131826Sharti	  case ATMOP_ADD_PARTY:
865131826Sharti		if (len != sizeof(struct atm_add_party))
866131826Sharti			goto bad_len;
867131826Sharti		err = cc_user_sig_msg(user, USER_SIG_ADD_PARTY, msg);
868131826Sharti		break;
869131826Sharti
870131826Sharti	  case ATMOP_CALL_RELEASE:
871131826Sharti		if (len != sizeof(struct atm_call_release))
872131826Sharti			goto bad_len;
873131826Sharti		err = cc_user_sig_msg(user, USER_SIG_CALL_RELEASE, msg);
874131826Sharti		break;
875131826Sharti
876131826Sharti	  case ATMOP_CONNECT_OUTGOING_CALL:
877131826Sharti		if (len != sizeof(struct atm_connect_outgoing_call))
878131826Sharti			goto bad_len;
879131826Sharti		err = cc_user_sig_msg(user, USER_SIG_CONNECT_OUTGOING, msg);
880131826Sharti		break;
881131826Sharti
882131826Sharti	  case ATMOP_DROP_PARTY:
883131826Sharti		if (len != sizeof(struct atm_drop_party))
884131826Sharti			goto bad_len;
885131826Sharti		err = cc_user_sig_msg(user, USER_SIG_DROP_PARTY, msg);
886131826Sharti		break;
887131826Sharti
888131826Sharti	  case ATMOP_GET_LOCAL_PORT_INFO:
889131826Sharti		if (len != sizeof(struct atm_get_local_port_info))
890131826Sharti			goto bad_len;
891131826Sharti		err = cc_user_sig_msg(user, USER_SIG_GET_LOCAL_PORT_INFO, msg);
892131826Sharti		break;
893131826Sharti
894131826Sharti	  case ATMOP_PREPARE_INCOMING_CALL:
895131826Sharti		if (len != sizeof(struct atm_prepare_incoming_call))
896131826Sharti			goto bad_len;
897131826Sharti		err = cc_user_sig_msg(user, USER_SIG_PREPARE_INCOMING, msg);
898131826Sharti		break;
899131826Sharti
900131826Sharti	  case ATMOP_PREPARE_OUTGOING_CALL:
901131826Sharti		if (len != 0)
902131826Sharti			goto bad_len;
903131826Sharti		uni_msg_destroy(msg);
904131826Sharti		err = cc_user_sig(user, USER_SIG_PREPARE_OUTGOING, NULL, 0);
905131826Sharti		break;
906131826Sharti
907131826Sharti	  case ATMOP_QUERY_CONNECTION_ATTRIBUTES:
908131826Sharti		if (len != sizeof(struct atm_query_connection_attributes))
909131826Sharti			goto bad_len;
910131826Sharti		err = cc_user_sig_msg(user, USER_SIG_QUERY_ATTR, msg);
911131826Sharti		break;
912131826Sharti
913131826Sharti	  case ATMOP_REJECT_INCOMING_CALL:
914131826Sharti		if (len != sizeof(struct atm_reject_incoming_call))
915131826Sharti			goto bad_len;
916131826Sharti		err = cc_user_sig_msg(user, USER_SIG_REJECT_INCOMING, msg);
917131826Sharti		break;
918131826Sharti
919131826Sharti	  case ATMOP_SET_CONNECTION_ATTRIBUTES:
920131826Sharti		if (len < sizeof(struct atm_set_connection_attributes))
921131826Sharti			goto bad_len;
922131826Sharti		err = cc_user_sig_msg(user, USER_SIG_SET_ATTR, msg);
923131826Sharti		break;
924131826Sharti
925131826Sharti	  case ATMOP_WAIT_ON_INCOMING_CALL:
926131826Sharti		if (len != 0)
927131826Sharti			goto bad_len;
928131826Sharti		uni_msg_destroy(msg);
929131826Sharti		err = cc_user_sig(user, USER_SIG_WAIT_ON_INCOMING, NULL, 0);
930131826Sharti		break;
931131826Sharti
932131826Sharti	  case ATMOP_QUERY_CONNECTION_ATTRIBUTES_X:
933131826Sharti		if (len < sizeof(struct atm_set_connection_attributes_x) ||
934131826Sharti		    len != offsetof(struct atm_set_connection_attributes_x,
935131826Sharti		    attr) + uni_msg_rptr(msg,
936131826Sharti		    struct atm_set_connection_attributes_x *)->count *
937131826Sharti		    sizeof(uint32_t))
938131826Sharti			goto bad_len;
939131826Sharti		err = cc_user_sig_msg(user, USER_SIG_QUERY_ATTR_X, msg);
940131826Sharti		break;
941131826Sharti
942131826Sharti	  case ATMOP_SET_CONNECTION_ATTRIBUTES_X:
943131826Sharti		if (len < sizeof(struct atm_set_connection_attributes_x))
944131826Sharti			goto bad_len;
945131826Sharti		err = cc_user_sig_msg(user, USER_SIG_SET_ATTR_X, msg);
946131826Sharti		break;
947131826Sharti
948131826Sharti	  case ATMOP_QUERY_STATE:
949131826Sharti		if (len != 0)
950131826Sharti			goto bad_len;
951131826Sharti		uni_msg_destroy(msg);
952131826Sharti		err = cc_user_sig(user, USER_SIG_QUERY_STATE, NULL, 0);
953131826Sharti		break;
954131826Sharti
955131826Sharti	  case ATMOP_RESP:
956131826Sharti	  case ATMOP_ADD_PARTY_REJECT:
957131826Sharti	  case ATMOP_ADD_PARTY_SUCCESS:
958131826Sharti	  case ATMOP_ARRIVAL_OF_INCOMING_CALL:
959131826Sharti	  case ATMOP_P2MP_CALL_ACTIVE:
960131826Sharti	  case ATMOP_P2P_CALL_ACTIVE:
961131826Sharti	  bad_signal:
962131826Sharti		/* bad signal */
963131826Sharti		if (user->cc->log & CCLOG_USER_SIG)
964131826Sharti			cc_user_log(user, "bad signal %u", sig);
965131826Sharti		cc_user_err(user, ATMERR_BAD_OP);
966131826Sharti		uni_msg_destroy(msg);
967131826Sharti		break;
968131826Sharti	}
969131826Sharti	return (err);
970131826Sharti
971131826Sharti  bad_len:
972131826Sharti	/* bad argument length */
973131826Sharti	if (user->cc->log & CCLOG_USER_SIG)
974131826Sharti		cc_user_log(user, "signal %s had bad len=%zu",
975131826Sharti		    op_names[sig], len);
976131826Sharti	cc_user_err(user, ATMERR_BAD_ARGS);
977131826Sharti	uni_msg_destroy(msg);
978131826Sharti	return (EINVAL);
979131826Sharti}
980131826Sharti
981131826Sharti/*
982131826Sharti * Send active signal to user
983131826Sharti */
984131826Shartistatic void
985131826Sharticc_user_active(struct ccuser *user)
986131826Sharti{
987131826Sharti	struct ccconn *conn = TAILQ_FIRST(&user->connq);
988131826Sharti
989131826Sharti	set_state(user, USER_ACTIVE);
990131826Sharti	if (conn->bearer.cfg == UNI_BEARER_P2P) {
991131826Sharti		struct atm_p2p_call_active *act;
992131826Sharti
993131826Sharti		user->config = USER_P2P;
994131826Sharti		act = CCZALLOC(sizeof(*act));
995131826Sharti		if (act == NULL)
996131826Sharti			return;
997131826Sharti		act->connid = conn->connid;
998131826Sharti		cc_user_send(user, ATMOP_P2P_CALL_ACTIVE, act, sizeof(*act));
999131826Sharti		CCFREE(act);
1000131826Sharti	} else {
1001131826Sharti		struct atm_p2mp_call_active *act;
1002131826Sharti
1003131826Sharti		user->config = USER_ROOT;
1004131826Sharti		act = CCZALLOC(sizeof(*act));
1005131826Sharti		if (act == NULL)
1006131826Sharti			return;
1007131826Sharti		act->connid = conn->connid;
1008131826Sharti		cc_user_send(user, ATMOP_P2MP_CALL_ACTIVE, act, sizeof(*act));
1009131826Sharti		CCFREE(act);
1010131826Sharti	}
1011131826Sharti}
1012131826Sharti
1013131826Sharti/*
1014131826Sharti* Handle a signal to this user
1015131826Sharti*/
1016131826Shartivoid
1017131826Sharticc_user_sig_handle(struct ccuser *user, enum user_sig sig,
1018131826Sharti    void *arg, u_int arg2)
1019131826Sharti{
1020131826Sharti
1021131826Sharti	if (user->cc->log & CCLOG_USER_SIG)
1022131826Sharti		cc_user_log(user, "signal %s to user state %s",
1023131826Sharti		    cc_user_sigtab[sig], stab[user->state]);
1024131826Sharti
1025131826Sharti	switch (sig) {
1026131826Sharti
1027131826Sharti
1028131826Sharti	  case USER_SIG_PREPARE_OUTGOING:
1029131826Sharti	    {
1030131826Sharti		/*
1031131826Sharti		 * Here we create a connection for the call we soon will make.
1032131826Sharti		 * We put this call on the list of orphaned connections,
1033131826Sharti		 * because we don't know yet, which port will get the
1034131826Sharti		 * connection. It is assigned, when the user issues the call
1035131826Sharti		 * to connect.
1036131826Sharti		 */
1037131826Sharti		struct ccconn *conn;
1038131826Sharti
1039131826Sharti		if (user->state != USER_NULL) {
1040131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1041131826Sharti			goto bad_state;
1042131826Sharti		}
1043131826Sharti		conn = cc_conn_create(user->cc);
1044131826Sharti		if (conn == NULL) {
1045131826Sharti			cc_user_err(user, ATMERR_NOMEM);
1046131826Sharti			return;
1047131826Sharti		}
1048131826Sharti		set_state(user, USER_OUT_PREPARING);
1049131826Sharti		cc_conn_set_state(conn, CONN_OUT_PREPARING);
1050131826Sharti		conn->blli_selector = 1;
1051131826Sharti		cc_connect_to_user(conn, user);
1052131826Sharti
1053131826Sharti		cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1054131826Sharti		return;
1055131826Sharti	    }
1056131826Sharti
1057131826Sharti
1058131826Sharti	  case USER_SIG_CONNECT_OUTGOING:
1059131826Sharti	    {
1060131826Sharti		/*
1061131826Sharti		 * Request to connect that call
1062131826Sharti		 *
1063131826Sharti		 * Here we assign the connection to a port.
1064131826Sharti		 */
1065131826Sharti		struct uni_msg *msg = arg;
1066131826Sharti		struct atm_connect_outgoing_call *req = uni_msg_rptr(msg,
1067131826Sharti		    struct atm_connect_outgoing_call *);
1068131826Sharti		struct ccdata *priv = user->cc;
1069131826Sharti		struct ccport *port;
1070131826Sharti		struct ccaddr *addr;
1071131826Sharti		struct ccconn *conn = TAILQ_FIRST(&user->connq);
1072131826Sharti
1073131826Sharti		if (user->state != USER_OUT_PREPARING) {
1074131826Sharti			uni_msg_destroy(msg);
1075131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1076131826Sharti			goto bad_state;
1077131826Sharti		}
1078131826Sharti		if (!IE_ISPRESENT(req->called)) {
1079131826Sharti			uni_msg_destroy(msg);
1080131826Sharti			cc_user_err(user, ATMERR_BAD_ARGS);
1081131826Sharti			return;
1082131826Sharti		}
1083131826Sharti		CCASSERT(conn->port == NULL, ("connection still on port"));
1084131826Sharti
1085131826Sharti		if (TAILQ_EMPTY(&priv->port_list)) {
1086131826Sharti			/*
1087131826Sharti			 * We have no ports - reject
1088131826Sharti			 */
1089131826Sharti			uni_msg_destroy(msg);
1090131826Sharti			cc_user_err(user, ATMERR_BAD_PORT);
1091131826Sharti			return;
1092131826Sharti		}
1093131826Sharti
1094131826Sharti		/*
1095131826Sharti		 * Find the correct port
1096131826Sharti		 * Routing of outgoing calls goes to the lowest numbered port
1097131826Sharti		 * with a matching address or, if no address match is found to
1098131826Sharti		 * the lowest numbered port.
1099131826Sharti		 */
1100131826Sharti		TAILQ_FOREACH(port, &priv->port_list, node_link)
1101131826Sharti			TAILQ_FOREACH(addr, &port->addr_list, port_link)
1102131826Sharti				if (addr_matches(addr, conn))
1103131826Sharti					break;
1104131826Sharti
1105131826Sharti		if (port == NULL)
1106131826Sharti			port = TAILQ_FIRST(&priv->port_list);
1107131826Sharti
1108131826Sharti		cc_conn_ins_port(conn, port);
1109131826Sharti		conn->called = req->called;
1110131826Sharti		uni_msg_destroy(msg);
1111131826Sharti
1112131826Sharti		/*
1113131826Sharti		 * Now move the state
1114131826Sharti		 */
1115131826Sharti		set_state(user, USER_OUT_WAIT_OK);
1116131826Sharti		cc_conn_sig(conn, CONN_SIG_CONNECT_OUTGOING, NULL);
1117131826Sharti
1118131826Sharti		return;
1119131826Sharti	    }
1120131826Sharti
1121131826Sharti
1122131826Sharti	  case USER_SIG_CONNECT_OUTGOING_ERR:
1123131826Sharti		switch (user->state) {
1124131826Sharti
1125131826Sharti		  case USER_OUT_WAIT_OK:
1126131826Sharti			set_state(user, USER_OUT_PREPARING);
1127131826Sharti			cc_user_err(user, arg2);
1128131826Sharti			break;
1129131826Sharti
1130131826Sharti		  case USER_REL_WAIT_CONN:
1131131826Sharti		    {
1132131826Sharti			struct ccconn *conn;
1133131826Sharti
1134131826Sharti			conn = TAILQ_FIRST(&user->connq);
1135131826Sharti			if (conn != NULL) {
1136131826Sharti				cc_disconnect_from_user(conn);
1137131826Sharti				cc_conn_destroy(conn);
1138131826Sharti			}
1139131826Sharti
1140131826Sharti			cc_user_reset(user);
1141131826Sharti			cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1142131826Sharti			break;
1143131826Sharti		    }
1144131826Sharti
1145131826Sharti		  default:
1146131826Sharti			goto bad_state;
1147131826Sharti		}
1148131826Sharti		return;
1149131826Sharti
1150131826Sharti
1151131826Sharti	  case USER_SIG_CONNECT_OUTGOING_OK:
1152131826Sharti		switch (user->state) {
1153131826Sharti
1154131826Sharti		  case USER_OUT_WAIT_OK:
1155131826Sharti			set_state(user, USER_OUT_WAIT_CONF);
1156131826Sharti			cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1157131826Sharti			break;
1158131826Sharti
1159131826Sharti		  case USER_REL_WAIT_CONN:
1160131826Sharti			set_state(user, USER_REL_WAIT_SCONF);
1161131826Sharti			break;
1162131826Sharti
1163131826Sharti		  default:
1164131826Sharti			goto bad_state;
1165131826Sharti		}
1166131826Sharti		return;
1167131826Sharti
1168131826Sharti
1169131826Sharti	  case USER_SIG_SETUP_CONFIRM:
1170131826Sharti		/*
1171131826Sharti		 * SETUP.confirm from UNI stack.
1172131826Sharti		 */
1173131826Sharti		switch (user->state) {
1174131826Sharti
1175131826Sharti		  case USER_OUT_WAIT_CONF:
1176131826Sharti			cc_user_active(user);
1177131826Sharti			break;
1178131826Sharti
1179131826Sharti		  case USER_REL_WAIT_SCONF:
1180131826Sharti			/* now try to release */
1181131826Sharti			set_state(user, USER_REL_WAIT_CONF);
1182131826Sharti			cc_conn_sig(TAILQ_FIRST(&user->connq),
1183131826Sharti			    CONN_SIG_RELEASE, NULL);
1184131826Sharti			break;
1185131826Sharti
1186131826Sharti		  default:
1187131826Sharti			goto bad_state;
1188131826Sharti		}
1189131826Sharti		return;
1190131826Sharti
1191131826Sharti
1192131826Sharti	  case USER_SIG_PREPARE_INCOMING:
1193131826Sharti	    {
1194131826Sharti		struct uni_msg *msg = arg;
1195131826Sharti		struct ccuser *ptr;
1196131826Sharti		struct atm_prepare_incoming_call *prep = uni_msg_rptr(msg,
1197131826Sharti		    struct atm_prepare_incoming_call *);
1198131826Sharti
1199131826Sharti		if (user->state != USER_NULL) {
1200131826Sharti			uni_msg_destroy(msg);
1201131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1202131826Sharti			goto bad_state;
1203131826Sharti		}
1204131826Sharti
1205131826Sharti		/*
1206131826Sharti		 * Check the SAP
1207131826Sharti		 */
1208131826Sharti		if (unisve_check_sap(&prep->sap) != UNISVE_OK) {
1209131826Sharti			uni_msg_destroy(msg);
1210131826Sharti			cc_user_err(user, ATMERR_BAD_SAP);
1211131826Sharti			return;
1212131826Sharti		}
1213131826Sharti
1214131826Sharti		/*
1215131826Sharti		 * Loop through all incoming calls and check whether there
1216131826Sharti		 * is an overlap in SAP space.
1217131826Sharti		 */
1218131826Sharti		LIST_FOREACH(ptr, &user->cc->user_list, node_link) {
1219131826Sharti			if (check_overlap(ptr, &prep->sap)) {
1220131826Sharti				uni_msg_destroy(msg);
1221131826Sharti				cc_user_err(user, ATMERR_OVERLAP);
1222131826Sharti				return;
1223131826Sharti			}
1224131826Sharti		}
1225131826Sharti
1226131826Sharti		/*
1227131826Sharti		 * Save info and set state
1228131826Sharti		 */
1229131826Sharti		user->sap = CCZALLOC(sizeof(struct uni_sap));
1230131826Sharti		if (user->sap == NULL) {
1231131826Sharti			uni_msg_destroy(msg);
1232131826Sharti			cc_user_err(user, ATMERR_NOMEM);
1233131826Sharti			return;
1234131826Sharti		}
1235131826Sharti		*user->sap = prep->sap;
1236131826Sharti		user->queue_max = prep->queue_size;
1237131826Sharti		user->queue_act = 0;
1238131826Sharti		uni_msg_destroy(msg);
1239131826Sharti
1240131826Sharti		set_state(user, USER_IN_PREPARING);
1241131826Sharti		cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1242131826Sharti
1243131826Sharti		return;
1244131826Sharti	    }
1245131826Sharti
1246131826Sharti
1247131826Sharti	  case USER_SIG_WAIT_ON_INCOMING:
1248131826Sharti		if (user->state != USER_IN_PREPARING) {
1249131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1250131826Sharti			goto bad_state;
1251131826Sharti		}
1252131826Sharti
1253131826Sharti		set_state(user, USER_IN_WAITING);
1254131826Sharti		cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1255131826Sharti		return;
1256131826Sharti
1257131826Sharti
1258131826Sharti	  case USER_SIG_SETUP_IND:
1259131826Sharti		/*
1260131826Sharti		 * New connection queued up in the queue. If this is the
1261131826Sharti		 * first one, inform the application of the arrival.
1262131826Sharti		 */
1263131826Sharti		switch (user->state) {
1264131826Sharti
1265131826Sharti		  case USER_IN_WAITING:
1266131826Sharti			do_arrival(user);
1267131826Sharti			break;
1268131826Sharti
1269131826Sharti		  case USER_IN_ARRIVED:
1270131826Sharti		  case USER_IN_WAIT_REJ:
1271131826Sharti		  case USER_IN_WAIT_ACC:
1272131826Sharti			break;
1273131826Sharti
1274131826Sharti		  default:
1275131826Sharti			goto bad_state;
1276131826Sharti		}
1277131826Sharti		return;
1278131826Sharti
1279131826Sharti
1280131826Sharti	  case USER_SIG_REJECT_INCOMING:
1281131826Sharti	     {
1282131826Sharti		/*
1283131826Sharti		 * User rejects call. This is done on the OLD user
1284131826Sharti		 * (i.e. the one sending the arrival).
1285131826Sharti		 */
1286131826Sharti		struct uni_msg *msg = arg;
1287131826Sharti		struct atm_reject_incoming_call *rej = uni_msg_rptr(msg,
1288131826Sharti		    struct atm_reject_incoming_call *);
1289131826Sharti		struct ccconn *conn = TAILQ_FIRST(&user->connq);
1290131826Sharti
1291131826Sharti		if (user->state != USER_IN_ARRIVED) {
1292131826Sharti			uni_msg_destroy(msg);
1293131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1294131826Sharti			goto bad_state;
1295131826Sharti		}
1296131826Sharti		if (user->aborted) {
1297131826Sharti			/* connection has disappeared. Send an ok
1298131826Sharti			 * to the user and lock whether there is another
1299131826Sharti			 * connection at this endpoint */
1300133492Sharti			uni_msg_destroy(msg);
1301131826Sharti			cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1302131826Sharti
1303131826Sharti			set_state(user, USER_IN_WAITING);
1304131826Sharti			do_arrival(user);
1305131826Sharti			return;
1306131826Sharti		}
1307131826Sharti		conn->cause[0] = rej->cause;
1308131826Sharti		memset(&conn->cause[1], 0, sizeof(conn->cause[1]));
1309131826Sharti		uni_msg_destroy(msg);
1310131826Sharti
1311131826Sharti		set_state(user, USER_IN_WAIT_REJ);
1312131826Sharti		cc_conn_sig(conn, CONN_SIG_REJECT, NULL);
1313131826Sharti
1314131826Sharti		return;
1315131826Sharti	    }
1316131826Sharti
1317131826Sharti
1318131826Sharti	  case USER_SIG_REJECT_OK:
1319131826Sharti		if (user->state != USER_IN_WAIT_REJ)
1320131826Sharti			goto bad_state;
1321131826Sharti		cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1322131826Sharti
1323131826Sharti		set_state(user, USER_IN_WAITING);
1324131826Sharti		do_arrival(user);
1325131826Sharti		return;
1326131826Sharti
1327131826Sharti
1328131826Sharti	  case USER_SIG_REJECT_ERR:
1329131826Sharti		if (user->state != USER_IN_WAIT_REJ)
1330131826Sharti			goto bad_state;
1331131826Sharti		cc_user_err(user, arg2);
1332131826Sharti
1333131826Sharti		if (arg == NULL)
1334131826Sharti			set_state(user, USER_IN_ARRIVED);
1335131826Sharti		else {
1336131826Sharti			set_state(user, USER_IN_WAITING);
1337131826Sharti			do_arrival(user);
1338131826Sharti		}
1339131826Sharti		return;
1340131826Sharti
1341131826Sharti
1342131826Sharti	  case USER_SIG_ACCEPT_INCOMING:
1343131826Sharti	    {
1344131826Sharti		/*
1345131826Sharti		 * User accepts call. This is done on the OLD user (i.e. the one
1346131826Sharti		 * sending the arrival), the message contains a pointer to the
1347131826Sharti		 * new endpoint.
1348131826Sharti		 */
1349131826Sharti		struct uni_msg *msg = arg;
1350131826Sharti		struct atm_accept_incoming_call *acc =
1351131826Sharti		    uni_msg_rptr(msg, struct atm_accept_incoming_call *);
1352131826Sharti		struct ccuser *newep;
1353131826Sharti
1354131826Sharti		if (user->state != USER_IN_ARRIVED) {
1355131826Sharti			uni_msg_destroy(msg);
1356131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1357131826Sharti			return;
1358131826Sharti		}
1359131826Sharti		if (user->aborted) {
1360131826Sharti			/* connection has disappeared. Send an error
1361131826Sharti			 * to the user and lock whether there is another
1362131826Sharti			 * connection at this endpoint */
1363133492Sharti			uni_msg_destroy(msg);
1364131826Sharti			cc_user_err(user, ATMERR_PREVIOUSLY_ABORTED);
1365131826Sharti
1366131826Sharti			set_state(user, USER_IN_WAITING);
1367131826Sharti			do_arrival(user);
1368131826Sharti			return;
1369131826Sharti		}
1370131826Sharti		acc->newep[sizeof(acc->newep) - 1] = '\0';
1371131826Sharti
1372131826Sharti		LIST_FOREACH(newep, &user->cc->user_list, node_link)
1373131826Sharti			if (strcmp(acc->newep, newep->name) == 0)
1374131826Sharti				break;
1375133492Sharti		uni_msg_destroy(msg);
1376131826Sharti
1377131826Sharti		if (newep == NULL) {
1378131826Sharti			cc_user_err(user, ATMERR_BAD_ENDPOINT);
1379131826Sharti			return;
1380131826Sharti		}
1381131826Sharti
1382131826Sharti		if (newep->state != USER_NULL || newep->accepted != NULL) {
1383131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1384131826Sharti			return;
1385131826Sharti		}
1386131826Sharti
1387131826Sharti		set_state(user, USER_IN_WAIT_ACC);
1388131826Sharti		cc_conn_sig(TAILQ_FIRST(&user->connq), CONN_SIG_ACCEPT, newep);
1389131826Sharti
1390131826Sharti		return;
1391131826Sharti	    }
1392131826Sharti
1393131826Sharti
1394131826Sharti	  case USER_SIG_ACCEPT_OK:
1395131826Sharti		if (user->state != USER_IN_WAIT_ACC)
1396131826Sharti			goto bad_state;
1397131826Sharti		cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1398131826Sharti
1399131826Sharti		set_state(user, USER_IN_WAITING);
1400131826Sharti		do_arrival(user);
1401131826Sharti		return;
1402131826Sharti
1403131826Sharti
1404131826Sharti	  case USER_SIG_ACCEPT_ERR:
1405131826Sharti		if (user->state != USER_IN_WAIT_ACC)
1406131826Sharti			goto bad_state;
1407131826Sharti		cc_user_err(user, arg2);
1408131826Sharti
1409131826Sharti		if (arg == NULL) {
1410131826Sharti			/* arg used as flag! */
1411131826Sharti			set_state(user, USER_IN_ARRIVED);
1412131826Sharti		} else {
1413131826Sharti			set_state(user, USER_IN_WAITING);
1414131826Sharti			do_arrival(user);
1415131826Sharti		}
1416131826Sharti		return;
1417131826Sharti
1418131826Sharti
1419131826Sharti	  case USER_SIG_ACCEPTING:
1420131826Sharti		if (user->state != USER_NULL)
1421131826Sharti			goto bad_state;
1422131826Sharti		set_state(user, USER_IN_ACCEPTING);
1423131826Sharti		return;
1424131826Sharti
1425131826Sharti
1426131826Sharti	  case USER_SIG_SETUP_COMPL:
1427131826Sharti	    {
1428131826Sharti		struct ccconn *conn = TAILQ_FIRST(&user->connq);
1429131826Sharti
1430131826Sharti		if (user->state != USER_IN_ACCEPTING)
1431131826Sharti			goto bad_state;
1432131826Sharti
1433131826Sharti		user->state = USER_ACTIVE;
1434131826Sharti		if (conn->bearer.cfg == UNI_BEARER_P2P) {
1435131826Sharti			struct atm_p2p_call_active *act;
1436131826Sharti
1437131826Sharti			user->config = USER_P2P;
1438131826Sharti			act = CCZALLOC(sizeof(*act));
1439131826Sharti			if (act == NULL)
1440131826Sharti				return;
1441131826Sharti			act->connid = conn->connid;
1442131826Sharti			cc_user_send(user, ATMOP_P2P_CALL_ACTIVE,
1443131826Sharti			    act, sizeof(*act));
1444131826Sharti			CCFREE(act);
1445131826Sharti		} else {
1446131826Sharti			struct atm_p2mp_call_active *act;
1447131826Sharti
1448131826Sharti			user->config = USER_LEAF;
1449131826Sharti			act = CCZALLOC(sizeof(*act));
1450131826Sharti			if (act == NULL)
1451131826Sharti				return;
1452131826Sharti			act->connid = conn->connid;
1453131826Sharti			cc_user_send(user, ATMOP_P2MP_CALL_ACTIVE,
1454131826Sharti			    act, sizeof(*act));
1455131826Sharti			CCFREE(act);
1456131826Sharti		}
1457131826Sharti		return;
1458131826Sharti	    }
1459131826Sharti
1460131826Sharti
1461131826Sharti	  case USER_SIG_CALL_RELEASE:
1462131826Sharti	    {
1463131826Sharti		struct uni_msg *msg = arg;
1464131826Sharti		struct atm_call_release *api = uni_msg_rptr(msg,
1465131826Sharti		    struct atm_call_release *);
1466131826Sharti		struct ccconn *conn;
1467131826Sharti
1468131826Sharti		conn = TAILQ_FIRST(&user->connq);
1469131826Sharti		switch (user->state) {
1470131826Sharti
1471131826Sharti		  case USER_OUT_WAIT_OK:	/* U2/A3 */
1472131826Sharti			/* wait for CONN_OK first */
1473131826Sharti			conn->cause[0] = api->cause[0];
1474131826Sharti			conn->cause[1] = api->cause[1];
1475131826Sharti			set_state(user, USER_REL_WAIT_CONN);
1476131826Sharti			break;
1477131826Sharti
1478131826Sharti		  case USER_OUT_WAIT_CONF:	/* U3/A3 */
1479131826Sharti			/* wait for SETUP.confirm first */
1480131826Sharti			conn->cause[0] = api->cause[0];
1481131826Sharti			conn->cause[1] = api->cause[1];
1482131826Sharti			set_state(user, USER_REL_WAIT_SCONF);
1483131826Sharti			break;
1484131826Sharti
1485131826Sharti		  case USER_IN_ACCEPTING:	/* U11/A7 */
1486131826Sharti			conn->cause[0] = api->cause[0];
1487131826Sharti			conn->cause[1] = api->cause[1];
1488131826Sharti			set_state(user, USER_REL_WAIT_SCOMP);
1489131826Sharti			cc_conn_sig(conn, CONN_SIG_RELEASE, NULL);
1490131826Sharti			break;
1491131826Sharti
1492131826Sharti		  case USER_ACTIVE:		/* U4/A8,A9,A10 */
1493131826Sharti			conn->cause[0] = api->cause[0];
1494131826Sharti			conn->cause[1] = api->cause[1];
1495131826Sharti			set_state(user, USER_REL_WAIT);
1496131826Sharti			cc_conn_sig(conn, CONN_SIG_RELEASE, NULL);
1497131826Sharti			break;
1498131826Sharti
1499131826Sharti		  default:
1500131826Sharti			uni_msg_destroy(msg);
1501131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1502131826Sharti			goto bad_state;
1503131826Sharti		}
1504131826Sharti		uni_msg_destroy(msg);
1505131826Sharti		return;
1506131826Sharti	    }
1507131826Sharti
1508131826Sharti
1509131826Sharti	  case USER_SIG_RELEASE_CONFIRM:
1510131826Sharti	    {
1511131826Sharti		struct atm_call_release *ind;
1512131826Sharti
1513131826Sharti		switch (user->state) {
1514131826Sharti
1515131826Sharti		  case USER_OUT_WAIT_CONF:	/* U3/A3 */
1516131826Sharti		  case USER_ACTIVE:		/* U4/A8,A9,A10 */
1517131826Sharti			cc_user_reset(user);
1518131826Sharti			break;
1519131826Sharti
1520131826Sharti		  case USER_REL_WAIT:		/* U5 /A8,A9,A10 */
1521131826Sharti		  case USER_REL_WAIT_SCOMP:	/* U12/A7 */
1522131826Sharti		  case USER_REL_WAIT_SCONF:	/* U13/A3 */
1523131826Sharti		  case USER_REL_WAIT_CONF:	/* U14/A3 */
1524131826Sharti			cc_user_reset(user);
1525131826Sharti			cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1526131826Sharti			return;
1527131826Sharti
1528131826Sharti		  case USER_IN_ACCEPTING:	/* U11/A7 */
1529131826Sharti			cc_user_reset(user);
1530131826Sharti			break;
1531131826Sharti
1532131826Sharti		  default:
1533131826Sharti			goto bad_state;
1534131826Sharti		}
1535131826Sharti
1536131826Sharti		ind = CCZALLOC(sizeof(*ind));
1537131826Sharti		if (ind == NULL)
1538131826Sharti			return;
1539131826Sharti		memcpy(ind->cause, user->cause, sizeof(ind->cause));
1540131826Sharti		cc_user_send(user, ATMOP_CALL_RELEASE, ind, sizeof(*ind));
1541131826Sharti		CCFREE(ind);
1542131826Sharti		return;
1543131826Sharti	    }
1544131826Sharti
1545131826Sharti
1546131826Sharti	  case USER_SIG_RELEASE_ERR:
1547131826Sharti		switch (user->state) {
1548131826Sharti
1549131826Sharti		  case USER_REL_WAIT:		/* U5/A8,A9,A10 */
1550131826Sharti			set_state(user, USER_ACTIVE);
1551131826Sharti			cc_user_err(user, ATM_MKUNIERR(arg2));
1552131826Sharti			break;
1553131826Sharti
1554131826Sharti		  case USER_REL_WAIT_CONF:	/* U14/A3 */
1555131826Sharti			cc_user_err(user, ATM_MKUNIERR(arg2));
1556131826Sharti			cc_user_active(user);
1557131826Sharti			break;
1558131826Sharti
1559131826Sharti		  case USER_REL_WAIT_SCOMP:	/* U12/A7 */
1560131826Sharti			set_state(user, USER_IN_ACCEPTING);
1561131826Sharti			cc_user_err(user, ATM_MKUNIERR(arg2));
1562131826Sharti			break;
1563131826Sharti
1564131826Sharti		  default:
1565131826Sharti			goto bad_state;
1566131826Sharti		}
1567131826Sharti		return;
1568131826Sharti
1569131826Sharti
1570131826Sharti	  case USER_SIG_ADD_PARTY:
1571131826Sharti	    {
1572131826Sharti		struct uni_msg *msg = arg;
1573131826Sharti		struct atm_add_party *add = uni_msg_rptr(msg,
1574131826Sharti		    struct atm_add_party *);
1575131826Sharti		struct ccconn *conn;
1576131826Sharti
1577131826Sharti		if (user->state != USER_ACTIVE || user->config != USER_ROOT) {
1578131826Sharti			uni_msg_destroy(msg);
1579131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1580131826Sharti			return;
1581131826Sharti		}
1582131826Sharti
1583131826Sharti		if (add->leaf_ident == 0 || add->leaf_ident >= 32786) {
1584131826Sharti			uni_msg_destroy(msg);
1585131826Sharti			cc_user_err(user, ATMERR_BAD_LEAF_IDENT);
1586131826Sharti			return;
1587131826Sharti		}
1588131826Sharti
1589131826Sharti		conn = TAILQ_FIRST(&user->connq);
1590131826Sharti		conn->called = add->called;
1591131826Sharti
1592131826Sharti		cc_conn_sig(conn, CONN_SIG_ADD_PARTY,
1593131826Sharti		    (void *)(uintptr_t)add->leaf_ident);
1594131826Sharti
1595131826Sharti		uni_msg_destroy(msg);
1596131826Sharti		return;
1597131826Sharti	    }
1598131826Sharti
1599131826Sharti
1600131826Sharti	  case USER_SIG_ADD_PARTY_ERR:
1601131826Sharti		if (user->state != USER_ACTIVE)
1602131826Sharti			goto bad_state;
1603131826Sharti		cc_user_err(user, arg2);
1604131826Sharti		return;
1605131826Sharti
1606131826Sharti
1607131826Sharti	  case USER_SIG_ADD_PARTY_OK:
1608131826Sharti		if (user->state != USER_ACTIVE)
1609131826Sharti			goto bad_state;
1610131826Sharti		cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1611131826Sharti		return;
1612131826Sharti
1613131826Sharti
1614131826Sharti	  case USER_SIG_ADD_PARTY_ACK:
1615131826Sharti	    {
1616131826Sharti		u_int leaf_ident = arg2;
1617131826Sharti		struct atm_add_party_success *succ;
1618131826Sharti
1619131826Sharti		if (user->state != USER_ACTIVE)
1620131826Sharti			goto bad_state;
1621131826Sharti
1622131826Sharti		succ = CCZALLOC(sizeof(*succ));
1623131826Sharti		if (succ == NULL)
1624131826Sharti			return;
1625131826Sharti
1626131826Sharti		succ->leaf_ident = leaf_ident;
1627131826Sharti		cc_user_send(user, ATMOP_ADD_PARTY_SUCCESS,
1628131826Sharti		    succ, sizeof(*succ));
1629131826Sharti
1630131826Sharti		CCFREE(succ);
1631131826Sharti		return;
1632131826Sharti	    }
1633131826Sharti
1634131826Sharti
1635131826Sharti	  case USER_SIG_ADD_PARTY_REJ:
1636131826Sharti	    {
1637131826Sharti		u_int leaf_ident = arg2;
1638131826Sharti		struct atm_add_party_reject *reject;
1639131826Sharti
1640131826Sharti		if (user->state != USER_ACTIVE)
1641131826Sharti			goto bad_state;
1642131826Sharti
1643131826Sharti		reject = CCZALLOC(sizeof(*reject));
1644131826Sharti		if (reject == NULL)
1645131826Sharti			return;
1646131826Sharti
1647131826Sharti		reject->leaf_ident = leaf_ident;
1648131826Sharti		reject->cause = user->cause[0];
1649131826Sharti		cc_user_send(user, ATMOP_ADD_PARTY_REJECT,
1650131826Sharti		    reject, sizeof(*reject));
1651131826Sharti
1652131826Sharti		CCFREE(reject);
1653131826Sharti		return;
1654131826Sharti	    }
1655131826Sharti
1656131826Sharti
1657131826Sharti	  case USER_SIG_DROP_PARTY:
1658131826Sharti	    {
1659131826Sharti		struct uni_msg *msg = arg;
1660131826Sharti		struct atm_drop_party *drop = uni_msg_rptr(msg,
1661131826Sharti		    struct atm_drop_party *);
1662131826Sharti		struct ccconn *conn;
1663131826Sharti
1664131826Sharti		if (user->state != USER_ACTIVE || user->config != USER_ROOT) {
1665131826Sharti			uni_msg_destroy(msg);
1666131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1667131826Sharti			return;
1668131826Sharti		}
1669131826Sharti
1670131826Sharti		if (drop->leaf_ident >= 32786) {
1671131826Sharti			uni_msg_destroy(msg);
1672131826Sharti			cc_user_err(user, ATMERR_BAD_LEAF_IDENT);
1673131826Sharti			return;
1674131826Sharti		}
1675131826Sharti
1676131826Sharti		conn = TAILQ_FIRST(&user->connq);
1677131826Sharti		conn->cause[0] = drop->cause;
1678131826Sharti		memset(&conn->cause[1], 0, sizeof(conn->cause[1]));
1679131826Sharti
1680131826Sharti		cc_conn_sig(conn, CONN_SIG_DROP_PARTY,
1681131826Sharti		    (void *)(uintptr_t)drop->leaf_ident);
1682131826Sharti
1683131826Sharti		uni_msg_destroy(msg);
1684131826Sharti		return;
1685131826Sharti	    }
1686131826Sharti
1687131826Sharti
1688131826Sharti	  case USER_SIG_DROP_PARTY_ERR:
1689131826Sharti		if (user->state != USER_ACTIVE)
1690131826Sharti			goto bad_state;
1691131826Sharti		cc_user_err(user, arg2);
1692131826Sharti		return;
1693131826Sharti
1694131826Sharti
1695131826Sharti	  case USER_SIG_DROP_PARTY_OK:
1696131826Sharti		if (user->state != USER_ACTIVE)
1697131826Sharti			goto bad_state;
1698131826Sharti		cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1699131826Sharti		return;
1700131826Sharti
1701131826Sharti
1702131826Sharti	  case USER_SIG_DROP_PARTY_IND:
1703131826Sharti	    {
1704131826Sharti		u_int leaf_ident = arg2;
1705131826Sharti		struct atm_drop_party *drop;
1706131826Sharti
1707131826Sharti		if (user->state != USER_ACTIVE)
1708131826Sharti			goto bad_state;
1709131826Sharti
1710131826Sharti		drop = CCZALLOC(sizeof(*drop));
1711131826Sharti		if (drop == NULL)
1712131826Sharti			return;
1713131826Sharti
1714131826Sharti		drop->leaf_ident = leaf_ident;
1715131826Sharti		drop->cause = user->cause[0];
1716131826Sharti		cc_user_send(user, ATMOP_DROP_PARTY, drop, sizeof(*drop));
1717131826Sharti
1718131826Sharti		CCFREE(drop);
1719131826Sharti		return;
1720131826Sharti	    }
1721131826Sharti
1722131826Sharti
1723131826Sharti	  case USER_SIG_QUERY_ATTR:
1724131826Sharti	    {
1725131826Sharti		struct uni_msg *msg = arg;
1726131826Sharti		struct atm_query_connection_attributes *req;
1727131826Sharti		struct ccconn *conn;
1728131826Sharti
1729131826Sharti		if (user->aborted) {
1730131826Sharti			cc_user_err(user, ATMERR_PREVIOUSLY_ABORTED);
1731131826Sharti			uni_msg_destroy(msg);
1732131826Sharti			return;
1733131826Sharti		}
1734131826Sharti		conn = cc_query_check(user);
1735131826Sharti		if (conn == NULL) {
1736131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1737131826Sharti			uni_msg_destroy(msg);
1738131826Sharti			return;
1739131826Sharti		}
1740131826Sharti		req = uni_msg_rptr(msg,
1741131826Sharti		    struct atm_query_connection_attributes *);
1742131826Sharti		cc_attr_query(user, conn, &req->attr, 1);
1743131826Sharti		uni_msg_destroy(msg);
1744131826Sharti		return;
1745131826Sharti	    }
1746131826Sharti
1747131826Sharti	  case USER_SIG_QUERY_ATTR_X:
1748131826Sharti	    {
1749131826Sharti		struct uni_msg *msg = arg;
1750131826Sharti		struct atm_query_connection_attributes_x *req;
1751131826Sharti		struct ccconn *conn;
1752131826Sharti
1753131826Sharti		conn = cc_query_check(user);
1754131826Sharti		if (conn == NULL) {
1755131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1756131826Sharti			uni_msg_destroy(msg);
1757131826Sharti			return;
1758131826Sharti		}
1759131826Sharti		req = uni_msg_rptr(msg,
1760131826Sharti		    struct atm_query_connection_attributes_x *);
1761131826Sharti		cc_attr_query(user, conn, req->attr, req->count);
1762131826Sharti		uni_msg_destroy(msg);
1763131826Sharti		return;
1764131826Sharti	    }
1765131826Sharti
1766131826Sharti	  case USER_SIG_SET_ATTR:
1767131826Sharti	    {
1768131826Sharti		struct uni_msg *msg = arg;
1769131826Sharti		struct atm_set_connection_attributes *req;
1770131826Sharti		struct ccconn *conn;
1771131826Sharti
1772131826Sharti		if (user->aborted) {
1773131826Sharti			cc_user_err(user, ATMERR_PREVIOUSLY_ABORTED);
1774131826Sharti			uni_msg_destroy(msg);
1775131826Sharti			return;
1776131826Sharti		}
1777131826Sharti		conn = cc_set_check(user);
1778131826Sharti		if (conn == NULL) {
1779131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1780131826Sharti			uni_msg_destroy(msg);
1781131826Sharti			return;
1782131826Sharti		}
1783131826Sharti		req = uni_msg_rptr(msg, struct atm_set_connection_attributes *);
1784131826Sharti		cc_attr_set(user, conn, &req->attr, 1, (u_char *)(req + 1),
1785131826Sharti		    uni_msg_len(msg) - sizeof(*req));
1786131826Sharti		uni_msg_destroy(msg);
1787131826Sharti		return;
1788131826Sharti	    }
1789131826Sharti
1790131826Sharti	  case USER_SIG_SET_ATTR_X:
1791131826Sharti	    {
1792131826Sharti		struct uni_msg *msg = arg;
1793131826Sharti		struct atm_set_connection_attributes_x *req;
1794131826Sharti		struct ccconn *conn;
1795131826Sharti
1796131826Sharti		conn = cc_set_check(user);
1797131826Sharti		if (conn == NULL) {
1798131826Sharti			cc_user_err(user, ATMERR_BAD_STATE);
1799131826Sharti			uni_msg_destroy(msg);
1800131826Sharti			return;
1801131826Sharti		}
1802131826Sharti		req = uni_msg_rptr(msg,
1803131826Sharti		    struct atm_set_connection_attributes_x *);
1804131826Sharti		cc_attr_set(user, conn, req->attr, req->count,
1805131826Sharti		    (u_char *)req->attr + req->count * sizeof(req->attr[0]),
1806131826Sharti		    uni_msg_len(msg) -
1807131826Sharti		    offsetof(struct atm_set_connection_attributes_x, attr) -
1808131826Sharti		    req->count * sizeof(req->attr[0]));
1809131826Sharti		uni_msg_destroy(msg);
1810131826Sharti		return;
1811131826Sharti	    }
1812131826Sharti
1813131826Sharti	  case USER_SIG_QUERY_STATE:
1814131826Sharti	    {
1815131826Sharti		struct atm_epstate state;
1816131826Sharti
1817131826Sharti		strcpy(state.name, user->name);
1818131826Sharti		switch (user->state) {
1819131826Sharti
1820131826Sharti		  case USER_NULL:
1821131826Sharti			if (user->accepted != NULL)
1822131826Sharti				state.state = ATM_A7;
1823131826Sharti			else
1824131826Sharti				state.state = ATM_A1;
1825131826Sharti			break;
1826131826Sharti
1827131826Sharti		  case USER_OUT_PREPARING:
1828131826Sharti			state.state = ATM_A2;
1829131826Sharti			break;
1830131826Sharti
1831131826Sharti		  case USER_OUT_WAIT_OK:
1832131826Sharti		  case USER_OUT_WAIT_CONF:
1833131826Sharti		  case USER_REL_WAIT_SCONF:
1834131826Sharti		  case USER_REL_WAIT_CONF:
1835131826Sharti		  case USER_REL_WAIT_CONN:
1836131826Sharti			state.state = ATM_A3;
1837131826Sharti			break;
1838131826Sharti
1839131826Sharti		  case USER_ACTIVE:
1840131826Sharti		  case USER_REL_WAIT:
1841131826Sharti			switch (user->config) {
1842131826Sharti
1843131826Sharti			  case USER_P2P:
1844131826Sharti				state.state = ATM_A8;
1845131826Sharti				break;
1846131826Sharti
1847131826Sharti			  case USER_ROOT:
1848131826Sharti				state.state = ATM_A9;
1849131826Sharti				break;
1850131826Sharti
1851131826Sharti			  case USER_LEAF:
1852131826Sharti				state.state = ATM_A10;
1853131826Sharti				break;
1854131826Sharti			}
1855131826Sharti			break;
1856131826Sharti
1857131826Sharti		  case USER_IN_PREPARING:
1858131826Sharti			state.state = ATM_A4;
1859131826Sharti			break;
1860131826Sharti
1861131826Sharti		  case USER_IN_WAITING:
1862131826Sharti			state.state = ATM_A5;
1863131826Sharti			break;
1864131826Sharti
1865131826Sharti		  case USER_IN_ARRIVED:
1866131826Sharti		  case USER_IN_WAIT_REJ:
1867131826Sharti		  case USER_IN_WAIT_ACC:
1868131826Sharti			state.state = ATM_A6;
1869131826Sharti			break;
1870131826Sharti
1871131826Sharti		  case USER_IN_ACCEPTING:
1872131826Sharti		  case USER_REL_WAIT_SCOMP:
1873131826Sharti			state.state = ATM_A7;
1874131826Sharti			break;
1875131826Sharti		}
1876131826Sharti		cc_user_ok(user, ATMRESP_STATE, &state, sizeof(state));
1877131826Sharti		return;
1878131826Sharti	    }
1879131826Sharti
1880131826Sharti	  case USER_SIG_GET_LOCAL_PORT_INFO:
1881131826Sharti	    {
1882131826Sharti		struct uni_msg *msg = arg;
1883131826Sharti		struct atm_port_list *list;
1884131826Sharti		size_t list_len;
1885131826Sharti
1886131826Sharti		list = cc_get_local_port_info(user->cc,
1887131826Sharti		    uni_msg_rptr(msg, struct atm_get_local_port_info *)->port,
1888131826Sharti		    &list_len);
1889131826Sharti		uni_msg_destroy(msg);
1890131826Sharti		if (list == NULL) {
1891131826Sharti			cc_user_err(user, ATMERR_NOMEM);
1892131826Sharti			return;
1893131826Sharti		}
1894131826Sharti		cc_user_ok(user, ATMRESP_PORTS, list, list_len);
1895131826Sharti		CCFREE(list);
1896131826Sharti		return;
1897131826Sharti	    }
1898131826Sharti
1899131826Sharti	  case USER_SIG_ABORT_CONNECTION:
1900131826Sharti	    {
1901131826Sharti		struct uni_msg *msg = arg;
1902131826Sharti		struct atm_abort_connection *abo = uni_msg_rptr(msg,
1903131826Sharti		    struct atm_abort_connection *);
1904131826Sharti
1905131826Sharti		cc_user_abort(user, &abo->cause);
1906131826Sharti		uni_msg_destroy(msg);
1907131826Sharti		cc_user_ok(user, ATMRESP_NONE, NULL, 0);
1908131826Sharti		return;
1909131826Sharti	    }
1910131826Sharti
1911131826Sharti	}
1912131826Sharti	if (user->cc->log & CCLOG_USER_SIG)
1913131826Sharti		cc_user_log(user, "bad signal=%u in state=%u",
1914131826Sharti		    sig, user->state);
1915131826Sharti	return;
1916131826Sharti
1917131826Sharti  bad_state:
1918131826Sharti	if (user->cc->log & CCLOG_USER_SIG)
1919131826Sharti		cc_user_log(user, "bad state=%u for signal=%u",
1920131826Sharti		    user->state, sig);
1921131826Sharti	return;
1922131826Sharti}
1923