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/saal/saal_sscfu.c,v 1.4 2004/07/08 08:22:10 brandt Exp $
30  *
31  * SSCF on the UNI
32  */
33 
34 #include <netnatm/saal/sscfu.h>
35 #include <netnatm/saal/sscfupriv.h>
36 
37 #define MKSTR(S)	#S
38 
39 static const char *const sscf_sigs[] = {
40 	MKSTR(SAAL_ESTABLISH_request),
41 	MKSTR(SAAL_ESTABLISH_indication),
42 	MKSTR(SAAL_ESTABLISH_confirm),
43 	MKSTR(SAAL_RELEASE_request),
44 	MKSTR(SAAL_RELEASE_confirm),
45 	MKSTR(SAAL_RELEASE_indication),
46 	MKSTR(SAAL_DATA_request),
47 	MKSTR(SAAL_DATA_indication),
48 	MKSTR(SAAL_UDATA_request),
49 	MKSTR(SAAL_UDATA_indication),
50 };
51 
52 static const char *const sscf_states[] = {
53 	MKSTR(SSCF_RELEASED),
54 	MKSTR(SSCF_AWAITING_ESTABLISH),
55 	MKSTR(SSCF_AWAITING_RELEASE),
56 	MKSTR(SSCF_ESTABLISHED),
57 	MKSTR(SSCF_RESYNC),
58 };
59 
60 #define AA_SIG(S,G,M) \
61 	((S)->funcs->send_upper((S), (S)->aarg, (G), (M)))
62 
63 #define SSCOP_AASIG(S,G,M,P) \
64 	((S)->funcs->send_lower((S), (S)->aarg, (G), (M), (P)))
65 
66 MEMINIT();
67 
68 static void sscfu_unqueue(struct sscfu *sscf);
69 
70 /************************************************************/
71 /*
72  * INSTANCE AND CLASS MANAGEMENT
73  */
74 
75 /*
76  * Initialize SSCF.
77  */
78 struct sscfu *
sscfu_create(void * a,const struct sscfu_funcs * funcs)79 sscfu_create(void *a, const struct sscfu_funcs *funcs)
80 {
81 	struct sscfu *sscf;
82 
83 	MEMZALLOC(sscf, struct sscfu *, sizeof(struct sscfu));
84 	if (sscf == NULL)
85 		return (NULL);
86 
87 	sscf->funcs = funcs;
88 	sscf->aarg = a;
89 	sscf->state = SSCFU_RELEASED;
90 	sscf->inhand = 0;
91 	SIGQ_INIT(&sscf->sigs);
92 	sscf->debug = 0;
93 
94 	return (sscf);
95 }
96 
97 /*
98  * Reset the instance. Call only if you know, what you're doing.
99  */
100 void
sscfu_reset(struct sscfu * sscf)101 sscfu_reset(struct sscfu *sscf)
102 {
103 	sscf->state = SSCFU_RELEASED;
104 	sscf->inhand = 0;
105 	SIGQ_CLEAR(&sscf->sigs);
106 }
107 
108 /*
109  * Destroy SSCF
110  */
111 void
sscfu_destroy(struct sscfu * sscf)112 sscfu_destroy(struct sscfu *sscf)
113 {
114 	SIGQ_CLEAR(&sscf->sigs);
115 	MEMFREE(sscf);
116 }
117 
118 enum sscfu_state
sscfu_getstate(const struct sscfu * sscf)119 sscfu_getstate(const struct sscfu *sscf)
120 {
121 	return (sscf->state);
122 }
123 
124 u_int
sscfu_getdefparam(struct sscop_param * p)125 sscfu_getdefparam(struct sscop_param *p)
126 {
127 	memset(p, 0, sizeof(*p));
128 
129 	p->timer_cc = 1000;
130 	p->timer_poll = 750;
131 	p->timer_keep_alive = 2000;
132 	p->timer_no_response = 7000;
133 	p->timer_idle = 15000;
134 	p->maxk = 4096;
135 	p->maxj = 4096;
136 	p->maxcc = 4;
137 	p->maxpd = 25;
138 
139 	return (SSCOP_SET_TCC | SSCOP_SET_TPOLL | SSCOP_SET_TKA |
140 	    SSCOP_SET_TNR | SSCOP_SET_TIDLE | SSCOP_SET_MAXK |
141 	    SSCOP_SET_MAXJ | SSCOP_SET_MAXCC | SSCOP_SET_MAXPD);
142 }
143 
144 const char *
sscfu_signame(enum saal_sig sig)145 sscfu_signame(enum saal_sig sig)
146 {
147 	static char str[40];
148 
149 	if (sig >= sizeof(sscf_sigs)/sizeof(sscf_sigs[0])) {
150 		sprintf(str, "BAD SAAL_SIGNAL %u", sig);
151 		return (str);
152 	} else {
153 		return (sscf_sigs[sig]);
154 	}
155 }
156 
157 const char *
sscfu_statename(enum sscfu_state s)158 sscfu_statename(enum sscfu_state s)
159 {
160 	static char str[40];
161 
162 	if (s >= sizeof(sscf_states)/sizeof(sscf_states[0])) {
163 		sprintf(str, "BAD SSCFU state %u", s);
164 		return (str);
165 	} else {
166 		return (sscf_states[s]);
167 	}
168 }
169 
170 /************************************************************/
171 /*
172  * EXTERNAL INPUT SIGNAL MAPPING
173  */
174 static __inline void
set_state(struct sscfu * sscf,enum sscfu_state state)175 set_state(struct sscfu *sscf, enum sscfu_state state)
176 {
177 	VERBOSE(sscf, SSCFU_DBG_STATE, (sscf, sscf->aarg,
178 	    "change state from %s to %s",
179 	    sscf_states[sscf->state], sscf_states[state]));
180 	sscf->state = state;
181 }
182 
183 /*
184  * signal from SSCOP to SSCF
185  * Message must be freed by the user specified handler, if
186  * it is passed.
187  */
188 void
sscfu_input(struct sscfu * sscf,enum sscop_aasig sig,struct SSCFU_MBUF_T * m,u_int arg __unused)189 sscfu_input(struct sscfu *sscf, enum sscop_aasig sig,
190     struct SSCFU_MBUF_T *m, u_int arg __unused)
191 {
192 	sscf->inhand = 1;
193 
194 	VERBOSE(sscf, SSCFU_DBG_LSIG, (sscf, sscf->aarg,
195 	    "SSCF got signal %d. in state %s", sig, sscf_states[sscf->state]));
196 
197 	switch (sig) {
198 
199 	  case SSCOP_RELEASE_indication:
200 		/* arg is: UU, SRC */
201 		switch (sscf->state) {
202 
203 		  case SSCFU_RELEASED:
204 			if (m)
205 				MBUF_FREE(m);
206 			goto badsig;
207 
208 		  case SSCFU_AWAITING_ESTABLISH:
209 			set_state(sscf, SSCFU_RELEASED);
210 			AA_SIG(sscf, SAAL_RELEASE_indication, m);
211 			break;
212 
213 		  case SSCFU_AWAITING_RELEASE:
214 			if (m)
215 				MBUF_FREE(m);
216 			goto badsig;
217 
218 		  case SSCFU_ESTABLISHED:
219 			set_state(sscf, SSCFU_RELEASED);
220 			AA_SIG(sscf, SAAL_RELEASE_indication, m);
221 			break;
222 
223 		  case SSCFU_RESYNC:
224 			set_state(sscf, SSCFU_RELEASED);
225 			AA_SIG(sscf, SAAL_RELEASE_indication, m);
226 			break;
227 		}
228 		break;
229 
230 	  case SSCOP_ESTABLISH_indication:
231 		/* arg is: UU */
232 		switch (sscf->state) {
233 
234 		  case SSCFU_RELEASED:
235 			set_state(sscf, SSCFU_ESTABLISHED);
236 			SSCOP_AASIG(sscf, SSCOP_ESTABLISH_response, NULL, 1);
237 			AA_SIG(sscf, SAAL_ESTABLISH_indication, m);
238 			break;
239 
240 		  case SSCFU_AWAITING_ESTABLISH:
241 		  case SSCFU_AWAITING_RELEASE:
242 		  case SSCFU_ESTABLISHED:
243 		  case SSCFU_RESYNC:
244 			if (m)
245 				MBUF_FREE(m);
246 			goto badsig;
247 		}
248 		break;
249 
250 	  case SSCOP_ESTABLISH_confirm:
251 		/* arg is: UU */
252 		switch (sscf->state) {
253 
254 		  case SSCFU_RELEASED:
255 			if (m)
256 				MBUF_FREE(m);
257 			goto badsig;
258 
259 		  case SSCFU_AWAITING_ESTABLISH:
260 			set_state(sscf, SSCFU_ESTABLISHED);
261 			AA_SIG(sscf, SAAL_ESTABLISH_confirm, m);
262 			break;
263 
264 		  case SSCFU_AWAITING_RELEASE:
265 		  case SSCFU_ESTABLISHED:
266 		  case SSCFU_RESYNC:
267 			if (m)
268 				MBUF_FREE(m);
269 			goto badsig;
270 		}
271 		break;
272 
273 	  case SSCOP_RELEASE_confirm:
274 		/* arg is: */
275 		switch (sscf->state) {
276 
277 		  case SSCFU_RELEASED:
278 		  case SSCFU_AWAITING_ESTABLISH:
279 			goto badsig;
280 
281 		  case SSCFU_AWAITING_RELEASE:
282 			set_state(sscf, SSCFU_RELEASED);
283 			AA_SIG(sscf, SAAL_RELEASE_confirm, NULL);
284 			break;
285 
286 		  case SSCFU_ESTABLISHED:
287 		  case SSCFU_RESYNC:
288 			goto badsig;
289 		}
290 		break;
291 
292 	  case SSCOP_DATA_indication:
293 		/* arg is: MU */
294 		sscf->funcs->window(sscf, sscf->aarg, 1);
295 		switch (sscf->state) {
296 
297 		  case SSCFU_RELEASED:
298 		  case SSCFU_AWAITING_ESTABLISH:
299 		  case SSCFU_AWAITING_RELEASE:
300 			MBUF_FREE(m);
301 			goto badsig;
302 
303 		  case SSCFU_ESTABLISHED:
304 			AA_SIG(sscf, SAAL_DATA_indication, m);
305 			break;
306 
307 		  case SSCFU_RESYNC:
308 			MBUF_FREE(m);
309 			goto badsig;
310 		}
311 		break;
312 
313 	  case SSCOP_RECOVER_indication:
314 		/* arg is: */
315 		switch (sscf->state) {
316 
317 		  case SSCFU_RELEASED:
318 		  case SSCFU_AWAITING_ESTABLISH:
319 		  case SSCFU_AWAITING_RELEASE:
320 			goto badsig;
321 
322 		  case SSCFU_ESTABLISHED:
323 			SSCOP_AASIG(sscf, SSCOP_RECOVER_response, NULL, 0);
324 			AA_SIG(sscf, SAAL_ESTABLISH_indication, NULL);
325 			break;
326 
327 		  case SSCFU_RESYNC:
328 			goto badsig;
329 		}
330 		break;
331 
332 	  case SSCOP_RESYNC_indication:
333 		/* arg is: UU */
334 		switch (sscf->state) {
335 
336 		  case SSCFU_RELEASED:
337 		  case SSCFU_AWAITING_ESTABLISH:
338 		  case SSCFU_AWAITING_RELEASE:
339 			if (m)
340 				MBUF_FREE(m);
341 			goto badsig;
342 
343 		  case SSCFU_ESTABLISHED:
344 			SSCOP_AASIG(sscf, SSCOP_RESYNC_response, NULL, 0);
345 			AA_SIG(sscf, SAAL_ESTABLISH_indication, m);
346 			break;
347 
348 		  case SSCFU_RESYNC:
349 			if (m)
350 				MBUF_FREE(m);
351 			goto badsig;
352 		}
353 		break;
354 
355 	  case SSCOP_RESYNC_confirm:
356 		/* arg is: */
357 		switch (sscf->state) {
358 
359 		  case SSCFU_RELEASED:
360 		  case SSCFU_AWAITING_ESTABLISH:
361 		  case SSCFU_AWAITING_RELEASE:
362 		  case SSCFU_ESTABLISHED:
363 
364 		  case SSCFU_RESYNC:
365 			set_state(sscf, SSCFU_ESTABLISHED);
366 			AA_SIG(sscf, SAAL_ESTABLISH_confirm, NULL);
367 			break;
368 		}
369 		break;
370 
371 	  case SSCOP_UDATA_indication:
372 		/* arg is: MD */
373 		AA_SIG(sscf, SAAL_UDATA_indication, m);
374 		break;
375 
376 
377 	  case SSCOP_RETRIEVE_indication:
378 		if (m)
379 			MBUF_FREE(m);
380 		goto badsig;
381 
382 	  case SSCOP_RETRIEVE_COMPL_indication:
383 		goto badsig;
384 
385 	  case SSCOP_ESTABLISH_request:
386 	  case SSCOP_RELEASE_request:
387 	  case SSCOP_ESTABLISH_response:
388 	  case SSCOP_DATA_request:
389 	  case SSCOP_RECOVER_response:
390 	  case SSCOP_RESYNC_request:
391 	  case SSCOP_RESYNC_response:
392 	  case SSCOP_UDATA_request:
393 	  case SSCOP_RETRIEVE_request:
394 		ASSERT(0);
395 		break;
396 	}
397 
398 	sscfu_unqueue(sscf);
399 	return;
400 
401   badsig:
402 	VERBOSE(sscf, SSCFU_DBG_ERR, (sscf, sscf->aarg,
403 	    "bad signal %d. in state %s", sig, sscf_states[sscf->state]));
404 	sscfu_unqueue(sscf);
405 }
406 
407 
408 /*
409  * Handle signals from the user
410  */
411 static void
sscfu_dosig(struct sscfu * sscf,enum saal_sig sig,struct SSCFU_MBUF_T * m)412 sscfu_dosig(struct sscfu *sscf, enum saal_sig sig, struct SSCFU_MBUF_T *m)
413 {
414 	VERBOSE(sscf, SSCFU_DBG_EXEC, (sscf, sscf->aarg,
415 	    "executing signal %s(%s)",
416 	    sscf_sigs[sig], sscf_states[sscf->state]));
417 
418 	switch (sig) {
419 
420 	  case SAAL_ESTABLISH_request:
421 		/* arg is opt UU */
422 		switch (sscf->state) {
423 
424 		  case SSCFU_RELEASED:
425 			set_state(sscf, SSCFU_AWAITING_ESTABLISH);
426 			SSCOP_AASIG(sscf, SSCOP_ESTABLISH_request, m, 1);
427 			break;
428 
429 		  case SSCFU_AWAITING_ESTABLISH:
430 			if (m)
431 				MBUF_FREE(m);
432 			goto badsig;
433 
434 		  case SSCFU_AWAITING_RELEASE:
435 			set_state(sscf, SSCFU_AWAITING_ESTABLISH);
436 			SSCOP_AASIG(sscf, SSCOP_ESTABLISH_request, m, 1);
437 			break;
438 
439 		  case SSCFU_ESTABLISHED:
440 			set_state(sscf, SSCFU_RESYNC);
441 			SSCOP_AASIG(sscf, SSCOP_RESYNC_request, m, 0);
442 			break;
443 
444 		  case SSCFU_RESYNC:
445 			if (m)
446 				MBUF_FREE(m);
447 			goto badsig;
448 		}
449 		break;
450 
451 	  case SAAL_RELEASE_request:
452 		/* arg is opt UU */
453 		switch(sscf->state) {
454 
455 		  case SSCFU_RELEASED:
456 			if (m)
457 				MBUF_FREE(m);
458 			AA_SIG(sscf, SAAL_RELEASE_confirm, NULL);
459 			break;
460 
461 		  case SSCFU_AWAITING_ESTABLISH:
462 			set_state(sscf, SSCFU_AWAITING_RELEASE);
463 			SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0);
464 			break;
465 
466 		  case SSCFU_AWAITING_RELEASE:
467 			if (m)
468 				MBUF_FREE(m);
469 			goto badsig;
470 
471 		  case SSCFU_ESTABLISHED:
472 			set_state(sscf, SSCFU_AWAITING_RELEASE);
473 			SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0);
474 			break;
475 
476 		  case SSCFU_RESYNC:
477 			set_state(sscf, SSCFU_AWAITING_RELEASE);
478 			SSCOP_AASIG(sscf, SSCOP_RELEASE_request, m, 0);
479 			break;
480 		}
481 		break;
482 
483 	  case SAAL_DATA_request:
484 		/* arg is DATA */
485 		switch (sscf->state) {
486 
487 		  case SSCFU_RELEASED:
488 		  case SSCFU_AWAITING_ESTABLISH:
489 		  case SSCFU_AWAITING_RELEASE:
490 			MBUF_FREE(m);
491 			goto badsig;
492 
493 		  case SSCFU_ESTABLISHED:
494 			SSCOP_AASIG(sscf, SSCOP_DATA_request, m, 0);
495 			break;
496 
497 		  case SSCFU_RESYNC:
498 			MBUF_FREE(m);
499 			goto badsig;
500 		}
501 		break;
502 
503 	  case SAAL_UDATA_request:
504 		/* arg is UDATA */
505 		SSCOP_AASIG(sscf, SSCOP_UDATA_request, m, 0);
506 		break;
507 
508 	  case SAAL_ESTABLISH_indication:
509 	  case SAAL_ESTABLISH_confirm:
510 	  case SAAL_RELEASE_confirm:
511 	  case SAAL_RELEASE_indication:
512 	  case SAAL_DATA_indication:
513 	  case SAAL_UDATA_indication:
514 		ASSERT(0);
515 		break;
516 	}
517 	return;
518 
519   badsig:
520 	VERBOSE(sscf, SSCFU_DBG_ERR, (sscf, sscf->aarg,
521 	    "bad signal %s in state %s", sscf_sigs[sig],
522 	    sscf_states[sscf->state]));
523 }
524 
525 /*
526  * Handle user signal.
527  */
528 int
sscfu_saalsig(struct sscfu * sscf,enum saal_sig sig,struct SSCFU_MBUF_T * m)529 sscfu_saalsig(struct sscfu *sscf, enum saal_sig sig, struct SSCFU_MBUF_T *m)
530 {
531 	struct sscfu_sig *s;
532 
533 	if (sscf->inhand) {
534 		VERBOSE(sscf, SSCFU_DBG_EXEC, (sscf, sscf->aarg,
535 		    "queuing user signal %s(%s)",
536 		    sscf_sigs[sig], sscf_states[sscf->state]));
537 		SIG_ALLOC(s);
538 		if (s == NULL)
539 			return (ENOMEM);
540 		s->sig = sig;
541 		s->m = m;
542 		SIGQ_APPEND(&sscf->sigs, s);
543 		return (0);
544 	}
545 
546 	sscf->inhand = 1;
547 	sscfu_dosig(sscf, sig, m);
548 	sscfu_unqueue(sscf);
549 	return (0);
550 }
551 
552 /*
553  * Unqueue all qeueued signals. Must be called with inhand==1.
554  */
555 static void
sscfu_unqueue(struct sscfu * sscf)556 sscfu_unqueue(struct sscfu *sscf)
557 {
558 	struct sscfu_sig *s;
559 
560 	while ((s = SIGQ_GET(&sscf->sigs)) != NULL) {
561 		sscfu_dosig(sscf, s->sig, s->m);
562 		SIG_FREE(s);
563 	}
564 	sscf->inhand = 0;
565 }
566 
567 void
sscfu_setdebug(struct sscfu * sscf,u_int n)568 sscfu_setdebug(struct sscfu *sscf, u_int n)
569 {
570 	sscf->debug = n;
571 }
572 
573 u_int
sscfu_getdebug(const struct sscfu * sscf)574 sscfu_getdebug(const struct sscfu *sscf)
575 {
576 	return (sscf->debug);
577 }
578