1/*
2 * Copyright (c) 1996-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 * 	All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * Author: Hartmut Brandt <harti@freebsd.org>
28 *
29 * $Begemot: libunimsg/netnatm/sig/sig_uni.c,v 1.11 2004/08/05 07:11:03 brandt Exp $
30 *
31 * Instance handling
32 */
33
34#include <netnatm/unimsg.h>
35#include <netnatm/saal/sscopdef.h>
36#include <netnatm/saal/sscfudef.h>
37#include <netnatm/msg/unistruct.h>
38#include <netnatm/msg/unimsglib.h>
39#include <netnatm/sig/uni.h>
40#include <netnatm/sig/unisig.h>
41
42#include <netnatm/sig/unipriv.h>
43
44#ifdef UNICORE
45UNICORE
46#endif
47
48#define STR(S) [S] = #S
49static const char *custat_names[] = {
50	STR(CU_STAT0),
51	STR(CU_STAT1),
52	STR(CU_STAT2),
53	STR(CU_STAT3),
54};
55static const char *globstat_names[] = {
56	STR(UNI_CALLSTATE_REST0),
57	STR(UNI_CALLSTATE_REST1),
58	STR(UNI_CALLSTATE_REST2),
59};
60
61static const char *sig_names[] = {
62	STR(UNIAPI_ERROR),
63	STR(UNIAPI_CALL_CREATED),
64	STR(UNIAPI_CALL_DESTROYED),
65	STR(UNIAPI_PARTY_CREATED),
66	STR(UNIAPI_PARTY_DESTROYED),
67	STR(UNIAPI_LINK_ESTABLISH_request),
68	STR(UNIAPI_LINK_ESTABLISH_confirm),
69	STR(UNIAPI_LINK_RELEASE_request),
70	STR(UNIAPI_LINK_RELEASE_confirm),
71	STR(UNIAPI_RESET_request),
72	STR(UNIAPI_RESET_confirm),
73	STR(UNIAPI_RESET_indication),
74	STR(UNIAPI_RESET_ERROR_indication),
75	STR(UNIAPI_RESET_response),
76	STR(UNIAPI_RESET_ERROR_response),
77	STR(UNIAPI_RESET_STATUS_indication),
78	STR(UNIAPI_SETUP_request),
79	STR(UNIAPI_SETUP_indication),
80	STR(UNIAPI_SETUP_response),
81	STR(UNIAPI_SETUP_confirm),
82	STR(UNIAPI_SETUP_COMPLETE_indication),
83	STR(UNIAPI_SETUP_COMPLETE_request),
84	STR(UNIAPI_ALERTING_request),
85	STR(UNIAPI_ALERTING_indication),
86	STR(UNIAPI_PROCEEDING_request),
87	STR(UNIAPI_PROCEEDING_indication),
88	STR(UNIAPI_RELEASE_request),
89	STR(UNIAPI_RELEASE_indication),
90	STR(UNIAPI_RELEASE_response),
91	STR(UNIAPI_RELEASE_confirm),
92	STR(UNIAPI_NOTIFY_request),
93	STR(UNIAPI_NOTIFY_indication),
94	STR(UNIAPI_STATUS_indication),
95	STR(UNIAPI_STATUS_ENQUIRY_request),
96	STR(UNIAPI_ADD_PARTY_request),
97	STR(UNIAPI_ADD_PARTY_indication),
98	STR(UNIAPI_PARTY_ALERTING_request),
99	STR(UNIAPI_PARTY_ALERTING_indication),
100	STR(UNIAPI_ADD_PARTY_ACK_request),
101	STR(UNIAPI_ADD_PARTY_ACK_indication),
102	STR(UNIAPI_ADD_PARTY_REJ_request),
103	STR(UNIAPI_ADD_PARTY_REJ_indication),
104	STR(UNIAPI_DROP_PARTY_request),
105	STR(UNIAPI_DROP_PARTY_indication),
106	STR(UNIAPI_DROP_PARTY_ACK_request),
107	STR(UNIAPI_DROP_PARTY_ACK_indication),
108	STR(UNIAPI_ABORT_CALL_request),
109};
110
111static const char *verb_names[] = {
112# define UNI_DEBUG_DEFINE(D) [UNI_FAC_##D] = #D,
113	UNI_DEBUG_FACILITIES
114# undef UNI_DEBUG_DEFINE
115};
116
117const char *
118uni_facname(enum uni_verb fac)
119{
120	static char buf[40];
121
122	if (fac >= UNI_MAXFACILITY) {
123		sprintf(buf, "FAC%u", fac);
124		return (buf);
125	}
126	return (verb_names[fac]);
127}
128
129const char *
130uni_signame(enum uni_sig sig)
131{
132	static char buf[40];
133
134	if (sig >= UNIAPI_MAXSIG) {
135		sprintf(buf, "UNIAPI_SIG%u", sig);
136		return (buf);
137	}
138	return (sig_names[sig]);
139}
140
141struct unicx *
142uni_context(struct uni *uni)
143{
144	return (&uni->cx);
145}
146
147static void
148uni_init(struct uni *uni)
149{
150	uni->working = 0;
151	uni->cref_alloc = 12;
152	uni->custat = CU_STAT0;
153	uni->glob_start = UNI_CALLSTATE_REST0;
154	uni->glob_respond = UNI_CALLSTATE_REST0;
155}
156
157static void
158uni_stop(struct uni *uni)
159{
160	struct call *c;
161
162	while ((c = TAILQ_FIRST(&uni->calls)) != NULL) {
163		TAILQ_REMOVE(&uni->calls, c, link);
164		uni_destroy_call(c, 1);
165	}
166
167	SIGQ_CLEAR(&uni->workq);
168	SIGQ_CLEAR(&uni->delq);
169}
170
171/*
172 * INSTANCE HANDLING
173 */
174struct uni *
175uni_create(void *arg, const struct uni_funcs *funcs)
176{
177	struct uni *uni;
178
179	if ((uni = INS_ALLOC()) == NULL)
180		return (NULL);
181
182	uni_init(uni);
183
184	uni->funcs = funcs;
185	uni->arg = arg;
186	uni->proto = UNIPROTO_UNI40U;
187	uni->sb_tb = 0;
188	TAILQ_INIT(&uni->workq);
189	TAILQ_INIT(&uni->delq);
190	TIMER_INIT_UNI(uni, t309);
191	uni->timer309 = UNI_T309_DEFAULT;
192	TAILQ_INIT(&uni->calls);
193	uni_initcx(&uni->cx);
194	TIMER_INIT_UNI(uni, t317);
195	TIMER_INIT_UNI(uni, t316);
196
197	uni->timer301 = UNI_T301_DEFAULT;
198	uni->init303 = UNI_T303_CNT_DEFAULT;
199	uni->timer303 = UNI_T303_DEFAULT;
200	uni->init308 = UNI_T308_CNT_DEFAULT;
201	uni->timer308 = UNI_T308_DEFAULT;
202	uni->timer310 = UNI_T310U_DEFAULT;
203	uni->timer313 = UNI_T313_DEFAULT;
204	uni->init316 = UNI_T316_CNT_DEFAULT;
205	uni->timer316 = UNI_T316_DEFAULT;
206	uni->timer317 = UNI_T317_DEFAULT;
207	uni->timer322 = UNI_T322_DEFAULT;
208	uni->init322 = UNI_T322_CNT_DEFAULT;
209	uni->timer397 = UNI_T397_DEFAULT;
210	uni->timer398 = UNI_T398_DEFAULT;
211	uni->timer399 = UNI_T399U_DEFAULT;
212
213	return (uni);
214}
215
216void
217uni_destroy(struct uni *uni)
218{
219	uni_stop(uni);
220
221	TIMER_DESTROY_UNI(uni, t309);
222	TIMER_DESTROY_UNI(uni, t316);
223	TIMER_DESTROY_UNI(uni, t317);
224
225	INS_FREE(uni);
226}
227
228void
229uni_reset(struct uni *uni)
230{
231	uni_stop(uni);
232	uni_init(uni);
233}
234
235
236/*
237 * DISPATCH SSCOP SIGNAL
238 */
239void
240uni_saal_input(struct uni *uni, enum saal_sig sig, struct uni_msg *m)
241{
242	switch (sig) {
243
244	  case SAAL_ESTABLISH_indication:
245		if (m != NULL)
246			uni_msg_destroy(m);
247		uni_enq_coord(uni, SIGO_SAAL_ESTABLISH_indication, 0, NULL);
248		break;
249
250	  case SAAL_ESTABLISH_confirm:
251		if (m != NULL)
252			uni_msg_destroy(m);
253		uni_enq_coord(uni, SIGO_SAAL_ESTABLISH_confirm, 0, NULL);
254		break;
255
256	  case SAAL_RELEASE_confirm:
257		if (m != NULL)
258			uni_msg_destroy(m);
259		uni_enq_coord(uni, SIGO_SAAL_RELEASE_confirm, 0, NULL);
260		break;
261
262	  case SAAL_RELEASE_indication:
263		if (m != NULL)
264			uni_msg_destroy(m);
265		uni_enq_coord(uni, SIGO_SAAL_RELEASE_indication, 0, NULL);
266		break;
267
268	  case SAAL_DATA_indication:
269		uni_enq_coord(uni, SIGO_SAAL_DATA_indication, 0, m);
270		break;
271
272	  case SAAL_UDATA_indication:
273		uni_enq_coord(uni, SIGO_SAAL_UDATA_indication, 0, m);
274		break;
275
276	  default:
277		VERBOSE(uni, UNI_FAC_ERR, 1, "bogus saal signal %u", sig);
278		if (m != NULL)
279			uni_msg_destroy(m);
280		break;
281	}
282}
283
284static struct {
285	const char	*name;
286	enum uni_sig	sig;
287	size_t		arglen;
288	u_int		coord_sig;
289	u_int		proto;
290#define UNIU	0x01
291#define UNIN	0x02
292#define PNNI	0x04
293} maptab[] = {
294	{ "LINK-ESTABLISH.request", UNIAPI_LINK_ESTABLISH_request,
295	    0,
296	    SIGO_LINK_ESTABLISH_request, UNIU | UNIN },
297	{ "LINK-RELEASE.request", UNIAPI_LINK_RELEASE_request,
298	    0,
299	    SIGO_LINK_RELEASE_request, UNIU | UNIN },
300
301	{ "RESET.request", UNIAPI_RESET_request,
302	    sizeof(struct uniapi_reset_request),
303	    SIGO_RESET_request, UNIU | UNIN },
304	{ "RESET-ERROR.response", UNIAPI_RESET_ERROR_response,
305	    sizeof(struct uniapi_reset_error_response),
306	    SIGO_RESET_ERROR_response, UNIU | UNIN },
307	{ "RESET.response", UNIAPI_RESET_response,
308	    sizeof(struct uniapi_reset_response),
309	    SIGO_RESET_response, UNIU | UNIN },
310
311	{ "SETUP.request", UNIAPI_SETUP_request,
312	    sizeof(struct uniapi_setup_request),
313	    SIGO_SETUP_request, UNIU | UNIN },
314	{ "SETUP.response", UNIAPI_SETUP_response,
315	    sizeof(struct uniapi_setup_response),
316	    SIGO_SETUP_response, UNIU | UNIN },
317	{ "SETUP-COMPLETE.request", UNIAPI_SETUP_COMPLETE_request,
318	    sizeof(struct uniapi_setup_complete_request),
319	    SIGO_SETUP_COMPLETE_request, UNIN },
320	{ "PROCEEDING.request", UNIAPI_PROCEEDING_request,
321	    sizeof(struct uniapi_proceeding_request),
322	    SIGO_PROCEEDING_request, UNIU | UNIN },
323	{ "ALERTING.request", UNIAPI_ALERTING_request,
324	    sizeof(struct uniapi_alerting_request),
325	    SIGO_ALERTING_request, UNIU | UNIN },
326	{ "RELEASE.request", UNIAPI_RELEASE_request,
327	    sizeof(struct uniapi_release_request),
328	    SIGO_RELEASE_request, UNIU | UNIN },
329	{ "RELEASE.response", UNIAPI_RELEASE_response,
330	    sizeof(struct uniapi_release_response),
331	    SIGO_RELEASE_response, UNIU | UNIN },
332	{ "NOTIFY.request", UNIAPI_NOTIFY_request,
333	    sizeof(struct uniapi_notify_request),
334	    SIGO_NOTIFY_request, UNIU | UNIN },
335	{ "STATUS-ENQUIRY.request", UNIAPI_STATUS_ENQUIRY_request,
336	    sizeof(struct uniapi_status_enquiry_request),
337	    SIGO_STATUS_ENQUIRY_request, UNIU | UNIN },
338
339	{ "ADD-PARTY.request", UNIAPI_ADD_PARTY_request,
340	    sizeof(struct uniapi_add_party_request),
341	    SIGO_ADD_PARTY_request, UNIU | UNIN },
342	{ "ADD-PARTY-ACK.request", UNIAPI_ADD_PARTY_ACK_request,
343	    sizeof(struct uniapi_add_party_ack_request),
344	    SIGO_ADD_PARTY_ACK_request, UNIU | UNIN },
345	{ "ADD-PARTY-REJ.request", UNIAPI_ADD_PARTY_REJ_request,
346	    sizeof(struct uniapi_add_party_rej_request),
347	    SIGO_ADD_PARTY_REJ_request, UNIU | UNIN },
348	{ "PARTY-ALERTING.request", UNIAPI_PARTY_ALERTING_request,
349	    sizeof(struct uniapi_party_alerting_request),
350	    SIGO_PARTY_ALERTING_request, UNIU | UNIN },
351	{ "DROP-PARTY.request", UNIAPI_DROP_PARTY_request,
352	    sizeof(struct uniapi_drop_party_request),
353	    SIGO_DROP_PARTY_request, UNIU | UNIN },
354	{ "DROP-PARTY-ACK.request", UNIAPI_DROP_PARTY_ACK_request,
355	    sizeof(struct uniapi_drop_party_ack_request),
356	    SIGO_DROP_PARTY_ACK_request, UNIU | UNIN },
357
358	{ "ABORT-CALL.request", UNIAPI_ABORT_CALL_request,
359	    sizeof(struct uniapi_abort_call_request),
360	    SIGO_ABORT_CALL_request, UNIU | UNIN },
361
362	{ NULL, 0, 0, 0, 0 }
363};
364
365void
366uni_uni_input(struct uni *uni, enum uni_sig sig, uint32_t cookie,
367    struct uni_msg *m)
368{
369	u_int i;
370
371	for (i = 0; maptab[i].name != NULL; i++) {
372		if (maptab[i].sig == sig) {
373			if (uni->proto == UNIPROTO_UNI40U) {
374				if (!(maptab[i].proto & UNIU))
375					uniapi_uni_error(uni,
376					    UNIAPI_ERROR_BAD_SIGNAL, cookie, 0);
377			} else if(uni->proto == UNIPROTO_UNI40N) {
378				if (!(maptab[i].proto & UNIN))
379					uniapi_uni_error(uni,
380					    UNIAPI_ERROR_BAD_SIGNAL, cookie, 0);
381			} else if(uni->proto == UNIPROTO_PNNI10) {
382				if (!(maptab[i].proto & PNNI))
383					uniapi_uni_error(uni,
384					    UNIAPI_ERROR_BAD_SIGNAL, cookie, 0);
385			} else {
386				uniapi_uni_error(uni,
387				    UNIAPI_ERROR_BAD_SIGNAL, cookie, 0);
388			}
389			if (uni_msg_len(m) != maptab[i].arglen) {
390				VERBOSE(uni, UNI_FAC_ERR, 1, "bogus data in %s"
391				    " (expecting %zu, got %zu)", maptab[i].name,
392				    maptab[i].arglen, uni_msg_len(m));
393				uni_msg_destroy(m);
394				uniapi_uni_error(uni, UNIAPI_ERROR_BAD_ARG,
395				    cookie, 0);
396				return;
397			}
398			if (maptab[i].arglen == 0) {
399				uni_msg_destroy(m);
400				m = NULL;
401			}
402			VERBOSE(uni, UNI_FAC_API, 1, "got signal %s - "
403			    "delivering to Coord", maptab[i].name);
404			uni_enq_coord(uni, maptab[i].coord_sig, cookie, m);
405			return;
406		}
407	}
408	VERBOSE(uni, UNI_FAC_ERR, 1, "bogus uni signal %u", sig);
409	uni_msg_destroy(m);
410	uniapi_uni_error(uni, UNIAPI_ERROR_BAD_SIGNAL, cookie, 0);
411}
412#undef UNIU
413#undef UNIN
414#undef PNNI
415
416/**************************************************************/
417
418void
419uni_work(struct uni *uni)
420{
421	struct sig *s;
422
423	if (uni->working)
424		return;
425	uni->working = 1;
426
427	while ((s = TAILQ_FIRST(&uni->workq)) != NULL) {
428		TAILQ_REMOVE(&uni->workq, s, link);
429		switch (s->type) {
430
431		  case SIG_COORD:
432			uni_sig_coord(uni, s->sig, s->cookie, s->msg);
433			break;
434
435		  case SIG_RESET_START:
436			uni_sig_start(uni, s->sig, s->cookie, s->msg, s->u);
437			break;
438
439		  case SIG_RESET_RESP:
440			uni_sig_respond(uni, s->sig, s->cookie, s->msg, s->u);
441			break;
442
443		  case SIG_CALL:
444			uni_sig_call(s->call, s->sig, s->cookie, s->msg, s->u);
445			break;
446
447		  case SIG_PARTY:
448			uni_sig_party(s->party, s->sig, s->cookie, s->msg, s->u);
449			break;
450
451		  default:
452			ASSERT(0, ("bad signal type"));
453		}
454		SIG_FREE(s);
455	}
456
457	uni->working = 0;
458}
459
460/*
461 * Enqueue a signal in the working queue
462 */
463void
464uni_enq_sig(struct uni *uni, u_int type, struct call *call,
465    struct party *party, uint32_t sig, uint32_t cookie,
466    struct uni_msg *msg, struct uni_all *u)
467{
468	struct sig *s;
469
470	if ((s = SIG_ALLOC()) != NULL) {
471		s->type = type;
472		s->sig = sig;
473		s->cookie = cookie;
474		s->msg = msg;
475		s->call = call;
476		s->party = party;
477		s->u = u;
478		TAILQ_INSERT_TAIL(&uni->workq, s, link);
479	}
480}
481
482/*
483 * Enqueue a signal in the delayed queue
484 */
485void
486uni_delenq_sig(struct uni *uni, u_int type, struct call *call,
487    struct party *party, uint32_t sig, uint32_t cookie,
488    struct uni_msg *msg, struct uni_all *u)
489{
490	struct sig *s;
491
492	if ((s = SIG_ALLOC()) != NULL) {
493		s->type = type;
494		s->sig = sig;
495		s->cookie = cookie;
496		s->msg = msg;
497		s->call = call;
498		s->party = party;
499		s->u = u;
500		TAILQ_INSERT_TAIL(&uni->delq, s, link);
501	}
502}
503
504/**************************************************************/
505
506void
507uniapi_uni_error(struct uni *uni, uint32_t reason, uint32_t cookie,
508    uint32_t state)
509{
510	struct uni_msg *resp;
511	struct uniapi_error *err;
512
513	if (cookie == 0)
514		return;
515
516	resp = uni_msg_alloc(sizeof(struct uniapi_error));
517	err = uni_msg_wptr(resp, struct uniapi_error *);
518	resp->b_wptr += sizeof(struct uniapi_error);
519
520	err->reason = reason;
521	err->state = state;
522
523	uni->funcs->uni_output(uni, uni->arg, UNIAPI_ERROR, cookie, resp);
524}
525
526void
527uniapi_call_error(struct call *c, uint32_t reason, uint32_t cookie)
528{
529	uniapi_uni_error(c->uni, reason, cookie, callstates[c->cstate].ext);
530}
531void
532uniapi_party_error(struct party *p, uint32_t reason, uint32_t cookie)
533{
534	uniapi_uni_error(p->call->uni, reason, cookie,
535	    callstates[p->call->cstate].ext);
536}
537
538/**************************************************************/
539void
540uni_status(struct uni *uni, void *arg)
541{
542	uni->funcs->status(uni, uni->arg, arg,
543	    "working: %s\n", uni->working ? "yes" : "no");
544	uni->funcs->status(uni, uni->arg, arg,
545	    "work queue: %sempty\n", TAILQ_EMPTY(&uni->workq)? "" : "not ");
546	uni->funcs->status(uni, uni->arg, arg,
547	    "delayed work queue: %sempty\n",
548	    TAILQ_EMPTY(&uni->delq)? "" : "not ");
549	uni->funcs->status(uni, uni->arg, arg,
550	    "coordinator: %s\n", custat_names[uni->custat]);
551	uni->funcs->status(uni, uni->arg, arg,
552	    "reset-start: %s\n", globstat_names[uni->glob_start]);
553	uni->funcs->status(uni, uni->arg, arg,
554	    "reset-respond: %s\n", globstat_names[uni->glob_respond]);
555}
556
557void
558uni_undel(struct uni *uni, int (*filter)(struct sig *, void *), void *arg)
559{
560	struct sigqueue		newq;
561	struct sig *s, *s1;
562
563	if (TAILQ_EMPTY(&uni->delq))
564		return;
565
566	TAILQ_INIT(&newq);
567
568	s = TAILQ_FIRST(&uni->delq);
569	while (s != NULL) {
570		s1 = TAILQ_NEXT(s, link);
571		if ((*filter)(s, arg)) {
572			TAILQ_REMOVE(&uni->delq, s, link);
573			TAILQ_INSERT_TAIL(&uni->workq, s, link);
574		}
575		s = s1;
576	}
577}
578
579void
580uni_delsig(struct uni *uni, u_int type, struct call *c, struct party *p)
581{
582	struct sig *s, *s1;
583
584	s = TAILQ_FIRST(&uni->workq);
585	while (s != NULL) {
586		s1 = TAILQ_NEXT(s, link);
587		if ((type == SIG_CALL && s->type == SIG_CALL &&
588		    s->call == c) ||
589		    (type == SIG_PARTY && s->type == SIG_PARTY &&
590		    s->call == c && s->party == p)) {
591			TAILQ_REMOVE(&uni->workq, s, link);
592			if (s->msg)
593				uni_msg_destroy(s->msg);
594			if (s->u)
595				UNI_FREE(s->u);
596			SIG_FREE(s);
597		}
598		s = s1;
599	}
600
601	s = TAILQ_FIRST(&uni->delq);
602	while (s != NULL) {
603		s1 = TAILQ_NEXT(s, link);
604		if ((type == SIG_CALL && s->type == SIG_CALL &&
605		    s->call == c) ||
606		    (type == SIG_PARTY && s->type == SIG_PARTY &&
607		    s->call == c && s->party == p)) {
608			TAILQ_REMOVE(&uni->delq, s, link);
609			if (s->msg)
610				uni_msg_destroy(s->msg);
611			if (s->u)
612				UNI_FREE(s->u);
613			SIG_FREE(s);						\
614		}
615		s = s1;
616	}
617}
618
619/**************************************************************/
620
621void
622uni_get_config(const struct uni *uni, struct uni_config *config)
623{
624	config->proto = uni->proto;
625
626	config->popt = 0;
627	if (uni->cx.q2932)
628		config->popt |= UNIPROTO_GFP;
629
630	config->option = 0;
631	if (uni->cx.git_hard)
632		config->option |= UNIOPT_GIT_HARD;
633	if (uni->cx.bearer_hard)
634		config->option |= UNIOPT_BEARER_HARD;
635	if (uni->cx.cause_hard)
636		config->option |= UNIOPT_CAUSE_HARD;
637	if (uni->sb_tb)
638		config->popt |= UNIPROTO_SB_TB;
639
640	config->timer301 = uni->timer301;
641	config->timer303 = uni->timer303;
642	config->init303 = uni->init303;
643	config->timer308 = uni->timer308;
644	config->init308 = uni->init308;
645	config->timer309 = uni->timer309;
646	config->timer310 = uni->timer310;
647	config->timer313 = uni->timer313;
648	config->timer316 = uni->timer316;
649	config->init316 = uni->init316;
650	config->timer317 = uni->timer317;
651	config->timer322 = uni->timer322;
652	config->init322 = uni->init322;
653	config->timer397 = uni->timer397;
654	config->timer398 = uni->timer398;
655	config->timer399 = uni->timer399;
656}
657
658void
659uni_set_config(struct uni *uni, const struct uni_config *config,
660    uint32_t *mask, uint32_t *popt_mask, uint32_t *opt_mask)
661{
662	int idle;
663
664	idle = TAILQ_EMPTY(&uni->calls) &&
665	    TAILQ_EMPTY(&uni->workq) &&
666	    TAILQ_EMPTY(&uni->delq);
667
668	if ((*mask & UNICFG_PROTO) && idle) {
669		switch (config->proto) {
670
671		  case UNIPROTO_UNI40U:
672		  case UNIPROTO_UNI40N:
673		  /* case UNIPROTO_PNNI10: XXX */
674			uni->proto = config->proto;
675			*mask &= ~UNICFG_PROTO;
676			break;
677		}
678	}
679	if (*popt_mask & UNIPROTO_GFP) {
680		if (config->popt & UNIPROTO_GFP) {
681			uni->cx.q2932 = 1;
682			*popt_mask &= ~UNIPROTO_GFP;
683		} else {
684			if (!uni->cx.q2932 || idle) {
685				uni->cx.q2932 = 0;
686				*popt_mask &= ~UNIPROTO_GFP;
687			}
688		}
689	}
690	if (*popt_mask & UNIPROTO_SB_TB) {
691		uni->sb_tb = ((config->popt & UNIPROTO_SB_TB) != 0);
692		*popt_mask &= ~UNIPROTO_SB_TB;
693	}
694	if (*opt_mask & UNIOPT_GIT_HARD) {
695		uni->cx.git_hard = ((config->option & UNIOPT_GIT_HARD) != 0);
696		*opt_mask &= ~UNIOPT_GIT_HARD;
697	}
698	if (*opt_mask & UNIOPT_BEARER_HARD) {
699		uni->cx.bearer_hard = ((config->option & UNIOPT_BEARER_HARD) != 0);
700		*opt_mask &= ~UNIOPT_BEARER_HARD;
701	}
702	if (*opt_mask & UNIOPT_CAUSE_HARD) {
703		uni->cx.cause_hard = ((config->option & UNIOPT_CAUSE_HARD) != 0);
704		*opt_mask &= ~UNIOPT_CAUSE_HARD;
705	}
706
707#define SET_TIMER(NAME,name)						\
708	if (*mask & UNICFG_##NAME) {					\
709		uni->name = config->name;				\
710		*mask &= ~UNICFG_##NAME;				\
711	}
712
713	SET_TIMER(TIMER301, timer301);
714	SET_TIMER(TIMER303, timer303);
715	SET_TIMER(INIT303,  init303);
716	SET_TIMER(TIMER308, timer308);
717	SET_TIMER(INIT308,  init308);
718	SET_TIMER(TIMER309, timer309);
719	SET_TIMER(TIMER310, timer310);
720	SET_TIMER(TIMER313, timer313);
721	SET_TIMER(TIMER316, timer316);
722	SET_TIMER(INIT316,  init316);
723	SET_TIMER(TIMER317, timer317);
724	SET_TIMER(TIMER322, timer322);
725	SET_TIMER(INIT322,  init322);
726	SET_TIMER(TIMER397, timer397);
727	SET_TIMER(TIMER398, timer398);
728	SET_TIMER(TIMER399, timer399);
729
730#undef SET_TIMER
731}
732
733void
734uni_set_debug(struct uni *uni, enum uni_verb fac, u_int level)
735{
736	uni->debug[fac] = level;
737}
738
739u_int
740uni_get_debug(const struct uni *uni, enum uni_verb fac)
741{
742	return (uni->debug[fac]);
743}
744
745u_int
746uni_getcustate(const struct uni *uni)
747{
748	return (uni->custat);
749}
750