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_sscop.c,v 1.11 2004/07/08 08:22:13 brandt Exp $
30 *
31 * Core SSCOP code (ITU-T Q.2110)
32 */
33
34#include <netnatm/saal/sscop.h>
35#include <netnatm/saal/sscoppriv.h>
36
37#ifndef FAILURE
38#define FAILURE(S)
39#endif
40
41#define MKSTR(S)	#S
42
43static const char *const sscop_sigs[] = {
44	MKSTR(SSCOP_ESTABLISH_request),
45	MKSTR(SSCOP_ESTABLISH_indication),
46	MKSTR(SSCOP_ESTABLISH_response),
47	MKSTR(SSCOP_ESTABLISH_confirm),
48	MKSTR(SSCOP_RELEASE_request),
49	MKSTR(SSCOP_RELEASE_indication),
50	MKSTR(SSCOP_RELEASE_confirm),
51	MKSTR(SSCOP_DATA_request),
52	MKSTR(SSCOP_DATA_indication),
53	MKSTR(SSCOP_UDATA_request),
54	MKSTR(SSCOP_UDATA_indication),
55	MKSTR(SSCOP_RECOVER_indication),
56	MKSTR(SSCOP_RECOVER_response),
57	MKSTR(SSCOP_RESYNC_request),
58	MKSTR(SSCOP_RESYNC_indication),
59	MKSTR(SSCOP_RESYNC_response),
60	MKSTR(SSCOP_RESYNC_confirm),
61	MKSTR(SSCOP_RETRIEVE_request),
62	MKSTR(SSCOP_RETRIEVE_indication),
63	MKSTR(SSCOP_RETRIEVE_COMPL_indication),
64};
65
66static const char *const sscop_msigs[] = {
67	MKSTR(SSCOP_MDATA_request),
68	MKSTR(SSCOP_MDATA_indication),
69	MKSTR(SSCOP_MERROR_indication),
70};
71
72static const char *const states[] = {
73	MKSTR(SSCOP_IDLE),
74	MKSTR(SSCOP_OUT_PEND),
75	MKSTR(SSCOP_IN_PEND),
76	MKSTR(SSCOP_OUT_DIS_PEND),
77	MKSTR(SSCOP_OUT_RESYNC_PEND),
78	MKSTR(SSCOP_IN_RESYNC_PEND),
79	MKSTR(SSCOP_OUT_REC_PEND),
80	MKSTR(SSCOP_REC_PEND),
81	MKSTR(SSCOP_IN_REC_PEND),
82	MKSTR(SSCOP_READY),
83};
84
85#ifdef SSCOP_DEBUG
86static const char *const events[] = {
87	MKSTR(SIG_BGN),
88	MKSTR(SIG_BGAK),
89	MKSTR(SIG_END),
90	MKSTR(SIG_ENDAK),
91	MKSTR(SIG_RS),
92	MKSTR(SIG_RSAK),
93	MKSTR(SIG_BGREJ),
94	MKSTR(SIG_SD),
95	MKSTR(SIG_ER),
96	MKSTR(SIG_POLL),
97	MKSTR(SIG_STAT),
98	MKSTR(SIG_USTAT),
99	MKSTR(SIG_UD),
100	MKSTR(SIG_MD),
101	MKSTR(SIG_ERAK),
102
103	MKSTR(SIG_T_CC),
104	MKSTR(SIG_T_POLL),
105	MKSTR(SIG_T_KA),
106	MKSTR(SIG_T_NR),
107	MKSTR(SIG_T_IDLE),
108
109	MKSTR(SIG_PDU_Q),
110	MKSTR(SIG_USER_DATA),
111	MKSTR(SIG_ESTAB_REQ),
112	MKSTR(SIG_ESTAB_RESP),
113	MKSTR(SIG_RELEASE_REQ),
114	MKSTR(SIG_RECOVER),
115	MKSTR(SIG_SYNC_REQ),
116	MKSTR(SIG_SYNC_RESP),
117	MKSTR(SIG_UDATA),
118	MKSTR(SIG_MDATA),
119	MKSTR(SIG_UPDU_Q),
120	MKSTR(SIG_MPDU_Q),
121	MKSTR(SIG_RETRIEVE),
122};
123
124static const char *const pdus[] = {
125	"illegale PDU type 0",		/* no PDU type 0 */
126	MKSTR(PDU_BGN),
127	MKSTR(PDU_BGAK),
128	MKSTR(PDU_END),
129	MKSTR(PDU_ENDAK),
130	MKSTR(PDU_RS),
131	MKSTR(PDU_RSAK),
132	MKSTR(PDU_BGREJ),
133	MKSTR(PDU_SD),
134	MKSTR(PDU_ER),
135	MKSTR(PDU_POLL),
136	MKSTR(PDU_STAT),
137	MKSTR(PDU_USTAT),
138	MKSTR(PDU_UD),
139	MKSTR(PDU_MD),
140	MKSTR(PDU_ERAK),
141};
142#endif
143
144MEMINIT();
145
146static void sscop_signal(struct sscop *, u_int, struct sscop_msg *);
147static void sscop_save_signal(struct sscop *, u_int, struct sscop_msg *);
148static void handle_sigs(struct sscop *);
149static void sscop_set_state(struct sscop *, u_int);
150
151/************************************************************/
152
153
154/************************************************************/
155/*
156 * Queue macros
157 */
158#define SSCOP_MSG_FREE(MSG)						\
159    do {								\
160	if(MSG) {							\
161		MBUF_FREE((MSG)->m);					\
162		MSG_FREE((MSG));					\
163	}								\
164    } while(0)
165
166
167#define QFIND(Q,RN)							\
168    ({									\
169	struct sscop_msg *_msg = NULL, *_m;				\
170	MSGQ_FOREACH(_m, (Q)) {						\
171		if(_m->seqno == (RN)) {					\
172			_msg = _m;					\
173			break;						\
174		}							\
175	}								\
176	_msg;								\
177    })
178
179#define QINSERT(Q,M)							\
180    do {								\
181	struct sscop_msg *_msg = NULL, *_m;				\
182	MSGQ_FOREACH(_m, (Q)) {						\
183		if (_m->seqno > (M)->seqno) {				\
184			_msg = _m;					\
185			break;						\
186		}							\
187	}								\
188	if (_msg != NULL)							\
189		MSGQ_INSERT_BEFORE(_msg, (M));				\
190	else								\
191		MSGQ_APPEND((Q), (M));					\
192    } while (0)
193
194
195/*
196 * Send an error indication to the management plane.
197 */
198#define MAAL_ERROR(S,E,C) 						\
199    do {								\
200	VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg,			\
201	    "MAA-Signal %s in state %s", 				\
202	    sscop_msigs[SSCOP_MERROR_indication], states[(S)->state]));	\
203	(S)->funcs->send_manage((S), (S)->aarg,				\
204	    SSCOP_MERROR_indication, NULL, (E), (C));			\
205    } while(0)
206
207#define MAAL_DATA(S,M) 							\
208    do {								\
209	VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg,			\
210	    "MAA-Signal %s in state %s",				\
211	    sscop_msigs[SSCOP_MDATA_indication], states[(S)->state]));	\
212	(S)->funcs->send_manage((S), (S)->aarg,				\
213	    SSCOP_MDATA_indication, (M), 0, 0);				\
214    } while(0)
215
216#define AAL_DATA(S,D,M,N)						\
217    do {								\
218	VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg,			\
219	    "AA-Signal %s in state %s",					\
220	    sscop_sigs[D], states[(S)->state]));			\
221	(S)->funcs->send_upper((S), (S)->aarg, (D), (M), (N));		\
222    } while(0)
223
224#define AAL_SIG(S,D)							\
225    do {								\
226	VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg,			\
227	    "AA-Signal %s in state %s",					\
228	    sscop_sigs[D], states[(S)->state]));			\
229	(S)->funcs->send_upper((S), (S)->aarg, (D), NULL, 0);		\
230    } while(0)
231
232#ifdef SSCOP_DEBUG
233#define AAL_SEND(S,M) do {						\
234	if (ISVERBOSE(S, SSCOP_DBG_PDU))				\
235		sscop_dump_pdu(S, "tx", (M));				\
236	(S)->funcs->send_lower((S), (S)->aarg, (M));			\
237    } while(0)
238#else
239#define AAL_SEND(S,M) (S)->funcs->send_lower((S), (S)->aarg, (M))
240#endif
241
242
243/*
244 * Free a save user-to-user data buffer and set the pointer to zero
245 * to signal, that it is free.
246 */
247#define FREE_UU(F)							\
248	do {								\
249		if(sscop->F) {						\
250			MBUF_FREE(sscop->F);				\
251			sscop->F = NULL;				\
252		}							\
253	} while(0)
254
255#define SET_UU(F,U)							\
256	do {								\
257		FREE_UU(F);						\
258		sscop->F = U->m;					\
259		U->m = NULL;						\
260		SSCOP_MSG_FREE(U);					\
261	} while(0)
262
263#define AAL_UU_SIGNAL(S, SIG, M, PL, SN)				\
264	do {								\
265		if(MBUF_LEN((M)->m) > 0) { 				\
266			MBUF_UNPAD((M)->m,(PL));			\
267			AAL_DATA((S), (SIG), (M)->m, (SN)); 		\
268			(M)->m = NULL;					\
269		} else {						\
270			AAL_DATA((S), (SIG), NULL, (SN));		\
271		}							\
272		SSCOP_MSG_FREE((M));					\
273	} while(0)
274
275
276
277TIMER_FUNC(cc, CC)
278TIMER_FUNC(nr, NR)
279TIMER_FUNC(ka, KA)
280TIMER_FUNC(poll, POLL)
281TIMER_FUNC(idle, IDLE)
282
283/************************************************************/
284/*
285 * INSTANCE AND TYPE HANDLING.
286 */
287#ifdef SSCOP_DEBUG
288static void
289sscop_dump_pdu(struct sscop *sscop, const char *dir,
290    const struct SSCOP_MBUF_T *m)
291{
292	u_int32_t v1, v2, v3, v4;
293	u_int size = MBUF_LEN(m);
294	u_int n, i;
295
296	if (size < 8)
297		return;
298
299	v1 = MBUF_TRAIL32(m, -1);
300	v2 = MBUF_TRAIL32(m, -2);
301
302	switch ((v1 >> 24) & 0xf) {
303
304	  case 0:
305		return;
306
307	  case PDU_BGN:
308		sscop->funcs->verbose(sscop, sscop->aarg,
309		    "%s BGN n(mr)=%u n(sq)=%u pl=%u",
310		    dir, v1 & 0xffffff, v2 & 0xff, (v1 >> 30) & 0x3);
311		return;
312
313	  case PDU_BGAK:
314		sscop->funcs->verbose(sscop, sscop->aarg,
315		    "%s BGAK n(mr)=%u pl=%u",
316		    dir, v1 & 0xffffff, (v1 >> 30) & 0x3);
317		return;
318
319	  case PDU_END:
320		sscop->funcs->verbose(sscop, sscop->aarg,
321		    "%s END r=%u s=%u pl=%u",
322		    dir, (v1 >> 29) & 1, (v1 >> 28) & 1, (v1 >> 30) & 0x3);
323		return;
324
325	  case PDU_ENDAK:
326		sscop->funcs->verbose(sscop, sscop->aarg, "%s ENDAK", dir);
327		return;
328
329	  case PDU_RS:
330		sscop->funcs->verbose(sscop, sscop->aarg,
331		    "%s RS n(mr)=%u n(sq)=%u pl=%u",
332		    dir, v1 & 0xffffff, v2 & 0xff, (v1 >> 30) & 0x3);
333		return;
334
335	  case PDU_RSAK:
336		sscop->funcs->verbose(sscop, sscop->aarg, "%s RSAK n(mr)=%u",
337		    dir, v1 & 0xffffff);
338		return;
339
340	  case PDU_BGREJ:
341		sscop->funcs->verbose(sscop, sscop->aarg, "%s BGREJ pl=%u",
342		    dir, (v1 >> 30) & 0x3);
343		return;
344
345	  case PDU_SD:
346		sscop->funcs->verbose(sscop, sscop->aarg, "%s SD n(s)=%u pl=%u",
347		    dir, v1 & 0xffffff, (v1 >> 30) & 0x3);
348		return;
349
350	  case PDU_ER:
351		sscop->funcs->verbose(sscop, sscop->aarg, "%s ER n(mr)=%u n(sq)=%u",
352		    dir, v1 & 0xffffff, v2 & 0xff);
353		return;
354
355	  case PDU_POLL:
356		sscop->funcs->verbose(sscop, sscop->aarg, "%s POLL n(s)=%u n(ps)=%u",
357		    dir, v1 & 0xffffff, v2 & 0xffffff);
358		return;
359
360	  case PDU_STAT:
361		if (size < 12)
362			return;
363		v3 = MBUF_TRAIL32(m, -3);
364		sscop->funcs->verbose(sscop, sscop->aarg,
365		    "%s STAT n(r)=%u n(mr)=%u n(ps)=%u",
366		    dir, v1 & 0xffffff, v2 & 0xffffff, v3 & 0xffffff);
367		n = (size - 12) / 4;
368		for (i = 0; i < (size - 12) / 4; i++, n--) {
369			v4 = MBUF_TRAIL32(m, -4 - (int)i);
370			sscop->funcs->verbose(sscop, sscop->aarg,
371			    "   LE(%u)=%u", n, v4 & 0xffffff);
372		}
373		return;
374
375	  case PDU_USTAT:
376		if (size < 16)
377			return;
378		sscop->funcs->verbose(sscop, sscop->aarg,
379		    "%s STAT n(r)=%u n(mr)=%u LE1=%u LE2=%u",
380		    dir, v1 & 0xffffff, v2 & 0xffffff,
381		    MBUF_TRAIL32(m, -4) & 0xffffff,
382		    MBUF_TRAIL32(m, -3) & 0xffffff);
383		return;
384
385	  case PDU_UD:
386		sscop->funcs->verbose(sscop, sscop->aarg,
387		    "%s UD pl=%u", dir, (v1 >> 30) & 0x3);
388		return;
389
390	  case PDU_MD:
391		sscop->funcs->verbose(sscop, sscop->aarg,
392		    "%s MD pl=%u", dir, (v1 >> 30) & 0x3);
393		return;
394
395	  case PDU_ERAK:
396		sscop->funcs->verbose(sscop, sscop->aarg,
397		    "%s ERAK n(mr)=%u", dir, v1 & 0xffffff);
398		return;
399	}
400}
401#endif
402
403
404/*
405 * Initialize state of variables
406 */
407static void
408sscop_init(struct sscop *sscop)
409{
410	sscop->state = SSCOP_IDLE;
411
412	sscop->vt_sq = 0;
413	sscop->vr_sq = 0;
414	sscop->clear_buffers = 1;
415
416	sscop->ll_busy = 0;
417
418	sscop->rxq = 0;
419}
420
421static void
422sscop_clear(struct sscop *sscop)
423{
424	TIMER_STOP(sscop, cc);
425	TIMER_STOP(sscop, ka);
426	TIMER_STOP(sscop, nr);
427	TIMER_STOP(sscop, idle);
428	TIMER_STOP(sscop, poll);
429
430	FREE_UU(uu_bgn);
431	FREE_UU(uu_bgak);
432	FREE_UU(uu_bgrej);
433	FREE_UU(uu_end);
434	FREE_UU(uu_rs);
435
436	MSGQ_CLEAR(&sscop->xq);
437	MSGQ_CLEAR(&sscop->uxq);
438	MSGQ_CLEAR(&sscop->mxq);
439	MSGQ_CLEAR(&sscop->xbuf);
440	MSGQ_CLEAR(&sscop->rbuf);
441
442	SIGQ_CLEAR(&sscop->sigs);
443	SIGQ_CLEAR(&sscop->saved_sigs);
444}
445
446
447/*
448 * Allocate instance memory, initialize the state of all variables.
449 */
450struct sscop *
451sscop_create(void *a, const struct sscop_funcs *funcs)
452{
453	struct sscop *sscop;
454
455	MEMZALLOC(sscop, struct sscop *, sizeof(struct sscop));
456	if (sscop == NULL)
457		return (NULL);
458
459	if (a == NULL)
460		sscop->aarg = sscop;
461	else
462		sscop->aarg = a;
463	sscop->funcs = funcs;
464
465	sscop->maxk = MAXK;
466	sscop->maxj = MAXJ;
467	sscop->maxcc = MAXCC;
468	sscop->maxpd = MAXPD;
469	sscop->maxstat = MAXSTAT;
470	sscop->timercc = TIMERCC;
471	sscop->timerka = TIMERKA;
472	sscop->timernr = TIMERNR;
473	sscop->timerpoll = TIMERPOLL;
474	sscop->timeridle = TIMERIDLE;
475	sscop->robustness = 0;
476	sscop->poll_after_rex = 0;
477	sscop->mr = MAXMR;
478
479	TIMER_INIT(sscop, cc);
480	TIMER_INIT(sscop, nr);
481	TIMER_INIT(sscop, ka);
482	TIMER_INIT(sscop, poll);
483	TIMER_INIT(sscop, idle);
484
485	MSGQ_INIT(&sscop->xq);
486	MSGQ_INIT(&sscop->uxq);
487	MSGQ_INIT(&sscop->mxq);
488	MSGQ_INIT(&sscop->rbuf);
489	MSGQ_INIT(&sscop->xbuf);
490
491	SIGQ_INIT(&sscop->sigs);
492	SIGQ_INIT(&sscop->saved_sigs);
493
494	sscop_init(sscop);
495
496	return (sscop);
497}
498
499/*
500 * Free all resources in a sscop instance
501 */
502void
503sscop_destroy(struct sscop *sscop)
504{
505	sscop_reset(sscop);
506
507	MEMFREE(sscop);
508}
509
510/*
511 * Reset the SSCOP instance.
512 */
513void
514sscop_reset(struct sscop *sscop)
515{
516	sscop_clear(sscop);
517	sscop_init(sscop);
518}
519
520void
521sscop_getparam(const struct sscop *sscop, struct sscop_param *p)
522{
523	p->timer_cc = sscop->timercc;
524	p->timer_poll = sscop->timerpoll;
525	p->timer_keep_alive = sscop->timerka;
526	p->timer_no_response = sscop->timernr;
527	p->timer_idle = sscop->timeridle;
528	p->maxk = sscop->maxk;
529	p->maxj = sscop->maxj;
530	p->maxcc = sscop->maxcc;
531	p->maxpd = sscop->maxpd;
532	p->maxstat = sscop->maxstat;
533	p->mr = sscop->mr;
534	p->flags = 0;
535	if(sscop->robustness)
536		p->flags |= SSCOP_ROBUST;
537	if(sscop->poll_after_rex)
538		p->flags |= SSCOP_POLLREX;
539}
540
541int
542sscop_setparam(struct sscop *sscop, struct sscop_param *p, u_int *pmask)
543{
544	u_int mask = *pmask;
545
546	/* can change only in idle state */
547	if (sscop->state != SSCOP_IDLE)
548		return (EISCONN);
549
550	*pmask = 0;
551
552	/*
553	 * first check all parameters
554	 */
555	if ((mask & SSCOP_SET_TCC) && p->timer_cc == 0)
556		*pmask |= SSCOP_SET_TCC;
557	if ((mask & SSCOP_SET_TPOLL) && p->timer_poll == 0)
558		*pmask |= SSCOP_SET_TPOLL;
559	if ((mask & SSCOP_SET_TKA) && p->timer_keep_alive == 0)
560		*pmask |= SSCOP_SET_TKA;
561	if ((mask & SSCOP_SET_TNR) && p->timer_no_response == 0)
562		*pmask |= SSCOP_SET_TNR;
563	if ((mask & SSCOP_SET_TIDLE) && p->timer_idle == 0)
564		*pmask |= SSCOP_SET_TIDLE;
565	if ((mask & SSCOP_SET_MAXK) && p->maxk > MAXMAXK)
566		*pmask |= SSCOP_SET_MAXK;
567	if ((mask & SSCOP_SET_MAXJ) && p->maxj > MAXMAXJ)
568		*pmask |= SSCOP_SET_MAXJ;
569	if ((mask & SSCOP_SET_MAXCC) && p->maxcc > 255)
570		*pmask |= SSCOP_SET_MAXCC;
571	if ((mask & SSCOP_SET_MAXPD) && p->maxpd >= (1 << 24))
572		*pmask |= SSCOP_SET_MAXPD;
573	if ((mask & SSCOP_SET_MAXSTAT) &&
574	    ((p->maxstat & 1) == 0 || p->maxstat == 1 || p->maxstat == 2 ||
575	    p->maxstat * 4 > MAXMAXK - 8))
576		*pmask |= SSCOP_SET_MAXSTAT;
577	if ((mask & SSCOP_SET_MR) && p->mr >= (1 << 24) - 1)
578		*pmask |= SSCOP_SET_MR;
579
580	if (*pmask)
581		return (EINVAL);
582
583
584	/*
585	 * now set it
586	 */
587	if (mask & SSCOP_SET_TCC)
588		sscop->timercc = p->timer_cc;
589
590	if (mask & SSCOP_SET_TPOLL)
591		sscop->timerpoll = p->timer_poll;
592
593	if (mask & SSCOP_SET_TKA)
594		sscop->timerka = p->timer_keep_alive;
595
596	if (mask & SSCOP_SET_TNR)
597		sscop->timernr = p->timer_no_response;
598
599	if (mask & SSCOP_SET_TIDLE)
600		sscop->timeridle = p->timer_idle;
601
602	if (mask & SSCOP_SET_MAXK)
603		sscop->maxk = p->maxk;
604	if (mask & SSCOP_SET_MAXJ)
605		sscop->maxj = p->maxj;
606
607	if (mask & SSCOP_SET_MAXCC)
608		sscop->maxcc = p->maxcc;
609	if (mask & SSCOP_SET_MAXPD)
610		sscop->maxpd = p->maxpd;
611	if (mask & SSCOP_SET_MAXSTAT)
612		sscop->maxstat = p->maxstat;
613
614	if (mask & SSCOP_SET_MR)
615		sscop->mr = p->mr;
616
617	if (mask & SSCOP_SET_ROBUST)
618		sscop->robustness = ((p->flags & SSCOP_ROBUST) != 0);
619
620	if (mask & SSCOP_SET_POLLREX)
621		sscop->poll_after_rex = ((p->flags & SSCOP_POLLREX) != 0);
622
623	return (0);
624}
625
626enum sscop_state
627sscop_getstate(const struct sscop *sscop)
628{
629	return (sscop->state);
630}
631
632
633/************************************************************/
634/*
635 * EXTERNAL INPUT SIGNAL MAPPING
636 */
637
638/*
639 * Map AA signal to SSCOP internal signal
640 */
641int
642sscop_aasig(struct sscop *sscop, enum sscop_aasig sig,
643    struct SSCOP_MBUF_T *m, u_int arg)
644{
645	struct sscop_msg *msg;
646
647	if (sig >= sizeof(sscop_sigs)/sizeof(sscop_sigs[0])) {
648		VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg,
649		    "AA-Signal %u - bad signal", sig));
650		MBUF_FREE(m);
651		return (EINVAL);
652	}
653	VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg,
654	    "AA-Signal %s in state %s with%s message",
655	    sscop_sigs[sig], states[sscop->state], m ? "" : "out"));
656
657	MSG_ALLOC(msg);
658	if (msg == NULL) {
659		FAILURE("sscop: cannot allocate aasig");
660		MBUF_FREE(m);
661		return (ENOMEM);
662	}
663
664	switch(sig) {
665
666	  case SSCOP_ESTABLISH_request:
667		msg->m = m;
668		msg->rexmit = arg;
669		sscop_signal(sscop, SIG_ESTAB_REQ, msg);
670		break;
671
672	  case SSCOP_ESTABLISH_response:
673		msg->m = m;
674		msg->rexmit = arg;
675		sscop_signal(sscop, SIG_ESTAB_RESP, msg);
676		break;
677
678	  case SSCOP_RELEASE_request:
679		msg->m = m;
680		sscop_signal(sscop, SIG_RELEASE_REQ, msg);
681		break;
682
683	  case SSCOP_DATA_request:
684		msg->m = m;
685		sscop_signal(sscop, SIG_USER_DATA, msg);
686		break;
687
688	  case SSCOP_UDATA_request:
689		msg->m = m;
690		sscop_signal(sscop, SIG_UDATA, msg);
691		break;
692
693	  case SSCOP_RECOVER_response:
694		MBUF_FREE(m);
695		MSG_FREE(msg);
696		sscop_signal(sscop, SIG_RECOVER, NULL);
697		break;
698
699	  case SSCOP_RESYNC_request:
700		msg->m = m;
701		sscop_signal(sscop, SIG_SYNC_REQ, msg);
702		break;
703
704	  case SSCOP_RESYNC_response:
705		MBUF_FREE(m);
706		MSG_FREE(msg);
707		sscop_signal(sscop, SIG_SYNC_RESP, NULL);
708		break;
709
710	  case SSCOP_RETRIEVE_request:
711		MBUF_FREE(m);
712		msg->rexmit = arg;
713		sscop_signal(sscop, SIG_RETRIEVE, msg);
714		break;
715
716	  case SSCOP_ESTABLISH_indication:
717	  case SSCOP_ESTABLISH_confirm:
718	  case SSCOP_RELEASE_indication:
719	  case SSCOP_RELEASE_confirm:
720	  case SSCOP_DATA_indication:
721	  case SSCOP_UDATA_indication:
722	  case SSCOP_RECOVER_indication:
723	  case SSCOP_RESYNC_indication:
724	  case SSCOP_RESYNC_confirm:
725	  case SSCOP_RETRIEVE_indication:
726	  case SSCOP_RETRIEVE_COMPL_indication:
727		MBUF_FREE(m);
728		MSG_FREE(msg);
729		return EINVAL;
730	}
731
732	return 0;
733}
734
735/*
736 * Signal from layer management.
737 */
738int
739sscop_maasig(struct sscop *sscop, enum sscop_maasig sig, struct SSCOP_MBUF_T *m)
740{
741	struct sscop_msg *msg;
742
743	if (sig >= sizeof(sscop_msigs)/sizeof(sscop_msigs[0])) {
744		VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg,
745		    "MAA-Signal %u - bad signal", sig));
746		MBUF_FREE(m);
747		return (EINVAL);
748	}
749	VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg,
750	    "MAA-Signal %s in state %s with%s message",
751	    sscop_msigs[sig], states[sscop->state], m ? "" : "out"));
752
753	MSG_ALLOC(msg);
754	if (msg == NULL) {
755		FAILURE("sscop: cannot allocate maasig");
756		MBUF_FREE(m);
757		return (ENOMEM);
758	}
759
760	switch (sig) {
761
762	  case SSCOP_MDATA_request:
763		msg->m = m;
764		sscop_signal(sscop, SIG_MDATA, msg);
765		break;
766
767	  case SSCOP_MDATA_indication:
768	  case SSCOP_MERROR_indication:
769		MBUF_FREE(m);
770		MSG_FREE(msg);
771		return (EINVAL);
772	}
773	return (0);
774}
775
776/*
777 * Map PDU to SSCOP signal.
778 */
779void
780sscop_input(struct sscop *sscop, struct SSCOP_MBUF_T *m)
781{
782	struct sscop_msg *msg;
783	union pdu pdu;
784	u_int size;
785
786	MSG_ALLOC(msg);
787	if(msg == NULL) {
788		FAILURE("sscop: cannot allocate in pdu msg");
789		MBUF_FREE(m);
790		return;
791	}
792
793	msg->m = m;
794	msg->rexmit = 0;
795
796	size = MBUF_LEN(m);
797
798	if(size % 4 != 0 || size < 4)
799		goto err;
800
801	pdu.sscop_null = MBUF_TRAIL32(m, -1);
802
803	VERBOSE(sscop, SSCOP_DBG_PDU, (sscop, sscop->aarg,
804	    "got %s, size=%u", pdus[pdu.sscop_type], size));
805
806#ifdef SSCOP_DEBUG
807#define ENSURE(C,F)	if(!(C)) { VERBOSE(sscop, SSCOP_DBG_PDU, F); goto err; }
808#else
809#define ENSURE(C,F)	if(!(C)) goto err
810#endif
811
812#ifdef SSCOP_DEBUG
813	if (ISVERBOSE(sscop, SSCOP_DBG_PDU))
814		sscop_dump_pdu(sscop, "rx", m);
815#endif
816
817	switch(pdu.sscop_type) {
818
819          default:
820		ENSURE(0, (sscop, sscop->aarg,
821		    "Bad PDU type %u", pdu.sscop_type));
822		break;
823
824	  case PDU_BGN:
825		ENSURE(size >= 8U, (sscop, sscop->aarg,
826			"PDU_BGN size=%u", size));
827		ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg,
828			"PDU_BGN size=%u pl=%u", size, pdu.sscop_pl));
829		ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg,
830			"PDU_BGN size=%u", size));
831		sscop_signal(sscop, SIG_BGN, msg);
832		break;
833
834	  case PDU_BGAK:
835		ENSURE(size >= 8U, (sscop, sscop->aarg,
836			"PDU_BGAK size=%u", size));
837		ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg,
838			"PDU_BGAK size=%u pl=%u", size, pdu.sscop_pl));
839		ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg,
840			"PDU_BGAK size=%u", size));
841		sscop_signal(sscop, SIG_BGAK, msg);
842		break;
843
844	  case PDU_END:
845		ENSURE(size >= 8U, (sscop, sscop->aarg,
846			"PDU_END size=%u", size));
847		ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg,
848			"PDU_END size=%u pl=%u", size, pdu.sscop_pl));
849		ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg,
850			"PDU_END size=%u", size));
851		sscop_signal(sscop, SIG_END, msg);
852		break;
853
854	  case PDU_ENDAK:
855		ENSURE(size == 8U, (sscop, sscop->aarg,
856			"PDU_ENDAK size=%u", size));
857		sscop_signal(sscop, SIG_ENDAK, msg);
858		break;
859
860	  case PDU_BGREJ:
861		ENSURE(size >= 8U, (sscop, sscop->aarg,
862			"PDU_BGREJ size=%u", size));
863		ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg,
864			"PDU_BGREJ size=%u pl=%u", size, pdu.sscop_pl));
865		ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg,
866			"PDU_BGREJ size=%u", size));
867		sscop_signal(sscop, SIG_BGREJ, msg);
868		break;
869
870	  case PDU_SD:
871		ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg,
872			"PDU_SD size=%u pl=%u", size, pdu.sscop_pl));
873		ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg,
874			"PDU_SD size=%u", size));
875		sscop_signal(sscop, SIG_SD, msg);
876		break;
877
878	  case PDU_UD:
879		ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg,
880			"PDU_UD size=%u pl=%u", size, pdu.sscop_pl));
881		ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg,
882			"PDU_UD size=%u", size));
883		sscop_signal(sscop, SIG_UD, msg);
884		break;
885
886	  case PDU_MD:
887		ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg,
888			"PDU_MD size=%u pl=%u", size, pdu.sscop_pl));
889		ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg,
890			"PDU_MD size=%u", size));
891		sscop_signal(sscop, SIG_MD, msg);
892		break;
893
894	  case PDU_POLL:
895		ENSURE(size == 8U, (sscop, sscop->aarg,
896			"PDU_POLL size=%u", size));
897		sscop_signal(sscop, SIG_POLL, msg);
898		break;
899
900	  case PDU_STAT:
901		ENSURE(size >= 12U, (sscop, sscop->aarg,
902			"PDU_STAT size=%u", size));
903		ENSURE(size <= 12U + 4 * sscop->maxstat, (sscop, sscop->aarg,
904			"PDU_STAT size=%u", size));
905		sscop_signal(sscop, SIG_STAT, msg);
906		break;
907
908	  case PDU_RS:
909		ENSURE(size >= 8U, (sscop, sscop->aarg,
910			"PDU_RS size=%u", size));
911		ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg,
912			"PDU_RS size=%u pl=%u", size, pdu.sscop_pl));
913		ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg,
914			"PDU_RS size=%u", size));
915		sscop_signal(sscop, SIG_RS, msg);
916		break;
917
918	  case PDU_RSAK:
919		ENSURE(size == 8U, (sscop, sscop->aarg,
920			"PDU_RSAK size=%u", size));
921		sscop_signal(sscop, SIG_RSAK, msg);
922		break;
923
924	  case PDU_ER:
925		ENSURE(size == 8U, (sscop, sscop->aarg,
926			"PDU_ER size=%u", size));
927		sscop_signal(sscop, SIG_ER, msg);
928		break;
929
930	  case PDU_ERAK:
931		ENSURE(size == 8U, (sscop, sscop->aarg,
932			"PDU_ERAK size=%u", size));
933		sscop_signal(sscop, SIG_ERAK, msg);
934		break;
935
936	  case PDU_USTAT:
937		ENSURE(size == 16U, (sscop, sscop->aarg,
938			"PDU_ERAK size=%u", size));
939		sscop_signal(sscop, SIG_USTAT, msg);
940		break;
941	}
942#undef ENSURE
943	return;
944
945  err:
946	MAAL_ERROR(sscop, 'U', 0);
947	SSCOP_MSG_FREE(msg);
948}
949
950/************************************************************/
951/*
952 * UTILITIES
953 */
954
955/*
956 * Move the receiver window by N packets
957 */
958u_int
959sscop_window(struct sscop *sscop, u_int n)
960{
961	sscop->vr_mr += n;
962	return (SEQNO_DIFF(sscop->vr_mr, sscop->vr_r));
963}
964
965/*
966 * Lower layer busy handling
967 */
968u_int
969sscop_setbusy(struct sscop *sscop, int busy)
970{
971	u_int old = sscop->ll_busy;
972
973	if (busy > 0)
974		sscop->ll_busy = 1;
975	else if (busy == 0) {
976		sscop->ll_busy = 0;
977		if(old)
978			handle_sigs(sscop);
979	}
980
981	return (old);
982}
983
984const char *
985sscop_signame(enum sscop_aasig sig)
986{
987	static char str[40];
988
989	if (sig >= sizeof(sscop_sigs)/sizeof(sscop_sigs[0])) {
990		sprintf(str, "BAD SSCOP_AASIG %u", sig);
991		return (str);
992	} else {
993		return (sscop_sigs[sig]);
994	}
995}
996
997const char *
998sscop_msigname(enum sscop_maasig sig)
999{
1000	static char str[40];
1001
1002	if (sig >= sizeof(sscop_msigs)/sizeof(sscop_msigs[0])) {
1003		sprintf(str, "BAD SSCOP_MAASIG %u", sig);
1004		return (str);
1005	} else {
1006		return (sscop_msigs[sig]);
1007	}
1008}
1009
1010const char *
1011sscop_statename(enum sscop_state s)
1012{
1013	static char str[40];
1014
1015	if (s >= sizeof(states)/sizeof(states[0])) {
1016		sprintf(str, "BAD SSCOP_STATE %u", s);
1017		return (str);
1018	} else {
1019		return (states[s]);
1020	}
1021}
1022
1023
1024/************************************************************/
1025/*
1026 * MACROS
1027 */
1028
1029/*
1030 * p 75: release buffers
1031 */
1032static void
1033m_release_buffers(struct sscop *sscop)
1034{
1035	MSGQ_CLEAR(&sscop->xq);
1036	MSGQ_CLEAR(&sscop->xbuf);
1037	sscop->rxq = 0;
1038	MSGQ_CLEAR(&sscop->rbuf);
1039}
1040
1041/*
1042 * P 75: Prepare retrival
1043 */
1044static void
1045m_prepare_retrieval(struct sscop *sscop)
1046{
1047	struct sscop_msg *msg;
1048
1049	if (sscop->clear_buffers) {
1050		MSGQ_CLEAR(&sscop->xq);
1051		MSGQ_CLEAR(&sscop->xbuf);
1052	}
1053	MSGQ_FOREACH(msg, &sscop->xbuf)
1054		msg->rexmit = 0;
1055	sscop->rxq = 0;
1056
1057	MSGQ_CLEAR(&sscop->rbuf);
1058}
1059
1060/*
1061 * P 75: Prepare retrival
1062 */
1063static void
1064m_prepare_recovery(struct sscop *sscop)
1065{
1066	struct sscop_msg *msg;
1067
1068	if(sscop->clear_buffers) {
1069		MSGQ_CLEAR(&sscop->xq);
1070		MSGQ_CLEAR(&sscop->xbuf);
1071	}
1072	MSGQ_FOREACH(msg, &sscop->xbuf)
1073		msg->rexmit = 0;
1074	sscop->rxq = 0;
1075}
1076
1077
1078/*
1079 * P 75: Clear transmitter
1080 */
1081static void
1082m_clear_transmitter(struct sscop *sscop)
1083{
1084	if(!sscop->clear_buffers) {
1085		MSGQ_CLEAR(&sscop->xq);
1086		MSGQ_CLEAR(&sscop->xbuf);
1087	}
1088}
1089
1090
1091/*
1092 * p 75: Deliver data
1093 * Freeing the message is the responibility of the handler function.
1094 */
1095static void
1096m_deliver_data(struct sscop *sscop)
1097{
1098	struct sscop_msg *msg;
1099	u_int sn;
1100
1101	if ((msg = MSGQ_GET(&sscop->rbuf)) == NULL)
1102		return;
1103
1104	if (sscop->clear_buffers) {
1105		MSGQ_CLEAR(&sscop->rbuf);
1106		return;
1107	}
1108
1109	sn = msg->seqno + 1;
1110	AAL_DATA(sscop, SSCOP_DATA_indication, msg->m, msg->seqno);
1111	MSG_FREE(msg);
1112
1113	while ((msg = MSGQ_GET(&sscop->rbuf)) != NULL) {
1114		ASSERT(msg->seqno == sn);
1115		if (++sn == SSCOP_MAXSEQNO)
1116			sn = 0;
1117		AAL_DATA(sscop, SSCOP_DATA_indication, msg->m, msg->seqno);
1118		MSG_FREE(msg);
1119	}
1120}
1121
1122/*
1123 * P 75: Initialize state variables
1124 */
1125static void
1126m_initialize_state(struct sscop *sscop)
1127{
1128	sscop->vt_s = 0;
1129	sscop->vt_ps = 0;
1130	sscop->vt_a = 0;
1131
1132	sscop->vt_pa = 1;
1133	sscop->vt_pd = 0;
1134	sscop->credit = 1;
1135
1136	sscop->vr_r = 0;
1137	sscop->vr_h = 0;
1138}
1139
1140/*
1141 * p 76: Data retrieval
1142 */
1143static void
1144m_data_retrieval(struct sscop *sscop, u_int rn)
1145{
1146	struct sscop_msg *s;
1147
1148	if (rn != SSCOP_RETRIEVE_UNKNOWN) {
1149		if(rn >= SSCOP_RETRIEVE_TOTAL)
1150			rn = sscop->vt_a;
1151		else
1152			rn++;
1153		while(rn >= sscop->vt_a && rn < sscop->vt_s) {
1154			if(rn == SSCOP_MAXSEQNO) rn = 0;
1155			if((s = QFIND(&sscop->xbuf, rn)) != NULL) {
1156				MSGQ_REMOVE(&sscop->xbuf, s);
1157				AAL_DATA(sscop, SSCOP_RETRIEVE_indication,
1158					s->m, 0);
1159				MSG_FREE(s);
1160			}
1161			rn++;
1162		}
1163	}
1164
1165	while((s = MSGQ_GET(&sscop->xq)) != NULL) {
1166		AAL_DATA(sscop, SSCOP_RETRIEVE_indication, s->m, 0);
1167		MSG_FREE(s);
1168	}
1169	AAL_SIG(sscop, SSCOP_RETRIEVE_COMPL_indication);
1170}
1171
1172/*
1173 * P 76: Detect retransmission. PDU type must already be stripped.
1174 */
1175static int
1176m_detect_retransmission(struct sscop *sscop, struct sscop_msg *msg)
1177{
1178	union bgn bgn;
1179
1180	bgn.sscop_null = MBUF_TRAIL32(msg->m, -1);
1181
1182	if (sscop->vr_sq == bgn.sscop_bgns)
1183		return (1);
1184
1185	sscop->vr_sq = bgn.sscop_bgns;
1186	return (0);
1187}
1188
1189/*
1190 * P 76: Set POLL timer
1191 */
1192static void
1193m_set_poll_timer(struct sscop *sscop)
1194{
1195	if(MSGQ_EMPTY(&sscop->xq) && sscop->vt_s == sscop->vt_a)
1196		TIMER_RESTART(sscop, ka);
1197	else
1198		TIMER_RESTART(sscop, poll);
1199}
1200
1201/*
1202 * P 77: Reset data transfer timers
1203 */
1204static void
1205m_reset_data_xfer_timers(struct sscop *sscop)
1206{
1207	TIMER_STOP(sscop, ka);
1208	TIMER_STOP(sscop, nr);
1209	TIMER_STOP(sscop, idle);
1210	TIMER_STOP(sscop, poll);
1211}
1212
1213/*
1214 * P 77: Set data transfer timers
1215 */
1216static void
1217m_set_data_xfer_timers(struct sscop *sscop)
1218{
1219	TIMER_RESTART(sscop, poll);
1220	TIMER_RESTART(sscop, nr);
1221}
1222
1223/*
1224 * P 77: Initialize VR(MR)
1225 */
1226static void
1227m_initialize_mr(struct sscop *sscop)
1228{
1229	sscop->vr_mr = sscop->mr;
1230}
1231
1232/************************************************************/
1233/*
1234 * CONDITIONS
1235 */
1236static int
1237c_ready_pduq(struct sscop *sscop)
1238{
1239	if (!sscop->ll_busy &&
1240	    (sscop->rxq != 0 ||
1241	    sscop->vt_s < sscop->vt_ms ||
1242	    TIMER_ISACT(sscop, idle)))
1243		return (1);
1244	return (0);
1245}
1246
1247/************************************************************/
1248/*
1249 * SEND PDUS
1250 */
1251
1252/*
1253 * Send BG PDU.
1254 */
1255static void
1256send_bgn(struct sscop *sscop, struct SSCOP_MBUF_T *uu)
1257{
1258	union pdu pdu;
1259	union bgn bgn;
1260	struct SSCOP_MBUF_T *m;
1261
1262	pdu.sscop_null = 0;
1263	pdu.sscop_type = PDU_BGN;
1264	pdu.sscop_ns = sscop->vr_mr;
1265
1266	bgn.sscop_null = 0;
1267	bgn.sscop_bgns = sscop->vt_sq;
1268
1269	if(uu) {
1270		if ((m = MBUF_DUP(uu)) == NULL) {
1271			FAILURE("sscop: cannot allocate BGN");
1272			return;
1273		}
1274		pdu.sscop_pl += MBUF_PAD4(m);
1275	} else {
1276		if ((m = MBUF_ALLOC(8)) == NULL) {
1277			FAILURE("sscop: cannot allocate BGN");
1278			return;
1279		}
1280	}
1281
1282	MBUF_APPEND32(m, bgn.sscop_null);
1283	MBUF_APPEND32(m, pdu.sscop_null);
1284
1285	AAL_SEND(sscop, m);
1286}
1287
1288/*
1289 * Send BGREJ PDU.
1290 */
1291static void
1292send_bgrej(struct sscop *sscop, struct SSCOP_MBUF_T *uu)
1293{
1294	union pdu pdu;
1295	union bgn bgn;
1296	struct SSCOP_MBUF_T *m;
1297
1298	pdu.sscop_null = 0;
1299	pdu.sscop_type = PDU_BGREJ;
1300	bgn.sscop_null = 0;
1301
1302	if(uu) {
1303		if((m = MBUF_DUP(uu)) == NULL) {
1304			FAILURE("sscop: cannot allocate BGREJ");
1305			return;
1306		}
1307		pdu.sscop_pl += MBUF_PAD4(m);
1308	} else {
1309		if((m = MBUF_ALLOC(8)) == NULL) {
1310			FAILURE("sscop: cannot allocate BGREJ");
1311			return;
1312		}
1313	}
1314
1315	MBUF_APPEND32(m, bgn.sscop_null);
1316	MBUF_APPEND32(m, pdu.sscop_null);
1317
1318	AAL_SEND(sscop, m);
1319}
1320
1321/*
1322 * Send BGAK PDU.
1323 */
1324static void
1325send_bgak(struct sscop *sscop, struct SSCOP_MBUF_T *uu)
1326{
1327	union pdu pdu;
1328	union bgn bgn;
1329	struct SSCOP_MBUF_T *m;
1330
1331	pdu.sscop_null = 0;
1332	pdu.sscop_type = PDU_BGAK;
1333	pdu.sscop_ns = sscop->vr_mr;
1334	bgn.sscop_null = 0;
1335
1336	if(uu) {
1337		if((m = MBUF_DUP(uu)) == NULL) {
1338			FAILURE("sscop: cannot allocate BGAK");
1339			return;
1340		}
1341		pdu.sscop_pl += MBUF_PAD4(m);
1342	} else {
1343		if((m = MBUF_ALLOC(8)) == NULL) {
1344			FAILURE("sscop: cannot allocate BGAK");
1345			return;
1346		}
1347	}
1348
1349	MBUF_APPEND32(m, bgn.sscop_null);
1350	MBUF_APPEND32(m, pdu.sscop_null);
1351
1352	AAL_SEND(sscop, m);
1353}
1354
1355/*
1356 * Send SD PDU. The function makes a duplicate of the message.
1357 */
1358static void
1359send_sd(struct sscop *sscop, struct SSCOP_MBUF_T *m, u_int seqno)
1360{
1361	union pdu pdu;
1362
1363	if((m = MBUF_DUP(m)) == NULL) {
1364		FAILURE("sscop: cannot allocate SD");
1365		return;
1366	}
1367
1368	pdu.sscop_null = 0;
1369	pdu.sscop_pl = 0;
1370	pdu.sscop_type = PDU_SD;
1371	pdu.sscop_ns = seqno;
1372
1373	pdu.sscop_pl += MBUF_PAD4(m);
1374
1375	MBUF_APPEND32(m, pdu.sscop_null);
1376
1377	AAL_SEND(sscop, m);
1378}
1379
1380/*
1381 * Send a UD PDU. The caller must free the sscop msg part.
1382 */
1383static void
1384send_ud(struct sscop *sscop, struct SSCOP_MBUF_T *m)
1385{
1386	union pdu pdu;
1387
1388	pdu.sscop_null = 0;
1389	pdu.sscop_type = PDU_UD;
1390
1391	pdu.sscop_pl += MBUF_PAD4(m);
1392
1393	MBUF_APPEND32(m, pdu.sscop_null);
1394
1395	AAL_SEND(sscop, m);
1396}
1397
1398/*
1399 * Send a MD PDU. The caller must free the sscop msg part.
1400 */
1401static void
1402send_md(struct sscop *sscop, struct SSCOP_MBUF_T *m)
1403{
1404	union pdu pdu;
1405
1406	pdu.sscop_null = 0;
1407	pdu.sscop_type = PDU_MD;
1408
1409	pdu.sscop_pl += MBUF_PAD4(m);
1410
1411	MBUF_APPEND32(m, pdu.sscop_null);
1412
1413	AAL_SEND(sscop, m);
1414}
1415
1416/*
1417 * Send END PDU.
1418 */
1419static void
1420send_end(struct sscop *sscop, int src, struct SSCOP_MBUF_T *uu)
1421{
1422	union pdu pdu;
1423	struct SSCOP_MBUF_T *m;
1424
1425	sscop->last_end_src = src;
1426
1427	pdu.sscop_null = 0;
1428	pdu.sscop_s = src;
1429	pdu.sscop_type = PDU_END;
1430
1431	if(uu) {
1432		if((m = MBUF_DUP(uu)) == NULL) {
1433			FAILURE("sscop: cannot allocate END");
1434			return;
1435		}
1436		pdu.sscop_pl += MBUF_PAD4(m);
1437	} else {
1438		if((m = MBUF_ALLOC(8)) == NULL) {
1439			FAILURE("sscop: cannot allocate END");
1440			return;
1441		}
1442	}
1443
1444	MBUF_APPEND32(m, 0);
1445	MBUF_APPEND32(m, pdu.sscop_null);
1446
1447	AAL_SEND(sscop, m);
1448}
1449
1450/*
1451 * Send USTAT PDU. List must be terminated by -1.
1452 */
1453static void
1454send_ustat(struct sscop *sscop, ...)
1455{
1456	va_list ap;
1457	int f;
1458	u_int n;
1459	union pdu pdu;
1460	union seqno seqno;
1461	struct SSCOP_MBUF_T *m;
1462
1463	va_start(ap, sscop);
1464	n = 0;
1465	while((f = va_arg(ap, int)) >= 0)
1466		n++;
1467	va_end(ap);
1468
1469	if((m = MBUF_ALLOC(n * 4 + 8)) == NULL) {
1470		FAILURE("sscop: cannot allocate USTAT");
1471		return;
1472	}
1473
1474	va_start(ap, sscop);
1475	while((f = va_arg(ap, int)) >= 0) {
1476		seqno.sscop_null = 0;
1477		seqno.sscop_n = f;
1478		MBUF_APPEND32(m, seqno.sscop_null);
1479	}
1480	va_end(ap);
1481
1482	seqno.sscop_null = 0;
1483	seqno.sscop_n = sscop->vr_mr;
1484	MBUF_APPEND32(m, seqno.sscop_null);
1485
1486	pdu.sscop_null = 0;
1487	pdu.sscop_type = PDU_USTAT;
1488	pdu.sscop_ns = sscop->vr_r;
1489	MBUF_APPEND32(m, pdu.sscop_null);
1490
1491	AAL_SEND(sscop, m);
1492}
1493
1494/*
1495 * Send ER PDU.
1496 */
1497static void
1498send_er(struct sscop *sscop)
1499{
1500	union pdu pdu;
1501	union bgn bgn;
1502	struct SSCOP_MBUF_T *m;
1503
1504	pdu.sscop_null = 0;
1505	pdu.sscop_type = PDU_ER;
1506	pdu.sscop_ns = sscop->vr_mr;
1507
1508	bgn.sscop_null = 0;
1509	bgn.sscop_bgns = sscop->vt_sq;
1510
1511	if((m = MBUF_ALLOC(8)) == NULL) {
1512		FAILURE("sscop: cannot allocate ER");
1513		return;
1514	}
1515	MBUF_APPEND32(m, bgn.sscop_null);
1516	MBUF_APPEND32(m, pdu.sscop_null);
1517
1518	AAL_SEND(sscop, m);
1519}
1520
1521/*
1522 * Send POLL PDU.
1523 */
1524static void
1525send_poll(struct sscop *sscop)
1526{
1527	union pdu pdu;
1528	union seqno seqno;
1529	struct SSCOP_MBUF_T *m;
1530
1531	seqno.sscop_null = 0;
1532	seqno.sscop_n = sscop->vt_ps;
1533
1534	pdu.sscop_null = 0;
1535	pdu.sscop_ns = sscop->vt_s;
1536	pdu.sscop_type = PDU_POLL;
1537
1538	if((m = MBUF_ALLOC(8)) == NULL) {
1539		FAILURE("sscop: cannot allocate POLL");
1540		return;
1541	}
1542	MBUF_APPEND32(m, seqno.sscop_null);
1543	MBUF_APPEND32(m, pdu.sscop_null);
1544
1545	AAL_SEND(sscop, m);
1546}
1547
1548/*
1549 * Send STAT PDU. List is already in buffer.
1550 */
1551static void
1552send_stat(struct sscop *sscop, u_int nps, struct SSCOP_MBUF_T *m)
1553{
1554	union pdu pdu;
1555	union seqno seqno;
1556
1557	seqno.sscop_null = 0;
1558	seqno.sscop_n = nps;
1559	MBUF_APPEND32(m, seqno.sscop_null);
1560
1561	seqno.sscop_null = 0;
1562	seqno.sscop_n = sscop->vr_mr;
1563	MBUF_APPEND32(m, seqno.sscop_null);
1564
1565	pdu.sscop_null = 0;
1566	pdu.sscop_type = PDU_STAT;
1567	pdu.sscop_ns = sscop->vr_r;
1568	MBUF_APPEND32(m, pdu.sscop_null);
1569
1570	AAL_SEND(sscop, m);
1571}
1572
1573/*
1574 * Send ENDAK PDU.
1575 */
1576static void
1577send_endak(struct sscop *sscop)
1578{
1579	union pdu pdu;
1580	union seqno seqno;
1581	struct SSCOP_MBUF_T *m;
1582
1583	seqno.sscop_null = 0;
1584	pdu.sscop_null = 0;
1585	pdu.sscop_type = PDU_ENDAK;
1586
1587	if((m = MBUF_ALLOC(8)) == NULL) {
1588		FAILURE("sscop: cannot allocate ENDAK");
1589		return;
1590	}
1591	MBUF_APPEND32(m, seqno.sscop_null);
1592	MBUF_APPEND32(m, pdu.sscop_null);
1593
1594	AAL_SEND(sscop, m);
1595}
1596
1597/*
1598 * Send ERAK PDU.
1599 */
1600static void
1601send_erak(struct sscop *sscop)
1602{
1603	union pdu pdu;
1604	union seqno seqno;
1605	struct SSCOP_MBUF_T *m;
1606
1607	seqno.sscop_null = 0;
1608	pdu.sscop_null = 0;
1609	pdu.sscop_type = PDU_ERAK;
1610	pdu.sscop_ns = sscop->vr_mr;
1611
1612	if((m = MBUF_ALLOC(8)) == NULL) {
1613		FAILURE("sscop: cannot allocate ERAK");
1614		return;
1615	}
1616	MBUF_APPEND32(m, seqno.sscop_null);
1617	MBUF_APPEND32(m, pdu.sscop_null);
1618
1619	AAL_SEND(sscop, m);
1620}
1621
1622/*
1623 * Send RS PDU
1624 */
1625static void
1626send_rs(struct sscop *sscop, int resend, struct SSCOP_MBUF_T *uu)
1627{
1628	union pdu pdu;
1629	union bgn bgn;
1630	struct SSCOP_MBUF_T *m;
1631
1632	pdu.sscop_null = 0;
1633	pdu.sscop_type = PDU_RS;
1634	pdu.sscop_ns = resend ? sscop->rs_mr : sscop->vr_mr;
1635
1636	bgn.sscop_null = 0;
1637	bgn.sscop_bgns = resend ? sscop->rs_sq : sscop->vt_sq;
1638
1639	sscop->rs_mr = pdu.sscop_ns;
1640	sscop->rs_sq = bgn.sscop_bgns;
1641
1642	if(uu) {
1643		if((m = MBUF_DUP(uu)) == NULL) {
1644			FAILURE("sscop: cannot allocate RS");
1645			return;
1646		}
1647		pdu.sscop_pl += MBUF_PAD4(m);
1648	} else {
1649		if((m = MBUF_ALLOC(8)) == NULL) {
1650			FAILURE("sscop: cannot allocate RS");
1651			return;
1652		}
1653	}
1654
1655	MBUF_APPEND32(m, bgn.sscop_null);
1656	MBUF_APPEND32(m, pdu.sscop_null);
1657
1658	AAL_SEND(sscop, m);
1659}
1660
1661/*
1662 * Send RSAK pdu
1663 */
1664static void
1665send_rsak(struct sscop *sscop)
1666{
1667	union pdu pdu;
1668	union seqno seqno;
1669	struct SSCOP_MBUF_T *m;
1670
1671	seqno.sscop_null = 0;
1672	pdu.sscop_null = 0;
1673	pdu.sscop_type = PDU_RSAK;
1674	pdu.sscop_ns = sscop->vr_mr;
1675
1676	if((m = MBUF_ALLOC(8)) == NULL) {
1677		FAILURE("sscop: cannot allocate RSAK");
1678		return;
1679	}
1680
1681	MBUF_APPEND32(m, seqno.sscop_null);
1682	MBUF_APPEND32(m, pdu.sscop_null);
1683
1684	AAL_SEND(sscop, m);
1685}
1686
1687/************************************************************/
1688/*
1689 * P 31; IDLE && AA-ESTABLISH-request
1690 *	arg is UU data (opt).
1691 */
1692static void
1693sscop_idle_establish_req(struct sscop *sscop, struct sscop_msg *uu)
1694{
1695	u_int br = uu->rexmit;
1696
1697	SET_UU(uu_bgn, uu);
1698
1699	m_clear_transmitter(sscop);
1700
1701	sscop->clear_buffers = br;
1702
1703	sscop->vt_cc = 1;
1704	sscop->vt_sq++;
1705
1706	m_initialize_mr(sscop);
1707
1708	send_bgn(sscop, sscop->uu_bgn);
1709
1710	TIMER_RESTART(sscop, cc);
1711
1712	sscop_set_state(sscop, SSCOP_OUT_PEND);
1713}
1714
1715/*
1716 * P 31: IDLE && BGN PDU
1717 *	arg is the received PDU (freed).
1718 */
1719static void
1720sscop_idle_bgn(struct sscop *sscop, struct sscop_msg *msg)
1721{
1722	union pdu pdu;
1723	union bgn bgn;
1724
1725	pdu.sscop_null = MBUF_STRIP32(msg->m);
1726
1727	if(sscop->robustness) {
1728		bgn.sscop_null = MBUF_STRIP32(msg->m);
1729		sscop->vr_sq = bgn.sscop_bgns;
1730	} else {
1731		if(m_detect_retransmission(sscop, msg)) {
1732			send_bgrej(sscop, sscop->uu_bgrej);
1733			SSCOP_MSG_FREE(msg);
1734			return;
1735		}
1736		(void)MBUF_STRIP32(msg->m);
1737	}
1738
1739	sscop->vt_ms = pdu.sscop_ns;
1740	sscop_set_state(sscop, SSCOP_IN_PEND);
1741
1742	AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
1743}
1744
1745/*
1746 * p 31: IDLE && ENDAK PDU
1747 * p 34: OUT_PEND && ENDAK PDU
1748 * p 34: OUT_PEND && SD PDU
1749 * p 34: OUT_PEND && ERAK PDU
1750 * p 34: OUT_PEND && END PDU
1751 * p 34: OUT_PEND && STAT PDU
1752 * p 34: OUT_PEND && USTAT PDU
1753 * p 34: OUT_PEND && POLL PDU
1754 * p 36: OUT_PEND && RS PDU
1755 * p 36: OUT_PEND && RSAK PDU
1756 * p 40: OUTGOING_DISCONNECT_PENDING && SD PDU
1757 * p 40: OUTGOING_DISCONNECT_PENDING && BGAK PDU
1758 * p 40: OUTGOING_DISCONNECT_PENDING && POLL PDU
1759 * p 40: OUTGOING_DISCONNECT_PENDING && STAT PDU
1760 * p 40: OUTGOING_DISCONNECT_PENDING && USTAT PDU
1761 * p 41: OUTGOING_DISCONNECT_PENDING && ERAK PDU
1762 * p 42: OUTGOING_DISCONNECT_PENDING && ER PDU
1763 * p 42: OUTGOING_DISCONNECT_PENDING && RS PDU
1764 * p 42: OUTGOING_DISCONNECT_PENDING && RSAK PDU
1765 * p 43: OUTGOING_RESYNC && ER PDU
1766 * p 43: OUTGOING_RESYNC && POLL PDU
1767 * p 44: OUTGOING_RESYNC && STAT PDU
1768 * p 44: OUTGOING_RESYNC && USTAT PDU
1769 * p 45: OUTGOING_RESYNC && BGAK PDU
1770 * p 45: OUTGOING_RESYNC && SD PDU
1771 * p 45: OUTGOING_RESYNC && ERAK PDU
1772 * P 60: READY && BGAK PDU
1773 * P 60: READY && ERAK PDU
1774 *	arg is pdu (freed).
1775 */
1776static void
1777sscop_ignore_pdu(struct sscop *sscop __unused, struct sscop_msg *msg)
1778{
1779	SSCOP_MSG_FREE(msg);
1780}
1781
1782/*
1783 * p 31: IDLE && END PDU
1784 *	arg is pdu (freed).
1785 */
1786static void
1787sscop_idle_end(struct sscop *sscop, struct sscop_msg *msg)
1788{
1789	SSCOP_MSG_FREE(msg);
1790	send_endak(sscop);
1791}
1792
1793/*
1794 * p 31: IDLE && ER PDU
1795 *	arg is pdu (freed).
1796 */
1797static void
1798sscop_idle_er(struct sscop *sscop, struct sscop_msg *msg)
1799{
1800	SSCOP_MSG_FREE(msg);
1801	MAAL_ERROR(sscop, 'L', 0);
1802	FREE_UU(uu_end);
1803	send_end(sscop, 1, NULL);
1804}
1805
1806/*
1807 * p 31: IDLE && BGREJ PDU
1808 *	arg is pdu (freed).
1809 */
1810static void
1811sscop_idle_bgrej(struct sscop *sscop, struct sscop_msg *msg)
1812{
1813	SSCOP_MSG_FREE(msg);
1814	MAAL_ERROR(sscop, 'D', 0);
1815	FREE_UU(uu_end);
1816}
1817
1818/*
1819 * p 32: IDLE && POLL PDU
1820 *	arg is pdu (freed).
1821 */
1822static void
1823sscop_idle_poll(struct sscop *sscop, struct sscop_msg *msg)
1824{
1825	SSCOP_MSG_FREE(msg);
1826	MAAL_ERROR(sscop, 'G', 0);
1827	FREE_UU(uu_end);
1828	send_end(sscop, 1, NULL);
1829}
1830
1831/*
1832 * p 32: IDLE && SD PDU
1833 *	arg is pdu (freed).
1834 */
1835static void
1836sscop_idle_sd(struct sscop *sscop, struct sscop_msg *msg)
1837{
1838	SSCOP_MSG_FREE(msg);
1839	MAAL_ERROR(sscop, 'A', 0);
1840	FREE_UU(uu_end);
1841	send_end(sscop, 1, NULL);
1842}
1843
1844/*
1845 * p 32: IDLE && BGAK PDU
1846 *	arg is pdu (freed).
1847 */
1848static void
1849sscop_idle_bgak(struct sscop *sscop, struct sscop_msg *msg)
1850{
1851	SSCOP_MSG_FREE(msg);
1852	MAAL_ERROR(sscop, 'C', 0);
1853	FREE_UU(uu_end);
1854	send_end(sscop, 1, NULL);
1855}
1856
1857/*
1858 * p 32: IDLE && ERAK PDU
1859 *	arg is pdu (freed).
1860 */
1861static void
1862sscop_idle_erak(struct sscop *sscop, struct sscop_msg *msg)
1863{
1864	SSCOP_MSG_FREE(msg);
1865	MAAL_ERROR(sscop, 'M', 0);
1866	FREE_UU(uu_end);
1867	send_end(sscop, 1, NULL);
1868}
1869
1870/*
1871 * p 32: IDLE && STAT PDU
1872 *	arg is pdu (freed).
1873 */
1874static void
1875sscop_idle_stat(struct sscop *sscop, struct sscop_msg *msg)
1876{
1877	SSCOP_MSG_FREE(msg);
1878	MAAL_ERROR(sscop, 'H', 0);
1879	FREE_UU(uu_end);
1880	send_end(sscop, 1, NULL);
1881}
1882
1883/*
1884 * p 32: IDLE && USTAT PDU
1885 *	arg is pdu (freed).
1886 */
1887static void
1888sscop_idle_ustat(struct sscop *sscop, struct sscop_msg *msg)
1889{
1890	SSCOP_MSG_FREE(msg);
1891	MAAL_ERROR(sscop, 'I', 0);
1892	FREE_UU(uu_end);
1893	send_end(sscop, 1, NULL);
1894}
1895
1896/*
1897 * p 33: IDLE & RS PDU
1898 *	arg is pdu (freed).
1899 */
1900static void
1901sscop_idle_rs(struct sscop *sscop, struct sscop_msg *msg)
1902{
1903	SSCOP_MSG_FREE(msg);
1904	MAAL_ERROR(sscop, 'J', 0);
1905	FREE_UU(uu_end);
1906	send_end(sscop, 1, NULL);
1907}
1908
1909/*
1910 * p 33: IDLE & RSAK PDU
1911 *	arg is pdu (freed).
1912 */
1913static void
1914sscop_idle_rsak(struct sscop *sscop, struct sscop_msg *msg)
1915{
1916	SSCOP_MSG_FREE(msg);
1917	MAAL_ERROR(sscop, 'K', 0);
1918	FREE_UU(uu_end);
1919	send_end(sscop, 1, NULL);
1920}
1921
1922/*
1923 * p 33: IDLE && PDU_Q
1924 * p XX: OUTPEND && PDU_Q
1925 * p 39: IN_PEND && PDU_Q
1926 * p 45: OUT_RESYNC_PEND && PDU_Q
1927 * p 48: IN_RESYNC_PEND && PDU_Q
1928 *	no arg
1929 */
1930static void
1931sscop_flush_pduq(struct sscop *sscop __unused, struct sscop_msg *unused __unused)
1932{
1933#if 0
1934	MSGQ_CLEAR(&sscop->xq);
1935#endif
1936}
1937
1938/*
1939 * p 34: OUT_PEND && BGAK PDU
1940 *	arg is pdu (freed).
1941 */
1942static void
1943sscop_outpend_bgak(struct sscop *sscop, struct sscop_msg *msg)
1944{
1945	union pdu pdu;
1946
1947	pdu.sscop_null = MBUF_STRIP32(msg->m);
1948	(void)MBUF_STRIP32(msg->m);
1949
1950	TIMER_STOP(sscop, cc);
1951	sscop->vt_ms = pdu.sscop_ns;
1952
1953	AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_confirm, msg, pdu.sscop_pl, 0);
1954
1955	m_initialize_state(sscop);
1956	m_set_data_xfer_timers(sscop);
1957
1958	sscop_set_state(sscop, SSCOP_READY);
1959}
1960
1961/*
1962 * P 34: OUT_PEND && BGREJ PDU
1963 */
1964static void
1965sscop_outpend_bgrej(struct sscop *sscop, struct sscop_msg *msg)
1966{
1967	union pdu pdu;
1968
1969	pdu.sscop_null = MBUF_STRIP32(msg->m);
1970	(void)MBUF_STRIP32(msg->m);
1971
1972	TIMER_STOP(sscop, cc);
1973
1974	AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, 0);
1975
1976	sscop_set_state(sscop, SSCOP_IDLE);
1977}
1978
1979/*
1980 * P 35: OUT_PEND && TIMER_CC expiry
1981 *	no arg
1982 */
1983static void
1984sscop_outpend_tcc(struct sscop *sscop, struct sscop_msg *unused __unused)
1985{
1986	if(sscop->vt_cc >= sscop->maxcc) {
1987		MAAL_ERROR(sscop, 'O', 0);
1988		FREE_UU(uu_end);
1989		send_end(sscop, 1, NULL);
1990
1991		AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
1992
1993		sscop_set_state(sscop, SSCOP_IDLE);
1994	} else {
1995		sscop->vt_cc++;
1996		send_bgn(sscop, sscop->uu_bgn);
1997		TIMER_RESTART(sscop, cc);
1998	}
1999}
2000
2001/*
2002 * P 35: OUT_PEND && RELEASE_REQ
2003 *	arg is UU
2004 */
2005static void
2006sscop_outpend_release_req(struct sscop *sscop, struct sscop_msg *uu)
2007{
2008	SET_UU(uu_end, uu);
2009
2010	TIMER_STOP(sscop, cc);
2011	sscop->vt_cc = 1;
2012	send_end(sscop, 0, sscop->uu_end);
2013	TIMER_RESTART(sscop, cc);
2014
2015	sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
2016}
2017
2018/*
2019 * P 36: OUT_PEND && BGN PDU
2020 *	arg is the received PDU (freed).
2021 */
2022static void
2023sscop_outpend_bgn(struct sscop *sscop, struct sscop_msg *msg)
2024{
2025	union pdu pdu;
2026
2027	pdu.sscop_null = MBUF_STRIP32(msg->m);
2028
2029	if(m_detect_retransmission(sscop, msg)) {
2030		SSCOP_MSG_FREE(msg);
2031		return;
2032	}
2033	(void)MBUF_STRIP32(msg->m);
2034
2035	TIMER_STOP(sscop, cc);
2036
2037	sscop->vt_ms = pdu.sscop_ns;
2038
2039	m_initialize_mr(sscop);
2040
2041	send_bgak(sscop, sscop->uu_bgak);
2042
2043	AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_confirm, msg, pdu.sscop_pl, 0);
2044
2045	m_initialize_state(sscop);
2046
2047	m_set_data_xfer_timers(sscop);
2048
2049	sscop_set_state(sscop, SSCOP_READY);
2050}
2051
2052/*
2053 * p 37: IN_PEND && AA-ESTABLISH.response
2054 *	arg is UU
2055 */
2056static void
2057sscop_inpend_establish_resp(struct sscop *sscop, struct sscop_msg *uu)
2058{
2059	u_int br = uu->rexmit;
2060
2061	SET_UU(uu_bgak, uu);
2062
2063	m_clear_transmitter(sscop);
2064	sscop->clear_buffers = br;
2065	m_initialize_mr(sscop);
2066	send_bgak(sscop, sscop->uu_bgak);
2067	m_initialize_state(sscop);
2068	m_set_data_xfer_timers(sscop);
2069
2070	sscop_set_state(sscop, SSCOP_READY);
2071}
2072
2073/*
2074 * p 37: IN_PEND && AA-RELEASE.request
2075 *	arg is uu.
2076 */
2077static void
2078sscop_inpend_release_req(struct sscop *sscop, struct sscop_msg *uu)
2079{
2080	SET_UU(uu_bgrej, uu);
2081
2082	send_bgrej(sscop, sscop->uu_bgrej);
2083
2084	sscop_set_state(sscop, SSCOP_IDLE);
2085}
2086
2087/*
2088 * p 37: IN_PEND && BGN PDU
2089 *	arg is pdu. (freed)
2090 */
2091static void
2092sscop_inpend_bgn(struct sscop *sscop, struct sscop_msg *msg)
2093{
2094	union pdu pdu;
2095
2096	pdu.sscop_null = MBUF_STRIP32(msg->m);
2097
2098	if(m_detect_retransmission(sscop, msg)) {
2099		SSCOP_MSG_FREE(msg);
2100		return;
2101	}
2102	(void)MBUF_STRIP32(msg->m);
2103
2104	sscop->vt_ms = pdu.sscop_ns;
2105
2106	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
2107	AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
2108}
2109
2110/*
2111 * p 37: IN_PEND && ER PDU
2112 *	arg is pdu (freed).
2113 */
2114static void
2115sscop_inpend_er(struct sscop *sscop, struct sscop_msg *msg)
2116{
2117	MAAL_ERROR(sscop, 'L', 0);
2118	SSCOP_MSG_FREE(msg);
2119}
2120
2121/*
2122 * p 37: IN_PEND && ENDAK PDU
2123 *	arg is pdu (freed).
2124 */
2125static void
2126sscop_inpend_endak(struct sscop *sscop, struct sscop_msg *msg)
2127{
2128	MAAL_ERROR(sscop, 'F', 0);
2129
2130	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2131
2132	sscop_set_state(sscop, SSCOP_IDLE);
2133
2134	SSCOP_MSG_FREE(msg);
2135}
2136
2137/*
2138 * p 38: IN_PEND && BGAK PDU
2139 *	arg is pdu (freed).
2140 */
2141static void
2142sscop_inpend_bgak(struct sscop *sscop, struct sscop_msg *msg)
2143{
2144	MAAL_ERROR(sscop, 'C', 0);
2145
2146	SSCOP_MSG_FREE(msg);
2147}
2148
2149/*
2150 * p 38: IN_PEND && BGREJ PDU
2151 *	arg is pdu (freed).
2152 */
2153static void
2154sscop_inpend_bgrej(struct sscop *sscop, struct sscop_msg *msg)
2155{
2156	MAAL_ERROR(sscop, 'D', 0);
2157
2158	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2159
2160	SSCOP_MSG_FREE(msg);
2161
2162	sscop_set_state(sscop, SSCOP_IDLE);
2163}
2164
2165/*
2166 * p 38: IN_PEND && SD PDU
2167 *	arg is pdu (freed).
2168 */
2169static void
2170sscop_inpend_sd(struct sscop *sscop, struct sscop_msg *msg)
2171{
2172	MAAL_ERROR(sscop, 'A', 0);
2173
2174	SSCOP_MSG_FREE(msg);
2175
2176	FREE_UU(uu_end);
2177	send_end(sscop, 1, NULL);
2178
2179	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2180
2181	sscop_set_state(sscop, SSCOP_IDLE);
2182}
2183
2184/*
2185 * p 38: IN_PEND && USTAT PDU
2186 *	arg is pdu (freed).
2187 */
2188static void
2189sscop_inpend_ustat(struct sscop *sscop, struct sscop_msg *msg)
2190{
2191	MAAL_ERROR(sscop, 'I', 0);
2192
2193	SSCOP_MSG_FREE(msg);
2194
2195	FREE_UU(uu_end);
2196	send_end(sscop, 1, NULL);
2197
2198	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2199
2200	sscop_set_state(sscop, SSCOP_IDLE);
2201}
2202
2203/*
2204 * p 38: IN_PEND && STAT PDU
2205 *	arg is pdu (freed).
2206 */
2207static void
2208sscop_inpend_stat(struct sscop *sscop, struct sscop_msg *msg)
2209{
2210	MAAL_ERROR(sscop, 'H', 0);
2211
2212	SSCOP_MSG_FREE(msg);
2213
2214	FREE_UU(uu_end);
2215	send_end(sscop, 1, NULL);
2216
2217	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2218
2219	sscop_set_state(sscop, SSCOP_IDLE);
2220}
2221
2222/*
2223 * p 38: IN_PEND && POLL PDU
2224 *	arg is pdu (freed).
2225 */
2226static void
2227sscop_inpend_poll(struct sscop *sscop, struct sscop_msg *msg)
2228{
2229	MAAL_ERROR(sscop, 'G', 0);
2230
2231	SSCOP_MSG_FREE(msg);
2232
2233	FREE_UU(uu_end);
2234	send_end(sscop, 1, NULL);
2235
2236	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2237
2238	sscop_set_state(sscop, SSCOP_IDLE);
2239}
2240
2241/*
2242 * p 39: IN_PEND && ERAK PDU
2243 *	arg is pdu (freed).
2244 */
2245static void
2246sscop_inpend_erak(struct sscop *sscop, struct sscop_msg *msg)
2247{
2248	SSCOP_MSG_FREE(msg);
2249	MAAL_ERROR(sscop, 'M', 0);
2250}
2251
2252/*
2253 * p 39: IN_PEND & RS PDU
2254 *	arg is pdu (freed).
2255 */
2256static void
2257sscop_inpend_rs(struct sscop *sscop, struct sscop_msg *msg)
2258{
2259	SSCOP_MSG_FREE(msg);
2260	MAAL_ERROR(sscop, 'J', 0);
2261}
2262
2263/*
2264 * p 39: IN_PEND & RSAK PDU
2265 *	arg is pdu (freed).
2266 */
2267static void
2268sscop_inpend_rsak(struct sscop *sscop, struct sscop_msg *msg)
2269{
2270	SSCOP_MSG_FREE(msg);
2271	MAAL_ERROR(sscop, 'K', 0);
2272}
2273
2274/*
2275 * p 39: IN_PEND && END PDU
2276 *	arg is pdu (freed).
2277 *	no uui
2278 */
2279static void
2280sscop_inpend_end(struct sscop *sscop, struct sscop_msg *msg)
2281{
2282	union pdu pdu;
2283
2284	pdu.sscop_null = MBUF_STRIP32(msg->m);
2285	(void)MBUF_STRIP32(msg->m);
2286
2287	send_endak(sscop);
2288
2289	AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
2290		msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
2291
2292	sscop_set_state(sscop, SSCOP_IDLE);
2293}
2294
2295/*
2296 * p 40: OUT_DIS_PEND && SSCOP_ESTABLISH_request
2297 *	no arg.
2298 *	no uui.
2299 */
2300static void
2301sscop_outdis_establish_req(struct sscop *sscop, struct sscop_msg *uu)
2302{
2303	SET_UU(uu_bgn, uu);
2304
2305	TIMER_STOP(sscop, cc);
2306	m_clear_transmitter(sscop);
2307	sscop->clear_buffers = 1;
2308	sscop->vt_cc = 1;
2309	sscop->vt_sq++;
2310	m_initialize_mr(sscop);
2311	send_bgn(sscop, sscop->uu_bgn);
2312	TIMER_RESTART(sscop, cc);
2313
2314	sscop_set_state(sscop, SSCOP_OUT_PEND);
2315}
2316
2317/*
2318 * p 41: OUT_DIS_PEND && END PDU
2319 *	arg is pdu (freed).
2320 */
2321static void
2322sscop_outdis_end(struct sscop *sscop, struct sscop_msg *msg)
2323{
2324	union pdu pdu;
2325
2326	pdu.sscop_null = MBUF_STRIP32(msg->m);
2327	(void)MBUF_STRIP32(msg->m);
2328
2329	TIMER_STOP(sscop, cc);
2330	send_endak(sscop);
2331
2332	AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_confirm, msg, pdu.sscop_pl, 0);
2333
2334	sscop_set_state(sscop, SSCOP_IDLE);
2335}
2336
2337/*
2338 * p 41: OUT_DIS_PEND && ENDAK PDU
2339 * p 41: OUT_DIS_PEND && BGREJ PDU
2340 *	arg is pdu (freed)
2341 */
2342static void
2343sscop_outdis_endak(struct sscop *sscop, struct sscop_msg *msg)
2344{
2345	union pdu pdu;
2346
2347	pdu.sscop_null = MBUF_STRIP32(msg->m);
2348	(void)MBUF_STRIP32(msg->m);
2349
2350	TIMER_STOP(sscop, cc);
2351
2352	AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_confirm, msg, pdu.sscop_pl, 0);
2353
2354	sscop_set_state(sscop, SSCOP_IDLE);
2355}
2356
2357/*
2358 * p 41: OUT_DIS_PEND && TIMER CC expiry
2359 *	no arg
2360 */
2361static void
2362sscop_outdis_cc(struct sscop *sscop, struct sscop_msg *unused __unused)
2363{
2364	if(sscop->vt_cc >= sscop->maxcc) {
2365		MAAL_ERROR(sscop, 'O', 0);
2366		AAL_SIG(sscop, SSCOP_RELEASE_confirm);
2367		sscop_set_state(sscop, SSCOP_IDLE);
2368	} else {
2369		sscop->vt_cc++;
2370		send_end(sscop, sscop->last_end_src, sscop->uu_end);
2371		TIMER_RESTART(sscop, cc);
2372	}
2373}
2374
2375/*
2376 * p 42: OUT_DIS_PEND && BGN PDU
2377 *	arg is pdu (freed).
2378 */
2379static void
2380sscop_outdis_bgn(struct sscop *sscop, struct sscop_msg *msg)
2381{
2382	union pdu pdu;
2383
2384	pdu.sscop_null = MBUF_STRIP32(msg->m);
2385
2386	if(m_detect_retransmission(sscop, msg)) {
2387		FREE_UU(uu_bgak);
2388		send_bgak(sscop, NULL);
2389		send_end(sscop, sscop->last_end_src, sscop->uu_end);
2390		SSCOP_MSG_FREE(msg);
2391
2392	} else {
2393		(void)MBUF_STRIP32(msg->m);
2394
2395		TIMER_STOP(sscop, cc);
2396		sscop->vt_ms = pdu.sscop_ns;
2397		AAL_SIG(sscop, SSCOP_RELEASE_confirm);
2398		AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication,
2399			msg, pdu.sscop_pl, 0);
2400		sscop_set_state(sscop, SSCOP_IN_PEND);
2401	}
2402}
2403
2404/*
2405 * p 43: OUT_RESYNC_PEND && BGN PDU
2406 *	arg is pdu (freed).
2407 */
2408static void
2409sscop_outsync_bgn(struct sscop *sscop, struct sscop_msg *msg)
2410{
2411	union pdu pdu;
2412
2413	pdu.sscop_null = MBUF_STRIP32(msg->m);
2414
2415	if(m_detect_retransmission(sscop, msg)) {
2416		send_bgak(sscop, sscop->uu_bgak);
2417		send_rs(sscop, 1, sscop->uu_rs);
2418		SSCOP_MSG_FREE(msg);
2419	} else {
2420		(void)MBUF_STRIP32(msg->m);
2421
2422		TIMER_STOP(sscop, cc);
2423		sscop->vt_ms = pdu.sscop_ns;
2424		AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
2425		AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication,
2426			msg, pdu.sscop_pl, 0);
2427		sscop_set_state(sscop, SSCOP_IN_PEND);
2428	}
2429}
2430
2431/*
2432 * p 43: OUT_RESYNC_PEND && ENDAK PDU
2433 *	arg is pdu (freed).
2434 */
2435static void
2436sscop_outsync_endak(struct sscop *sscop, struct sscop_msg *msg)
2437{
2438	SSCOP_MSG_FREE(msg);
2439	TIMER_STOP(sscop, cc);
2440	MAAL_ERROR(sscop, 'F', 0);
2441	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2442	sscop_set_state(sscop, SSCOP_IDLE);
2443}
2444
2445/*
2446 * p 43: OUT_RESYNC_PEND && BGREJ PDU
2447 *	arg is pdu (freed).
2448 */
2449static void
2450sscop_outsync_bgrej(struct sscop *sscop, struct sscop_msg *msg)
2451{
2452	SSCOP_MSG_FREE(msg);
2453	TIMER_STOP(sscop, cc);
2454	MAAL_ERROR(sscop, 'D', 0);
2455	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2456	sscop_set_state(sscop, SSCOP_IDLE);
2457}
2458
2459/*
2460 * p 43: OUT_RESYNC_PEND && END PDU
2461 *	arg is pdu (freed).
2462 *	no UU-data
2463 */
2464static void
2465sscop_outsync_end(struct sscop *sscop, struct sscop_msg *msg)
2466{
2467	union pdu pdu;
2468
2469	pdu.sscop_null = MBUF_STRIP32(msg->m);
2470	(void)MBUF_STRIP32(msg->m);
2471
2472	TIMER_STOP(sscop, cc);
2473	send_endak(sscop);
2474	AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl,
2475		(u_int)pdu.sscop_s);
2476	sscop_set_state(sscop, SSCOP_IDLE);
2477}
2478
2479/*
2480 * p 44: OUT_RESYNC && TIMER CC expiry
2481 */
2482static void
2483sscop_outsync_cc(struct sscop *sscop, struct sscop_msg *msg __unused)
2484{
2485	if(sscop->vt_cc == sscop->maxcc) {
2486		MAAL_ERROR(sscop, 'O', 0);
2487		FREE_UU(uu_end);
2488		send_end(sscop, 1, NULL);
2489		AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2490		sscop_set_state(sscop, SSCOP_IDLE);
2491	} else {
2492		sscop->vt_cc++;
2493		send_rs(sscop, 1, sscop->uu_rs);
2494		TIMER_RESTART(sscop, cc);
2495	}
2496}
2497
2498/*
2499 * p 44: OUT_RESYNC && AA-RELEASE.request
2500 *	arg is UU
2501 */
2502static void
2503sscop_outsync_release_req(struct sscop *sscop, struct sscop_msg *uu)
2504{
2505	SET_UU(uu_end, uu);
2506
2507	TIMER_STOP(sscop, cc);
2508	sscop->vt_cc = 1;
2509	send_end(sscop, 0, sscop->uu_end);
2510	TIMER_RESTART(sscop, cc);
2511	sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
2512}
2513
2514/*
2515 * p 45: OUT_RESYNC && RS PDU
2516 *	arg is pdu (freed).
2517 */
2518static void
2519sscop_outsync_rs(struct sscop *sscop, struct sscop_msg *msg)
2520{
2521	union pdu pdu;
2522
2523	pdu.sscop_null = MBUF_STRIP32(msg->m);
2524
2525	if(m_detect_retransmission(sscop, msg)) {
2526		SSCOP_MSG_FREE(msg);
2527		return;
2528	}
2529	(void)MBUF_STRIP32(msg->m);
2530
2531	TIMER_STOP(sscop, cc);
2532	sscop->vt_ms = pdu.sscop_ns;
2533	m_initialize_mr(sscop);
2534	send_rsak(sscop);
2535	AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_confirm, msg, pdu.sscop_pl, 0);
2536	m_initialize_state(sscop);
2537	m_set_data_xfer_timers(sscop);
2538	sscop_set_state(sscop, SSCOP_READY);
2539}
2540
2541/*
2542 * p 45: OUT_RESYNC && RSAK PDU
2543 *	arg is pdu (freed).
2544 */
2545static void
2546sscop_outsync_rsak(struct sscop *sscop, struct sscop_msg *msg)
2547{
2548	union pdu pdu;
2549
2550	pdu.sscop_null = MBUF_STRIP32(msg->m);
2551
2552	SSCOP_MSG_FREE(msg);
2553
2554	TIMER_STOP(sscop, cc);
2555	sscop->vt_ms = pdu.sscop_ns;
2556	AAL_SIG(sscop, SSCOP_RESYNC_confirm);
2557	m_initialize_state(sscop);
2558	m_set_data_xfer_timers(sscop);
2559	sscop_set_state(sscop, SSCOP_READY);
2560}
2561
2562/*
2563 * p 46: IN_RESYNC_PEND && AA-RESYNC.response
2564 */
2565static void
2566sscop_insync_sync_resp(struct sscop *sscop, struct sscop_msg *noarg __unused)
2567{
2568	m_initialize_mr(sscop);
2569	send_rsak(sscop);
2570	m_clear_transmitter(sscop);
2571	m_initialize_state(sscop);
2572	m_set_data_xfer_timers(sscop);
2573	sscop_set_state(sscop, SSCOP_READY);
2574}
2575
2576/*
2577 * p 46: IN_RESYNC_PEND && AA-RELEASE.request
2578 *	arg is uu
2579 */
2580static void
2581sscop_insync_release_req(struct sscop *sscop, struct sscop_msg *uu)
2582{
2583	SET_UU(uu_end, uu);
2584
2585	sscop->vt_cc = 1;
2586	send_end(sscop, 0, sscop->uu_end);
2587	TIMER_RESTART(sscop, cc);
2588	sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
2589}
2590
2591/*
2592 * p 46: IN_RESYNC_PEND && ENDAK PDU
2593 *	arg is pdu (freed).
2594 */
2595static void
2596sscop_insync_endak(struct sscop *sscop, struct sscop_msg *msg)
2597{
2598	SSCOP_MSG_FREE(msg);
2599	MAAL_ERROR(sscop, 'F', 0);
2600	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2601	sscop_set_state(sscop, SSCOP_IDLE);
2602}
2603
2604/*
2605 * p 46: IN_RESYNC_PEND && BGREJ PDU
2606 *	arg is pdu (freed).
2607 */
2608static void
2609sscop_insync_bgrej(struct sscop *sscop, struct sscop_msg *msg)
2610{
2611	SSCOP_MSG_FREE(msg);
2612	MAAL_ERROR(sscop, 'D', 0);
2613	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2614	sscop_set_state(sscop, SSCOP_IDLE);
2615}
2616
2617/*
2618 * p 46: IN_RESYNC_PEND && END PDU
2619 *	arg is pdu (freed).
2620 */
2621static void
2622sscop_insync_end(struct sscop *sscop, struct sscop_msg *msg)
2623{
2624	union pdu pdu;
2625
2626	pdu.sscop_null = MBUF_STRIP32(msg->m);
2627	(void)MBUF_STRIP32(msg->m);
2628
2629	send_endak(sscop);
2630	AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
2631		msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
2632	sscop_set_state(sscop, SSCOP_IDLE);
2633}
2634
2635/*
2636 * p 47: IN_RESYNC_PEND && ER PDU
2637 *	arg is pdu (freed).
2638 */
2639static void
2640sscop_insync_er(struct sscop *sscop, struct sscop_msg *msg)
2641{
2642	SSCOP_MSG_FREE(msg);
2643	MAAL_ERROR(sscop, 'L', 0);
2644}
2645
2646/*
2647 * p 47: IN_RESYNC_PEND && BGN PDU
2648 *	arg is pdu (freed).
2649 */
2650static void
2651sscop_insync_bgn(struct sscop *sscop, struct sscop_msg *msg)
2652{
2653	union pdu pdu;
2654
2655	pdu.sscop_null = MBUF_STRIP32(msg->m);
2656
2657	if(m_detect_retransmission(sscop, msg)) {
2658		MAAL_ERROR(sscop, 'B', 0);
2659		SSCOP_MSG_FREE(msg);
2660		return;
2661	}
2662	(void)MBUF_STRIP32(msg->m);
2663
2664	sscop->vt_ms = pdu.sscop_ns;
2665	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
2666	AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
2667
2668	sscop_set_state(sscop, SSCOP_IN_PEND);
2669}
2670
2671/*
2672 * p 47: IN_RESYNC_PEND && SD PDU
2673 *	arg is pdu (freed).
2674 */
2675static void
2676sscop_insync_sd(struct sscop *sscop, struct sscop_msg *msg)
2677{
2678	SSCOP_MSG_FREE(msg);
2679	MAAL_ERROR(sscop, 'A', 0);
2680	FREE_UU(uu_end);
2681	send_end(sscop, 1, NULL);
2682	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2683	sscop_set_state(sscop, SSCOP_IDLE);
2684}
2685
2686/*
2687 * p 47: IN_RESYNC_PEND && POLL PDU
2688 *	arg is pdu (freed).
2689 */
2690static void
2691sscop_insync_poll(struct sscop *sscop, struct sscop_msg *msg)
2692{
2693	SSCOP_MSG_FREE(msg);
2694	MAAL_ERROR(sscop, 'G', 0);
2695	FREE_UU(uu_end);
2696	send_end(sscop, 1, NULL);
2697	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2698	sscop_set_state(sscop, SSCOP_IDLE);
2699}
2700
2701/*
2702 * p 47: IN_RESYNC_PEND && STAT PDU
2703 *	arg is pdu (freed).
2704 */
2705static void
2706sscop_insync_stat(struct sscop *sscop, struct sscop_msg *msg)
2707{
2708	SSCOP_MSG_FREE(msg);
2709	MAAL_ERROR(sscop, 'H', 0);
2710	FREE_UU(uu_end);
2711	send_end(sscop, 1, NULL);
2712	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2713	sscop_set_state(sscop, SSCOP_IDLE);
2714}
2715
2716/*
2717 * p 47: IN_RESYNC_PEND && USTAT PDU
2718 *	arg is pdu (freed).
2719 */
2720static void
2721sscop_insync_ustat(struct sscop *sscop, struct sscop_msg *msg)
2722{
2723	SSCOP_MSG_FREE(msg);
2724	MAAL_ERROR(sscop, 'I', 0);
2725	FREE_UU(uu_end);
2726	send_end(sscop, 1, NULL);
2727	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2728	sscop_set_state(sscop, SSCOP_IDLE);
2729}
2730
2731/*
2732 * p 48: IN_RESYNC_PEND && BGAK PDU
2733 *	arg is pdu (freed).
2734 */
2735static void
2736sscop_insync_bgak(struct sscop *sscop, struct sscop_msg *msg)
2737{
2738	MAAL_ERROR(sscop, 'C', 0);
2739	SSCOP_MSG_FREE(msg);
2740}
2741
2742/*
2743 * p 48: IN_RESYNC_PEND && ERAK PDU
2744 *	arg is pdu (freed).
2745 */
2746static void
2747sscop_insync_erak(struct sscop *sscop, struct sscop_msg *msg)
2748{
2749	MAAL_ERROR(sscop, 'M', 0);
2750	SSCOP_MSG_FREE(msg);
2751}
2752
2753/*
2754 * p 48: IN_RESYNC_PEND && RS PDU
2755 *	arg is pdu (freed).
2756 */
2757static void
2758sscop_insync_rs(struct sscop *sscop, struct sscop_msg *msg)
2759{
2760	union pdu pdu;
2761
2762	pdu.sscop_null = MBUF_STRIP32(msg->m);
2763
2764	if(m_detect_retransmission(sscop, msg)) {
2765		SSCOP_MSG_FREE(msg);
2766		return;
2767	}
2768	SSCOP_MSG_FREE(msg);
2769	MAAL_ERROR(sscop, 'J', 0);
2770}
2771
2772/*
2773 * p 48: IN_RESYNC_PEND && RSAK PDU
2774 *	arg is pdu (freed).
2775 */
2776static void
2777sscop_insync_rsak(struct sscop *sscop, struct sscop_msg *msg)
2778{
2779	MAAL_ERROR(sscop, 'K', 0);
2780	SSCOP_MSG_FREE(msg);
2781}
2782
2783
2784/*
2785 * p 49: OUT_REC_PEND && AA-DATA.request
2786 *	arg is message (queued).
2787 */
2788static void
2789sscop_outrec_userdata(struct sscop *sscop, struct sscop_msg *msg)
2790{
2791	if(!sscop->clear_buffers) {
2792		MSGQ_APPEND(&sscop->xq, msg);
2793		sscop_signal(sscop, SIG_PDU_Q, msg);
2794	} else {
2795		SSCOP_MSG_FREE(msg);
2796	}
2797}
2798
2799/*
2800 * p 49: OUT_REC_PEND && BGAK PDU
2801 *	arg is pdu (freed)
2802 */
2803static void
2804sscop_outrec_bgak(struct sscop *sscop, struct sscop_msg *msg)
2805{
2806	MAAL_ERROR(sscop, 'C', 0);
2807
2808	SSCOP_MSG_FREE(msg);
2809}
2810
2811/*
2812 * p 49: OUT_REC_PEND && ERAK PDU
2813 *	arg is pdu (freed)
2814 */
2815static void
2816sscop_outrec_erak(struct sscop *sscop, struct sscop_msg *msg)
2817{
2818	union pdu pdu;
2819
2820	pdu.sscop_null = MBUF_STRIP32(msg->m);
2821
2822	TIMER_STOP(sscop, cc);
2823	sscop->vt_ms = pdu.sscop_ns;
2824	m_deliver_data(sscop);
2825
2826	AAL_SIG(sscop, SSCOP_RECOVER_indication);
2827
2828	sscop_set_state(sscop, SSCOP_REC_PEND);
2829
2830	SSCOP_MSG_FREE(msg);
2831}
2832
2833/*
2834 * p 49: OUT_REC_PEND && END PDU
2835 *	arg is pdu (freed)
2836 */
2837static void
2838sscop_outrec_end(struct sscop *sscop, struct sscop_msg *msg)
2839{
2840	union pdu pdu;
2841
2842	pdu.sscop_null = MBUF_STRIP32(msg->m);
2843	(void)MBUF_STRIP32(msg->m);
2844
2845	TIMER_STOP(sscop, cc);
2846	send_endak(sscop);
2847	AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
2848		msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
2849
2850	MSGQ_CLEAR(&sscop->rbuf);
2851
2852	sscop_set_state(sscop, SSCOP_IDLE);
2853}
2854
2855/*
2856 * p 49: OUT_REC_PEND && ENDAK PDU
2857 *	arg is pdu (freed)
2858 */
2859static void
2860sscop_outrec_endak(struct sscop *sscop, struct sscop_msg *msg)
2861{
2862	MAAL_ERROR(sscop, 'F', 0);
2863	TIMER_STOP(sscop, cc);
2864	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2865	MSGQ_CLEAR(&sscop->rbuf);
2866
2867	sscop_set_state(sscop, SSCOP_IDLE);
2868
2869	SSCOP_MSG_FREE(msg);
2870}
2871
2872/*
2873 * p 49: OUT_REC_PEND && BGREJ PDU
2874 *	arg is pdu (freed)
2875 */
2876static void
2877sscop_outrec_bgrej(struct sscop *sscop, struct sscop_msg *msg)
2878{
2879	MAAL_ERROR(sscop, 'D', 0);
2880	TIMER_STOP(sscop, cc);
2881	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2882	MSGQ_CLEAR(&sscop->rbuf);
2883
2884	sscop_set_state(sscop, SSCOP_IDLE);
2885
2886	SSCOP_MSG_FREE(msg);
2887}
2888
2889/*
2890 * p 50: OUT_REC_PEND && TIMER CC expiry
2891 *	no arg.
2892 */
2893static void
2894sscop_outrec_cc(struct sscop *sscop, struct sscop_msg *unused __unused)
2895{
2896	if(sscop->vt_cc >= sscop->maxcc) {
2897		MAAL_ERROR(sscop, 'O', 0);
2898		FREE_UU(uu_end);
2899		send_end(sscop, 1, NULL);
2900		AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
2901		MSGQ_CLEAR(&sscop->rbuf);
2902		sscop_set_state(sscop, SSCOP_IDLE);
2903	} else {
2904		sscop->vt_cc++;
2905		send_er(sscop);
2906		TIMER_RESTART(sscop, cc);
2907	}
2908}
2909
2910/*
2911 * p 50: OUT_REC_PEND && SSCOP_RELEASE_request
2912 *	arg is UU
2913 */
2914static void
2915sscop_outrec_release_req(struct sscop *sscop, struct sscop_msg *uu)
2916{
2917	SET_UU(uu_end, uu);
2918
2919	TIMER_STOP(sscop, cc);
2920	sscop->vt_cc = 1;
2921	send_end(sscop, 0, sscop->uu_end);
2922	MSGQ_CLEAR(&sscop->rbuf);
2923	TIMER_RESTART(sscop, cc);
2924
2925	sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
2926}
2927
2928/*
2929 * p 51: OUT_REC_PEND && AA-RESYNC.request
2930 *	arg is uu
2931 */
2932static void
2933sscop_outrec_sync_req(struct sscop *sscop, struct sscop_msg *uu)
2934{
2935	SET_UU(uu_rs, uu);
2936
2937	TIMER_STOP(sscop, cc);
2938	sscop->vt_cc = 1;
2939	sscop->vt_sq++;
2940	m_initialize_mr(sscop);
2941	send_rs(sscop, 0, sscop->uu_rs);
2942	m_clear_transmitter(sscop);
2943	MSGQ_CLEAR(&sscop->rbuf);
2944	TIMER_RESTART(sscop, cc);
2945}
2946
2947/*
2948 * p 51: OUT_REC_PEND && BGN PDU
2949 *	arg is pdu (freed).
2950 *	no uui
2951 */
2952static void
2953sscop_outrec_bgn(struct sscop *sscop, struct sscop_msg *msg)
2954{
2955	union pdu pdu;
2956
2957	pdu.sscop_null = MBUF_STRIP32(msg->m);
2958
2959	if(m_detect_retransmission(sscop, msg)) {
2960		MAAL_ERROR(sscop, 'B', 0);
2961		SSCOP_MSG_FREE(msg);
2962	} else {
2963		(void)MBUF_STRIP32(msg->m);
2964
2965		TIMER_STOP(sscop, cc);
2966		sscop->vt_ms = pdu.sscop_ns;
2967		AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
2968		AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication,
2969			msg, pdu.sscop_pl, 0);
2970		MSGQ_CLEAR(&sscop->rbuf);
2971
2972		sscop_set_state(sscop, SSCOP_IN_PEND);
2973	}
2974}
2975
2976/*
2977 * p 51: OUT_REC_PEND && ER PDU
2978 *	arg is pdu (freed).
2979 */
2980static void
2981sscop_outrec_er(struct sscop *sscop, struct sscop_msg *msg)
2982{
2983	union pdu pdu;
2984
2985	pdu.sscop_null = MBUF_STRIP32(msg->m);
2986
2987	if(m_detect_retransmission(sscop, msg)) {
2988		MAAL_ERROR(sscop, 'L', 0);
2989	} else {
2990		TIMER_STOP(sscop, cc);
2991		sscop->vt_ms = pdu.sscop_ns;
2992		m_initialize_mr(sscop);
2993		send_erak(sscop);
2994		m_deliver_data(sscop);
2995
2996		AAL_SIG(sscop, SSCOP_RECOVER_indication);
2997
2998		sscop_set_state(sscop, SSCOP_REC_PEND);
2999	}
3000
3001	SSCOP_MSG_FREE(msg);
3002}
3003
3004/*
3005 * p 52: OUT_REC_PEND && SD PDU queued
3006 *	no arg.
3007 */
3008static void
3009sscop_outrec_pduq(struct sscop *sscop, struct sscop_msg *msg)
3010{
3011	sscop_save_signal(sscop, SIG_PDU_Q, msg);
3012}
3013
3014/*
3015 * p 52: OUT_REC_PEND && RSAK PDU
3016 *	arg is pdu (freed).
3017 */
3018static void
3019sscop_outrec_rsak(struct sscop *sscop, struct sscop_msg *msg)
3020{
3021	SSCOP_MSG_FREE(msg);
3022	MAAL_ERROR(sscop, 'K', 0);
3023}
3024
3025/*
3026 * p 52: OUT_REC_PEND && RS PDU
3027 *	arg is pdu (freed).
3028 */
3029static void
3030sscop_outrec_rs(struct sscop *sscop, struct sscop_msg *msg)
3031{
3032	union pdu pdu;
3033
3034	pdu.sscop_null = MBUF_STRIP32(msg->m);
3035
3036	if(m_detect_retransmission(sscop, msg)) {
3037		SSCOP_MSG_FREE(msg);
3038		MAAL_ERROR(sscop, 'J', 0);
3039		return;
3040	}
3041	(void)MBUF_STRIP32(msg->m);
3042
3043	TIMER_STOP(sscop, cc);
3044	sscop->vt_ms = pdu.sscop_ns;
3045	AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0);
3046	MSGQ_CLEAR(&sscop->rbuf);
3047	sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND);
3048}
3049
3050/*
3051 * p 53: REC_PEND && BGAK PDU
3052 *	arg is pdu (freed)
3053 */
3054static void
3055sscop_rec_bgak(struct sscop *sscop, struct sscop_msg *msg)
3056{
3057	MAAL_ERROR(sscop, 'C', 0);
3058
3059	SSCOP_MSG_FREE(msg);
3060}
3061
3062/*
3063 * p 53: REC_PEND && END PDU
3064 *	arg is pdu (freed)
3065 *	no uui
3066 */
3067static void
3068sscop_rec_end(struct sscop *sscop, struct sscop_msg *msg)
3069{
3070	union pdu pdu;
3071
3072	pdu.sscop_null = MBUF_STRIP32(msg->m);
3073	(void)MBUF_STRIP32(msg->m);
3074
3075	send_endak(sscop);
3076	AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
3077		msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
3078
3079	sscop_set_state(sscop, SSCOP_IDLE);
3080}
3081
3082/*
3083 * p 53: REC_PEND && ENDAK PDU
3084 *	arg is pdu (freed)
3085 */
3086static void
3087sscop_rec_endak(struct sscop *sscop, struct sscop_msg *msg)
3088{
3089	MAAL_ERROR(sscop, 'F', 0);
3090	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3091	sscop_set_state(sscop, SSCOP_IDLE);
3092	SSCOP_MSG_FREE(msg);
3093}
3094
3095/*
3096 * p 53: REC_PEND && BGREJ PDU
3097 *	arg is pdu (freed)
3098 */
3099static void
3100sscop_rec_bgrej(struct sscop *sscop, struct sscop_msg *msg)
3101{
3102	MAAL_ERROR(sscop, 'D', 0);
3103	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3104	sscop_set_state(sscop, SSCOP_IDLE);
3105	SSCOP_MSG_FREE(msg);
3106}
3107
3108/*
3109 * p 54: REC_PEND && RELEASE
3110 *	arg is UU
3111 */
3112static void
3113sscop_rec_release_req(struct sscop *sscop, struct sscop_msg *uu)
3114{
3115	SET_UU(uu_end, uu);
3116
3117	sscop->vt_cc = 1;
3118	send_end(sscop, 0, sscop->uu_end);
3119	TIMER_RESTART(sscop, cc);
3120
3121	sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
3122}
3123
3124/*
3125 * p 54: REC_PEND && RSAK PDU
3126 *	arg is pdu (freed).
3127 */
3128static void
3129sscop_rec_rsak(struct sscop *sscop, struct sscop_msg *msg)
3130{
3131	MAAL_ERROR(sscop, 'K', 0);
3132	SSCOP_MSG_FREE(msg);
3133}
3134
3135
3136/*
3137 * p 54: REC_PEND && RS PDU
3138 *	arg is pdu (freed).
3139 */
3140static void
3141sscop_rec_rs(struct sscop *sscop, struct sscop_msg *msg)
3142{
3143	union pdu pdu;
3144
3145	pdu.sscop_null = MBUF_STRIP32(msg->m);
3146
3147	if(m_detect_retransmission(sscop, msg)) {
3148		SSCOP_MSG_FREE(msg);
3149		MAAL_ERROR(sscop, 'J', 0);
3150		return;
3151	}
3152	(void)MBUF_STRIP32(msg->m);
3153
3154	sscop->vt_ms = pdu.sscop_ns;
3155	AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0);
3156
3157	sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND);
3158}
3159
3160/*
3161 * p 54: REC_PEND && RECOVER response
3162 *	no arg
3163 */
3164static void
3165sscop_rec_recover(struct sscop *sscop, struct sscop_msg *unused __unused)
3166{
3167	if(!sscop->clear_buffers) {
3168		MSGQ_CLEAR(&sscop->xbuf);
3169	}
3170	m_initialize_state(sscop);
3171	m_set_data_xfer_timers(sscop);
3172
3173	sscop_set_state(sscop, SSCOP_READY);
3174}
3175
3176/*
3177 * p 54: REC_PEND && RESYNC request
3178 *	arg is uu
3179 */
3180static void
3181sscop_rec_sync_req(struct sscop *sscop, struct sscop_msg *uu)
3182{
3183	SET_UU(uu_rs, uu);
3184
3185	m_clear_transmitter(sscop);
3186	sscop->vt_cc = 1;
3187	sscop->vt_sq++;
3188	m_initialize_mr(sscop);
3189	send_rs(sscop, 0, sscop->uu_rs);
3190	TIMER_RESTART(sscop, cc);
3191
3192	sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND);
3193}
3194
3195/*
3196 * p 55: REC_PEND && SD PDU queued
3197 *	no arg
3198 */
3199static void
3200sscop_rec_pduq(struct sscop *sscop, struct sscop_msg *msg)
3201{
3202	sscop_save_signal(sscop, SIG_PDU_Q, msg);
3203}
3204
3205/*
3206 * p 55: REC_PEND && ER PDU
3207 *	arg is pdu (freed).
3208 */
3209static void
3210sscop_rec_er(struct sscop *sscop, struct sscop_msg *msg)
3211{
3212	union pdu pdu;
3213
3214	pdu.sscop_null = MBUF_STRIP32(msg->m);
3215
3216	if(m_detect_retransmission(sscop, msg)) {
3217		send_erak(sscop);
3218	} else {
3219		MAAL_ERROR(sscop, 'L', 0);
3220	}
3221	SSCOP_MSG_FREE(msg);
3222}
3223
3224/*
3225 * p 55: REC_PEND && BGN PDU
3226 *	arg is pdu (freed)
3227 *	no uui
3228 */
3229static void
3230sscop_rec_bgn(struct sscop *sscop, struct sscop_msg *msg)
3231{
3232	union pdu pdu;
3233
3234	pdu.sscop_null = MBUF_STRIP32(msg->m);
3235
3236	if(m_detect_retransmission(sscop, msg)) {
3237		MAAL_ERROR(sscop, 'B', 0);
3238		SSCOP_MSG_FREE(msg);
3239		return;
3240	}
3241	(void)MBUF_STRIP32(msg->m);
3242
3243	sscop->vt_ms = pdu.sscop_ns;
3244	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
3245	AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
3246
3247	sscop_set_state(sscop, SSCOP_IN_PEND);
3248}
3249
3250/*
3251 * p 55: REC_PEND && STAT PDU
3252 *	arg is pdu (freed)
3253 */
3254static void
3255sscop_rec_stat(struct sscop *sscop, struct sscop_msg *msg)
3256{
3257	MAAL_ERROR(sscop, 'H', 0);
3258	FREE_UU(uu_end);
3259	send_end(sscop, 1, NULL);
3260	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3261	sscop_set_state(sscop, SSCOP_IDLE);
3262	SSCOP_MSG_FREE(msg);
3263}
3264
3265/*
3266 * p 55: REC_PEND && USTAT PDU
3267 *	arg is pdu (freed)
3268 */
3269static void
3270sscop_rec_ustat(struct sscop *sscop, struct sscop_msg *msg)
3271{
3272	MAAL_ERROR(sscop, 'I', 0);
3273	FREE_UU(uu_end);
3274	send_end(sscop, 1, NULL);
3275	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3276	sscop_set_state(sscop, SSCOP_IDLE);
3277	SSCOP_MSG_FREE(msg);
3278}
3279
3280/*
3281 * p 56: IN_REC_PEND && AA-RECOVER.response
3282 *	no arg
3283 */
3284static void
3285sscop_inrec_recover(struct sscop *sscop, struct sscop_msg *unused __unused)
3286{
3287	if(!sscop->clear_buffers) {
3288		MSGQ_CLEAR(&sscop->xbuf);
3289	}
3290	m_initialize_mr(sscop);
3291	send_erak(sscop);
3292	m_initialize_state(sscop);
3293	m_set_data_xfer_timers(sscop);
3294
3295	sscop_set_state(sscop, SSCOP_READY);
3296}
3297
3298/*
3299 * p 56: IN_REC_PEND && SD PDU queued
3300 *	no arg
3301 */
3302static void
3303sscop_inrec_pduq(struct sscop *sscop, struct sscop_msg *msg)
3304{
3305	sscop_save_signal(sscop, SIG_PDU_Q, msg);
3306}
3307
3308/*
3309 * p 56: IN_REC_PEND && AA-RELEASE.request
3310 *	arg is UU
3311 */
3312static void
3313sscop_inrec_release_req(struct sscop *sscop, struct sscop_msg *uu)
3314{
3315	SET_UU(uu_end, uu);
3316
3317	sscop->vt_cc = 1;
3318	send_end(sscop, 0, sscop->uu_end);
3319	TIMER_RESTART(sscop, cc);
3320
3321	sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
3322}
3323
3324/*
3325 * p 56: IN_REC_PEND && END PDU
3326 *	arg is pdu (freed).
3327 *	no uui
3328 */
3329static void
3330sscop_inrec_end(struct sscop *sscop, struct sscop_msg *msg)
3331{
3332	union pdu pdu;
3333
3334	pdu.sscop_null = MBUF_STRIP32(msg->m);
3335	(void)MBUF_STRIP32(msg->m);
3336
3337	send_endak(sscop);
3338	AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
3339		msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
3340
3341	sscop_set_state(sscop, SSCOP_IDLE);
3342}
3343
3344/*
3345 * p 56: IN_REC_PEND && RESYNC_REQ
3346 */
3347static void
3348sscop_inrec_sync_req(struct sscop *sscop, struct sscop_msg *uu)
3349{
3350	SET_UU(uu_rs, uu);
3351
3352	m_clear_transmitter(sscop);
3353	sscop->vt_cc = 1;
3354	sscop->vt_sq++;
3355	m_initialize_mr(sscop);
3356	send_rs(sscop, 0, sscop->uu_rs);
3357	TIMER_RESTART(sscop, cc);
3358
3359	sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND);
3360}
3361
3362
3363/*
3364 * p 57: IN_REC_PEND && ENDAK PDU
3365 *	arg is pdu (freed)
3366 */
3367static void
3368sscop_inrec_endak(struct sscop *sscop, struct sscop_msg *msg)
3369{
3370	MAAL_ERROR(sscop, 'F', 0);
3371	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3372	SSCOP_MSG_FREE(msg);
3373	sscop_set_state(sscop, SSCOP_IDLE);
3374}
3375
3376/*
3377 * p 57: IN_REC_PEND && BGREJ PDU
3378 *	arg is pdu (freed)
3379 */
3380static void
3381sscop_inrec_bgrej(struct sscop *sscop, struct sscop_msg *msg)
3382{
3383	MAAL_ERROR(sscop, 'D', 0);
3384	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3385	SSCOP_MSG_FREE(msg);
3386	sscop_set_state(sscop, SSCOP_IDLE);
3387}
3388
3389/*
3390 * p 57: IN_REC_PEND && USTAT PDU
3391 *	arg is pdu (freed)
3392 */
3393static void
3394sscop_inrec_ustat(struct sscop *sscop, struct sscop_msg *msg)
3395{
3396	MAAL_ERROR(sscop, 'I', 0);
3397	FREE_UU(uu_end);
3398	send_end(sscop, 1, NULL);
3399	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3400	SSCOP_MSG_FREE(msg);
3401	sscop_set_state(sscop, SSCOP_IDLE);
3402}
3403
3404/*
3405 * p 57: IN_REC_PEND && STAT PDU
3406 *	arg is pdu (freed)
3407 */
3408static void
3409sscop_inrec_stat(struct sscop *sscop, struct sscop_msg *msg)
3410{
3411	MAAL_ERROR(sscop, 'H', 0);
3412	FREE_UU(uu_end);
3413	send_end(sscop, 1, NULL);
3414	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3415	SSCOP_MSG_FREE(msg);
3416	sscop_set_state(sscop, SSCOP_IDLE);
3417}
3418
3419/*
3420 * p 57: IN_REC_PEND && POLL PDU
3421 *	arg is pdu (freed)
3422 */
3423static void
3424sscop_inrec_poll(struct sscop *sscop, struct sscop_msg *msg)
3425{
3426	MAAL_ERROR(sscop, 'G', 0);
3427	FREE_UU(uu_end);
3428	send_end(sscop, 1, NULL);
3429	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3430	SSCOP_MSG_FREE(msg);
3431	sscop_set_state(sscop, SSCOP_IDLE);
3432}
3433
3434/*
3435 * p 57: IN_REC_PEND && SD PDU
3436 *	arg is pdu (freed)
3437 */
3438static void
3439sscop_inrec_sd(struct sscop *sscop, struct sscop_msg *msg)
3440{
3441	MAAL_ERROR(sscop, 'A', 0);
3442	FREE_UU(uu_end);
3443	send_end(sscop, 1, NULL);
3444	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3445	SSCOP_MSG_FREE(msg);
3446	sscop_set_state(sscop, SSCOP_IDLE);
3447}
3448
3449/*
3450 * p 58: IN_REC_PEND && RSAK PDU
3451 *	arg is pdu (freed).
3452 */
3453static void
3454sscop_inrec_rsak(struct sscop *sscop, struct sscop_msg *msg)
3455{
3456	SSCOP_MSG_FREE(msg);
3457	MAAL_ERROR(sscop, 'K', 0);
3458}
3459
3460/*
3461 * p 58: IN_REC_PEND && RS PDU
3462 *	arg is pdu (freed).
3463 */
3464static void
3465sscop_inrec_rs(struct sscop *sscop, struct sscop_msg *msg)
3466{
3467	union pdu pdu;
3468
3469	pdu.sscop_null = MBUF_STRIP32(msg->m);
3470
3471	if(m_detect_retransmission(sscop, msg)) {
3472		SSCOP_MSG_FREE(msg);
3473		MAAL_ERROR(sscop, 'J', 0);
3474		return;
3475	}
3476	(void)MBUF_STRIP32(msg->m);
3477
3478	sscop->vt_ms = pdu.sscop_ns;
3479	AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0);
3480
3481	sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND);
3482}
3483
3484/*
3485 * p 59: IN_REC_PEND && ER PDU
3486 *	arg is pdu (freed)
3487 */
3488static void
3489sscop_inrec_er(struct sscop *sscop, struct sscop_msg *msg)
3490{
3491	union pdu pdu;
3492
3493	pdu.sscop_null = MBUF_STRIP32(msg->m);
3494
3495	if(!m_detect_retransmission(sscop, msg)) {
3496		MAAL_ERROR(sscop, 'L', 0);
3497	}
3498
3499	SSCOP_MSG_FREE(msg);
3500}
3501
3502/*
3503 * p 59: IN_REC_PEND && BGN PDU
3504 *	arg is pdu (freed).
3505 *	no uui
3506 */
3507static void
3508sscop_inrec_bgn(struct sscop *sscop, struct sscop_msg *msg)
3509{
3510	union pdu pdu;
3511
3512	pdu.sscop_null = MBUF_STRIP32(msg->m);
3513
3514	if(m_detect_retransmission(sscop, msg)) {
3515		MAAL_ERROR(sscop, 'B', 0);
3516		SSCOP_MSG_FREE(msg);
3517		return;
3518	}
3519	(void)MBUF_STRIP32(msg->m);
3520
3521	sscop->vt_ms = pdu.sscop_ns;
3522	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
3523	AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
3524
3525	sscop_set_state(sscop, SSCOP_IN_PEND);
3526}
3527
3528/*
3529 * p 59: IN_REC_PEND && BGAK PDU
3530 *	arg is pdu (freed)
3531 *	no uui
3532 */
3533static void
3534sscop_inrec_bgak(struct sscop *sscop, struct sscop_msg *msg)
3535{
3536	MAAL_ERROR(sscop, 'C', 0);
3537	SSCOP_MSG_FREE(msg);
3538}
3539
3540/*
3541 * p 59: IN_REC_PEND && ERAK PDU
3542 *	arg is pdu (freed)
3543 *	no uui
3544 */
3545static void
3546sscop_inrec_erak(struct sscop *sscop, struct sscop_msg *msg)
3547{
3548	MAAL_ERROR(sscop, 'M', 0);
3549	SSCOP_MSG_FREE(msg);
3550}
3551
3552/*
3553 * p 60: READY && RESYNC request
3554 *	arg is UU
3555 */
3556static void
3557sscop_ready_sync_req(struct sscop *sscop, struct sscop_msg *uu)
3558{
3559	SET_UU(uu_rs, uu);
3560
3561	m_reset_data_xfer_timers(sscop);
3562	sscop->vt_cc = 1;
3563	sscop->vt_sq++;
3564	m_initialize_mr(sscop);
3565	send_rs(sscop, 0, sscop->uu_rs);
3566	m_release_buffers(sscop);
3567	TIMER_RESTART(sscop, cc);
3568
3569	sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND);
3570}
3571
3572
3573/*
3574 * p 60: READY && AA-RELEASE.request
3575 *	arg is uu.
3576 */
3577static void
3578sscop_ready_release_req(struct sscop *sscop, struct sscop_msg *uu)
3579{
3580	SET_UU(uu_end, uu);
3581
3582	m_reset_data_xfer_timers(sscop);
3583	sscop->vt_cc = 1;
3584	send_end(sscop, 0, sscop->uu_end);
3585	m_prepare_retrieval(sscop);
3586	TIMER_RESTART(sscop, cc);
3587
3588	sscop_set_state(sscop, SSCOP_OUT_DIS_PEND);
3589}
3590
3591/*
3592 * p 61: READY && ER PDU
3593 *	arg is pdu (freed).
3594 */
3595static void
3596sscop_ready_er(struct sscop *sscop, struct sscop_msg *msg)
3597{
3598	union pdu pdu;
3599
3600	pdu.sscop_null = MBUF_STRIP32(msg->m);
3601
3602	if(m_detect_retransmission(sscop, msg)) {
3603		TIMER_RESTART(sscop, nr);
3604		send_erak(sscop);
3605	} else {
3606		m_reset_data_xfer_timers(sscop);
3607		sscop->vt_ms = pdu.sscop_ns;
3608		m_prepare_recovery(sscop);
3609		m_deliver_data(sscop);
3610
3611		AAL_SIG(sscop, SSCOP_RECOVER_indication);
3612
3613		sscop_set_state(sscop, SSCOP_IN_REC_PEND);
3614	}
3615
3616	SSCOP_MSG_FREE(msg);
3617}
3618
3619/*
3620 * p 61: READY && BGN PDU
3621 *	arg is pdu (freed)
3622 */
3623static void
3624sscop_ready_bgn(struct sscop *sscop, struct sscop_msg *msg)
3625{
3626	union pdu pdu;
3627
3628	pdu.sscop_null = MBUF_STRIP32(msg->m);
3629
3630	if(m_detect_retransmission(sscop, msg)) {
3631		TIMER_RESTART(sscop, nr);
3632		send_bgak(sscop, sscop->uu_bgak);
3633		SSCOP_MSG_FREE(msg);
3634		return;
3635	}
3636	(void)MBUF_STRIP32(msg->m);
3637
3638	m_reset_data_xfer_timers(sscop);
3639	sscop->vt_ms = pdu.sscop_ns;
3640
3641	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0);
3642	AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0);
3643
3644	m_prepare_retrieval(sscop);
3645
3646	sscop_set_state(sscop, SSCOP_IN_PEND);
3647}
3648
3649/*
3650 * p 62: READY && ENDAK PDU
3651 *	arg is pdu (freed)
3652 */
3653static void
3654sscop_ready_endak(struct sscop *sscop, struct sscop_msg *msg)
3655{
3656	m_reset_data_xfer_timers(sscop);
3657	MAAL_ERROR(sscop, 'F', 0);
3658	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3659	m_prepare_retrieval(sscop);
3660	SSCOP_MSG_FREE(msg);
3661	sscop_set_state(sscop, SSCOP_IDLE);
3662}
3663
3664/*
3665 * p 62: READY && BGREJ PDU
3666 *	arg is pdu (freed)
3667 */
3668static void
3669sscop_ready_bgrej(struct sscop *sscop, struct sscop_msg *msg)
3670{
3671	m_reset_data_xfer_timers(sscop);
3672	MAAL_ERROR(sscop, 'D', 0);
3673	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3674	m_prepare_retrieval(sscop);
3675	SSCOP_MSG_FREE(msg);
3676	sscop_set_state(sscop, SSCOP_IDLE);
3677}
3678
3679/*
3680 * p 62: READY && RS PDU
3681 *	arg is pdu (freed)
3682 */
3683static void
3684sscop_ready_rs(struct sscop *sscop, struct sscop_msg *msg)
3685{
3686	union pdu pdu;
3687
3688	pdu.sscop_null = MBUF_STRIP32(msg->m);
3689
3690	if(m_detect_retransmission(sscop, msg)) {
3691		SSCOP_MSG_FREE(msg);
3692		TIMER_RESTART(sscop, nr);
3693		send_rsak(sscop);
3694		return;
3695	}
3696	(void)MBUF_STRIP32(msg->m);
3697
3698	m_reset_data_xfer_timers(sscop);
3699	sscop->vt_ms = pdu.sscop_ns;
3700	AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0);
3701	m_prepare_retrieval(sscop);
3702
3703	sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND);
3704}
3705
3706/*
3707 * p 62: READY && END PDU
3708 *	arg is pdu (freed)
3709 */
3710static void
3711sscop_ready_end(struct sscop *sscop, struct sscop_msg *msg)
3712{
3713	union pdu pdu;
3714
3715	pdu.sscop_null = MBUF_STRIP32(msg->m);
3716	(void)MBUF_STRIP32(msg->m);
3717
3718	m_reset_data_xfer_timers(sscop);
3719	send_endak(sscop);
3720	AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication,
3721		msg, pdu.sscop_pl, (u_int)pdu.sscop_s);
3722	m_prepare_retrieval(sscop);
3723
3724	sscop_set_state(sscop, SSCOP_IDLE);
3725}
3726
3727/*
3728 * p 63: READY && POLL expiry
3729 */
3730static void
3731sscop_ready_tpoll(struct sscop *sscop, struct sscop_msg *unused __unused)
3732{
3733	sscop->vt_ps++;
3734	send_poll(sscop);
3735	sscop->vt_pd = 0;
3736	m_set_poll_timer(sscop);
3737}
3738
3739/*
3740 * p 63: READY && KEEP_ALIVE expiry
3741 */
3742static void
3743sscop_ready_tka(struct sscop *sscop, struct sscop_msg *unused __unused)
3744{
3745	sscop->vt_ps++;
3746	send_poll(sscop);
3747	sscop->vt_pd = 0;
3748	m_set_poll_timer(sscop);
3749}
3750
3751/*
3752 * p 63: READY && IDLE expiry
3753 */
3754static void
3755sscop_ready_tidle(struct sscop *sscop, struct sscop_msg *unused __unused)
3756{
3757	TIMER_RESTART(sscop, nr);
3758	sscop->vt_ps++;
3759	send_poll(sscop);
3760	sscop->vt_pd = 0;
3761	m_set_poll_timer(sscop);
3762}
3763
3764/*
3765 * p 63: READY && NO_RESPONSE expiry
3766 *	no arg
3767 */
3768static void
3769sscop_ready_nr(struct sscop *sscop, struct sscop_msg *unused __unused)
3770{
3771	m_reset_data_xfer_timers(sscop);
3772	MAAL_ERROR(sscop, 'P', 0);
3773	FREE_UU(uu_end);
3774	send_end(sscop, 1, NULL);
3775	AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1);
3776	m_prepare_retrieval(sscop);
3777	sscop_set_state(sscop, SSCOP_IDLE);
3778}
3779
3780/*
3781 * p 63: READY && AA-DATA.request
3782 *	arg is message (queued).
3783 */
3784static void
3785sscop_ready_userdata(struct sscop *sscop, struct sscop_msg *msg)
3786{
3787	MSGQ_APPEND(&sscop->xq, msg);
3788
3789	sscop_signal(sscop, SIG_PDU_Q, msg);
3790}
3791
3792/*
3793 * p 64: READY && SD PDU queued up
3794 *	arg is unused.
3795 */
3796static void
3797sscop_ready_pduq(struct sscop *sscop, struct sscop_msg *unused __unused)
3798{
3799	struct sscop_msg *msg;
3800
3801	if(sscop->rxq != 0) {
3802		TAILQ_FOREACH(msg, &sscop->xbuf, link)
3803			if(msg->rexmit)
3804				break;
3805		ASSERT(msg != NULL);
3806		msg->rexmit = 0;
3807		sscop->rxq--;
3808		send_sd(sscop, msg->m, msg->seqno);
3809		msg->poll_seqno = sscop->vt_ps;
3810		if(sscop->poll_after_rex && sscop->rxq == 0)
3811			goto poll;			/* -> A */
3812		else
3813			goto maybe_poll;		/* -> B */
3814
3815	}
3816	if(MSGQ_EMPTY(&sscop->xq))
3817		return;
3818
3819	if(sscop->vt_s >= sscop->vt_ms) {
3820		/* Send windows closed */
3821		TIMER_STOP(sscop, idle);
3822		TIMER_RESTART(sscop, nr);
3823		goto poll;			/* -> A */
3824
3825	} else {
3826		msg = MSGQ_GET(&sscop->xq);
3827		msg->seqno = sscop->vt_s;
3828		send_sd(sscop, msg->m, msg->seqno);
3829		msg->poll_seqno = sscop->vt_ps;
3830		sscop->vt_s++;
3831		MSGQ_APPEND(&sscop->xbuf, msg);
3832		goto maybe_poll;		/* -> B */
3833	}
3834
3835	/*
3836	 * p 65: Poll handling
3837	 */
3838  maybe_poll:					/* label B */
3839	sscop->vt_pd++;
3840	if(TIMER_ISACT(sscop, poll)) {
3841		if(sscop->vt_pd < sscop->maxpd)
3842			return;
3843	} else {
3844		 if(TIMER_ISACT(sscop, idle)) {
3845			TIMER_STOP(sscop, idle);
3846			TIMER_RESTART(sscop, nr);
3847		} else {
3848			TIMER_STOP(sscop, ka);
3849		}
3850		if(sscop->vt_pd < sscop->maxpd) {
3851			TIMER_RESTART(sscop, poll);
3852			return;
3853		}
3854	}
3855  poll:						/* label A */
3856	sscop->vt_ps++;
3857	send_poll(sscop);
3858	sscop->vt_pd = 0;
3859	TIMER_RESTART(sscop, poll);
3860}
3861
3862/*
3863 * p 67: common recovery start
3864 */
3865static void
3866sscop_recover(struct sscop *sscop)
3867{
3868	sscop->vt_cc = 1;
3869	sscop->vt_sq++;
3870
3871	m_initialize_mr(sscop);
3872	send_er(sscop);
3873	m_prepare_recovery(sscop);
3874
3875	TIMER_RESTART(sscop, cc);
3876
3877	sscop_set_state(sscop, SSCOP_OUT_REC_PEND);
3878}
3879
3880/*
3881 * p 66: READY && SD PDU
3882 *	arg is received message.
3883 */
3884static void
3885sscop_ready_sd(struct sscop *sscop, struct sscop_msg *msg)
3886{
3887	union pdu pdu;
3888	u_int sn;
3889
3890	pdu.sscop_null = MBUF_STRIP32(msg->m);
3891	msg->seqno = pdu.sscop_ns;
3892
3893	/* Fix padding */
3894	MBUF_UNPAD(msg->m, pdu.sscop_pl);
3895
3896	if(msg->seqno >= sscop->vr_mr) {
3897		/* message outside window */
3898		if(sscop->vr_h < sscop->vr_mr) {
3899			send_ustat(sscop, sscop->vr_h, sscop->vr_mr, -1);
3900			sscop->vr_h = sscop->vr_mr;
3901		}
3902		SSCOP_MSG_FREE(msg);
3903		return;
3904	}
3905
3906	if(msg->seqno == sscop->vr_r) {
3907		if(msg->seqno == sscop->vr_h) {
3908			sscop->vr_r = msg->seqno + 1;
3909			sscop->vr_h = msg->seqno + 1;
3910
3911			AAL_DATA(sscop, SSCOP_DATA_indication,
3912				msg->m, msg->seqno);
3913			msg->m = NULL;
3914			SSCOP_MSG_FREE(msg);
3915
3916			return;
3917		}
3918		for(;;) {
3919			AAL_DATA(sscop, SSCOP_DATA_indication,
3920				msg->m, msg->seqno);
3921			msg->m = NULL;
3922			SSCOP_MSG_FREE(msg);
3923
3924			sscop->vr_r++;
3925			if((msg = MSGQ_PEEK(&sscop->rbuf)) == NULL)
3926				break;
3927			sn = msg->seqno;
3928			ASSERT(sn >= sscop->vr_r);
3929			if(sn != sscop->vr_r)
3930				break;
3931			msg = MSGQ_GET(&sscop->rbuf);
3932		}
3933		return;
3934	}
3935
3936	/* Messages were lost */
3937
3938	/* XXX Flow control */
3939	if(msg->seqno == sscop->vr_h) {
3940		QINSERT(&sscop->rbuf, msg);
3941		sscop->vr_h++;
3942		return;
3943	}
3944	if(sscop->vr_h < msg->seqno) {
3945		QINSERT(&sscop->rbuf, msg);
3946		send_ustat(sscop, sscop->vr_h, msg->seqno, -1);
3947		sscop->vr_h = msg->seqno + 1;
3948		return;
3949	}
3950
3951	if(QFIND(&sscop->rbuf, msg->seqno) == NULL) {
3952		QINSERT(&sscop->rbuf, msg);
3953		return;
3954	}
3955
3956	/* error: start recovery */
3957	SSCOP_MSG_FREE(msg);
3958	m_reset_data_xfer_timers(sscop);
3959	MAAL_ERROR(sscop, 'Q', 0);
3960	sscop_recover(sscop);
3961}
3962
3963/*
3964 * p 67: READY && POLL PDU
3965 */
3966static void
3967sscop_ready_poll(struct sscop *sscop, struct sscop_msg *msg)
3968{
3969	union pdu pdu;
3970	union seqno seqno;
3971	u_int sn, nps;
3972	struct SSCOP_MBUF_T *m;
3973
3974	pdu.sscop_null = MBUF_STRIP32(msg->m);
3975	seqno.sscop_null = MBUF_STRIP32(msg->m);
3976
3977	if((u_int)pdu.sscop_ns < sscop->vr_h) {
3978		SSCOP_MSG_FREE(msg);
3979		m_reset_data_xfer_timers(sscop);
3980		MAAL_ERROR(sscop, 'Q', 0);
3981		sscop_recover(sscop);
3982		return;
3983	}
3984	nps = seqno.sscop_n;
3985
3986	if((u_int)pdu.sscop_ns > sscop->vr_mr)
3987		sscop->vr_h = sscop->vr_mr;
3988	else
3989		sscop->vr_h = pdu.sscop_ns;
3990
3991	SSCOP_MSG_FREE(msg);
3992
3993	/* build stat pdu */
3994	if((m = MBUF_ALLOC(sscop->maxstat * 4 + 12)) == NULL) {
3995		FAILURE("sscop: cannot allocate STAT");
3996		return;
3997	}
3998	sn = sscop->vr_r;
3999
4000	while(sn != sscop->vr_h) {
4001		/* loop through burst we already have */
4002		for(;;) {
4003			if(sn >= sscop->vr_h) {
4004				seqno.sscop_null = 0;
4005				seqno.sscop_n = sn;
4006				MBUF_APPEND32(m, seqno.sscop_null);
4007				goto out;
4008			}
4009			if(QFIND(&sscop->rbuf, sn) == NULL)
4010				break;
4011			sn++;
4012		}
4013
4014		/* start of a hole */
4015		seqno.sscop_null = 0;
4016		seqno.sscop_n = sn;
4017		MBUF_APPEND32(m, seqno.sscop_null);
4018		if(MBUF_LEN(m)/4 >= sscop->maxstat) {
4019			send_stat(sscop, nps, m);
4020			if((m = MBUF_ALLOC(sscop->maxstat * 4 + 12)) == NULL) {
4021				FAILURE("sscop: cannot allocate STAT");
4022				return;
4023			}
4024			seqno.sscop_null = 0;
4025			seqno.sscop_n = sn;
4026			MBUF_APPEND32(m, seqno.sscop_null);
4027		}
4028		do {
4029			sn++;
4030		} while(sn < sscop->vr_h && !QFIND(&sscop->rbuf, sn));
4031		seqno.sscop_null = 0;
4032		seqno.sscop_n = sn;
4033		MBUF_APPEND32(m, seqno.sscop_null);
4034	}
4035  out:
4036	send_stat(sscop, nps, m);
4037}
4038
4039/*
4040 * p 69: READY && USTAT PDU
4041 *	arg is msg (freed)
4042 */
4043static void
4044sscop_ready_ustat(struct sscop *sscop, struct sscop_msg *msg)
4045{
4046	union pdu pdu;
4047	union seqno nmr, sq1, sq2;
4048	u_int cnt;
4049
4050	pdu.sscop_null = MBUF_STRIP32(msg->m);
4051	nmr.sscop_null = MBUF_STRIP32(msg->m);
4052	sq2.sscop_null = MBUF_STRIP32(msg->m);
4053	sq1.sscop_null = MBUF_STRIP32(msg->m);
4054
4055	SSCOP_MSG_FREE(msg);
4056
4057	cnt = sq1.sscop_n - sq2.sscop_n;
4058
4059	if((u_int)pdu.sscop_ns < sscop->vt_a || (u_int)pdu.sscop_ns >= sscop->vt_s) {
4060		VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg,
4061		    "USTAT: N(R) outside VT(A)...VT(S)-1: N(R)=%u VT(A)=%u "
4062		    "VT(S)=%u", (u_int)pdu.sscop_ns, sscop->vt_a, sscop->vt_s));
4063		goto err_f;
4064	}
4065
4066	/* Acknowledge all messages between VT(A) and N(R)-1. N(R) is the new
4067	 * next in sequence-SD-number of the receiver and means, it has all
4068	 * messages below N(R). Remove all message below N(R) from the
4069	 * transmission buffer. It may already be removed because of an
4070	 * earlier selective ACK in a STAT message.
4071	 */
4072	while((msg = MSGQ_PEEK(&sscop->xbuf)) != NULL && msg->seqno < (u_int)pdu.sscop_ns) {
4073		ASSERT(msg->seqno >= sscop->vt_a);
4074		MSGQ_REMOVE(&sscop->xbuf, msg);
4075		SSCOP_MSG_FREE(msg);
4076	}
4077
4078	/* Update the in-sequence acknowledge and the send window */
4079	sscop->vt_a = pdu.sscop_ns;
4080	sscop->vt_ms = nmr.sscop_n;
4081
4082	/* check, that the range of requested re-transmissions is between
4083	 * the in-sequence-ack and the highest up-to-now transmitted SD
4084	 */
4085	if(sq1.sscop_n >= sq2.sscop_n
4086	    || (u_int)sq1.sscop_n < sscop->vt_a
4087	    || (u_int)sq2.sscop_n >= sscop->vt_s) {
4088		VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg,
4089		    "USTAT: seq1 or seq2 outside VT(A)...VT(S)-1 or seq1>=seq2:"
4090		    " seq1=%u seq2=%u VT(A)=%u VT(S)=%u",
4091		    sq1.sscop_n, sq2.sscop_n, sscop->vt_a, sscop->vt_s));
4092		goto err_f;
4093	}
4094
4095	/*
4096	 * Retransmit all messages from seq1 to seq2-1
4097	 */
4098	do {
4099		/*
4100		 * The message may not be in the transmit buffer if it was
4101		 * already acked by a STAT. This means, the receiver is
4102		 * confused.
4103		 */
4104		if((msg = QFIND(&sscop->xbuf, sq1.sscop_n)) == NULL) {
4105			VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg,
4106			    "USTAT: message %u not found in xmit buffer",
4107			    sq1.sscop_n));
4108			goto err_f;
4109		}
4110
4111		/*
4112		 * If it is not yet in the re-transmission queue, put it there
4113		 */
4114		if(!msg->rexmit) {
4115			msg->rexmit = 1;
4116			sscop->rxq++;
4117			sscop_signal(sscop, SIG_PDU_Q, msg);
4118		}
4119		sq1.sscop_n++;
4120	} while(sq1.sscop_n != sq2.sscop_n);
4121
4122	/*
4123	 * report the re-transmission to the management
4124	 */
4125	MAAL_ERROR(sscop, 'V', cnt);
4126	return;
4127
4128  err_f:
4129	m_reset_data_xfer_timers(sscop);
4130	MAAL_ERROR(sscop, 'T', 0);
4131	sscop_recover(sscop);
4132}
4133
4134/*
4135 * p 70: READY && STAT PDU
4136 *	arg is msg (freed).
4137 */
4138static void
4139sscop_ready_stat(struct sscop *sscop, struct sscop_msg *msg)
4140{
4141	union pdu pdu;
4142	union seqno nps, nmr;
4143	u_int len, seq1, seq2, cnt;
4144	struct sscop_msg *m;
4145
4146	pdu.sscop_null = MBUF_STRIP32(msg->m);
4147	nmr.sscop_null = MBUF_STRIP32(msg->m);
4148	nps.sscop_null = MBUF_STRIP32(msg->m);
4149
4150	len = MBUF_LEN(msg->m) / 4;
4151
4152	if((u_int)nps.sscop_n < sscop->vt_pa
4153	    || (u_int)nps.sscop_n > sscop->vt_ps) {
4154		SSCOP_MSG_FREE(msg);
4155		m_reset_data_xfer_timers(sscop);
4156		MAAL_ERROR(sscop, 'R', 0);
4157		sscop_recover(sscop);
4158		return;
4159	}
4160
4161	if((u_int)pdu.sscop_ns < sscop->vt_a
4162	    || (u_int)pdu.sscop_ns > sscop->vt_s) {
4163		/*
4164		 * The in-sequence acknowledge, i.e. the receivers's next
4165		 * expected in-sequence msg is outside the window between
4166		 * the transmitters in-sequence ack and highest seqno -
4167		 * the receiver seems to be confused.
4168		 */
4169		VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg,
4170		    "STAT: N(R) outside VT(A)...VT(S)-1: N(R)=%u VT(A)=%u "
4171		    "VT(S)=%u", (u_int)pdu.sscop_ns, sscop->vt_a, sscop->vt_s));
4172  err_H:
4173		SSCOP_MSG_FREE(msg);
4174		m_reset_data_xfer_timers(sscop);
4175		MAAL_ERROR(sscop, 'S', 0);
4176		sscop_recover(sscop);
4177		return;
4178	}
4179
4180	/* Acknowledge all messages between VT(A) and N(R)-1. N(R) is the new
4181	 * next in sequence-SD-number of the receiver and means, it has all
4182	 * messages below N(R). Remove all message below N(R) from the
4183	 * transmission buffer. It may already be removed because of an
4184	 * earlier selective ACK in a STAT message.
4185	 */
4186	while((m = MSGQ_PEEK(&sscop->xbuf)) != NULL
4187	    && m->seqno < (u_int)pdu.sscop_ns) {
4188		ASSERT(m->seqno >= sscop->vt_a);
4189		MSGQ_REMOVE(&sscop->xbuf, m);
4190		SSCOP_MSG_FREE(m);
4191	}
4192
4193	/*
4194	 * Update in-sequence ack, poll-ack and send window.
4195	 */
4196	sscop->vt_a = pdu.sscop_ns;
4197	sscop->vt_pa = nps.sscop_n;
4198	sscop->vt_ms = nmr.sscop_n;
4199
4200	cnt = 0;
4201	if(len > 1) {
4202		seq1 = MBUF_GET32(msg->m);
4203		len--;
4204		if(seq1 >= sscop->vt_s) {
4205			VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg,
4206			    "STAT: seq1 >= VT(S): seq1=%u VT(S)=%u",
4207			    seq1, sscop->vt_s));
4208			goto err_H;
4209		}
4210
4211		for(;;) {
4212			seq2 = MBUF_GET32(msg->m);
4213			len--;
4214			if(seq1 >= seq2 || seq2 > sscop->vt_s) {
4215				VERBERR(sscop, SSCOP_DBG_ERR, (sscop,
4216				    sscop->aarg, "STAT: seq1 >= seq2 or "
4217				    "seq2 > VT(S): seq1=%u seq2=%u VT(S)=%u",
4218				    seq1, seq2, sscop->vt_s));
4219				goto err_H;
4220			}
4221
4222			do {
4223				/*
4224				 * The receiver requests the re-transmission
4225				 * of some message, but has acknowledged it
4226				 * already in an earlier STAT (it isn't in the
4227				 * transmitt buffer anymore).
4228				 */
4229				if((m = QFIND(&sscop->xbuf, seq1)) == NULL) {
4230					VERBERR(sscop, SSCOP_DBG_ERR,
4231					    (sscop, sscop->aarg, "STAT: message"
4232					    " %u not found in xmit buffer",
4233					    seq1));
4234					goto err_H;
4235				}
4236				if(m->poll_seqno < (u_int)nps.sscop_n
4237				    && (u_int)nps.sscop_n <= sscop->vt_ps)
4238					if(!m->rexmit) {
4239						m->rexmit = 1;
4240						sscop->rxq++;
4241						cnt++;
4242						sscop_signal(sscop, SIG_PDU_Q, msg);
4243					}
4244			} while(++seq1 < seq2);
4245
4246			if(len == 0)
4247				break;
4248
4249			seq2 = MBUF_GET32(msg->m);
4250			len--;
4251
4252			if(seq1 >= seq2 || seq2 > sscop->vt_s) {
4253				VERBERR(sscop, SSCOP_DBG_ERR, (sscop,
4254				    sscop->aarg, "STAT: seq1 >= seq2 or "
4255				    "seq2 > VT(S): seq1=%u seq2=%u VT(S)=%u",
4256				    seq1, seq2, sscop->vt_s));
4257				goto err_H;
4258			}
4259
4260			/* OK now the sucessful transmitted messages. Note, that
4261			 * some messages may already be out of the buffer because
4262			 * of earlier STATS */
4263			do {
4264				if(sscop->clear_buffers) {
4265					if((m = QFIND(&sscop->xbuf, seq1)) != NULL) {
4266						MSGQ_REMOVE(&sscop->xbuf, m);
4267						SSCOP_MSG_FREE(m);
4268					}
4269				}
4270			} while(++seq1 != seq2);
4271
4272			if(len == 0)
4273				break;
4274		}
4275		MAAL_ERROR(sscop, 'V', cnt);
4276	}
4277	SSCOP_MSG_FREE(msg);
4278
4279	/* label L: */
4280	if(sscop->vt_s >= sscop->vt_ms) {
4281		/*
4282		 * The receiver has closed the window: report to management
4283		 */
4284		if(sscop->credit) {
4285			sscop->credit = 0;
4286			MAAL_ERROR(sscop, 'W', 0);
4287		}
4288	} else if(!sscop->credit) {
4289		/*
4290		 * The window was forcefully closed above, but
4291		 * now re-opened. Report to management.
4292		 */
4293		sscop->credit = 1;
4294		MAAL_ERROR(sscop, 'X', 0);
4295	}
4296
4297	if(TIMER_ISACT(sscop, poll)) {
4298		TIMER_RESTART(sscop, nr);
4299	} else if(!TIMER_ISACT(sscop, idle)) {
4300		TIMER_STOP(sscop, ka);
4301		TIMER_STOP(sscop, nr);
4302		TIMER_RESTART(sscop, idle);
4303	}
4304}
4305
4306/*
4307 * P. 73: any state & UDATA_REQUEST
4308 *	arg is pdu (queued)
4309 */
4310static void
4311sscop_udata_req(struct sscop *sscop, struct sscop_msg *msg)
4312{
4313	MSGQ_APPEND(&sscop->uxq, msg);
4314	sscop_signal(sscop, SIG_UPDU_Q, msg);
4315}
4316
4317/*
4318 * P. 73: any state & MDATA_REQUEST
4319 *	arg is pdu (queued)
4320 */
4321static void
4322sscop_mdata_req(struct sscop *sscop, struct sscop_msg *msg)
4323{
4324	MSGQ_APPEND(&sscop->mxq, msg);
4325	sscop_signal(sscop, SIG_MPDU_Q, msg);
4326}
4327
4328/*
4329 * P. 74: any state & UDATA queued
4330 *	no arg.
4331 */
4332static void
4333sscop_upduq(struct sscop *sscop, struct sscop_msg *unused __unused)
4334{
4335	struct sscop_msg *msg;
4336
4337	if(sscop->ll_busy)
4338		return;
4339	while((msg = MSGQ_GET(&sscop->uxq)) != NULL) {
4340		send_ud(sscop, msg->m);
4341		msg->m = NULL;
4342		SSCOP_MSG_FREE(msg);
4343	}
4344}
4345
4346/*
4347 * P. 74: any state & MDATA queued
4348 *	no arg.
4349 */
4350static void
4351sscop_mpduq(struct sscop *sscop, struct sscop_msg *unused __unused)
4352{
4353	struct sscop_msg *msg;
4354
4355	if(sscop->ll_busy)
4356		return;
4357	while((msg = MSGQ_GET(&sscop->mxq)) != NULL) {
4358		send_md(sscop, msg->m);
4359		msg->m = NULL;
4360		SSCOP_MSG_FREE(msg);
4361	}
4362}
4363
4364/*
4365 * p 73: MD PDU
4366 *	arg is PDU
4367 */
4368static void
4369sscop_md(struct sscop *sscop, struct sscop_msg *msg)
4370{
4371	union pdu pdu;
4372
4373	pdu.sscop_null = MBUF_STRIP32(msg->m);
4374
4375	MBUF_UNPAD(msg->m, pdu.sscop_pl);
4376
4377	MAAL_DATA(sscop, msg->m);
4378	msg->m = NULL;
4379	SSCOP_MSG_FREE(msg);
4380}
4381
4382/*
4383 * p 73: UD PDU
4384 *	arg is PDU
4385 */
4386static void
4387sscop_ud(struct sscop *sscop, struct sscop_msg *msg)
4388{
4389	union pdu pdu;
4390
4391	pdu.sscop_null = MBUF_STRIP32(msg->m);
4392
4393	MBUF_UNPAD(msg->m, pdu.sscop_pl);
4394
4395	AAL_DATA(sscop, SSCOP_UDATA_indication, msg->m, 0);
4396	msg->m = NULL;
4397	SSCOP_MSG_FREE(msg);
4398}
4399
4400
4401/*
4402 * p 33: IDLE & RETRIEVE
4403 * p 39: IN_PEND & RETRIEVE
4404 * p 42: OUT_DIS_PEND & RETRIEVE
4405 * p 48: IN_RESYNC_PEND & RETRIEVE
4406 * p 53: REC_PEND & RETRIEVE
4407 * p 58: IN_REC_PEND & RETRIEVE
4408 */
4409static void
4410sscop_retrieve(struct sscop *sscop, struct sscop_msg *msg)
4411{
4412	m_data_retrieval(sscop, msg->rexmit);
4413	SSCOP_MSG_FREE(msg);
4414}
4415
4416/************************************************************/
4417/*
4418 * GENERAL EVENT HANDLING
4419 */
4420
4421/*
4422 * State/event matrix.
4423 *
4424 * Entries marked with Z are not specified in Q.2110, but are added for
4425 * the sake of stability.
4426 */
4427static struct {
4428	void	(*func)(struct sscop *, struct sscop_msg *);
4429	int	(*cond)(struct sscop *);
4430} state_matrix[SSCOP_NSTATES][SIG_NUM] = {
4431	/* SSCOP_IDLE */ {
4432		/* SIG_BGN */		{ sscop_idle_bgn, NULL },
4433		/* SIG_BGAK */		{ sscop_idle_bgak, NULL },
4434		/* SIG_END */		{ sscop_idle_end, NULL },
4435		/* SIG_ENDAK */		{ sscop_ignore_pdu, NULL },
4436		/* SIG_RS */		{ sscop_idle_rs, NULL },
4437		/* SIG_RSAK */		{ sscop_idle_rsak, NULL },
4438		/* SIG_BGREJ */		{ sscop_idle_bgrej, NULL },
4439		/* SIG_SD */		{ sscop_idle_sd, NULL },
4440		/* SIG_ER */		{ sscop_idle_er, NULL },
4441		/* SIG_POLL */		{ sscop_idle_poll, NULL },
4442		/* SIG_STAT */		{ sscop_idle_stat, NULL },
4443		/* SIG_USTAT */		{ sscop_idle_ustat, NULL },
4444		/* SIG_UD */		{ sscop_ud, NULL },
4445		/* SIG_MD */		{ sscop_md, NULL },
4446		/* SIG_ERAK */		{ sscop_idle_erak, NULL },
4447		/* SIG_T_CC */		{ NULL, NULL },
4448		/* SIG_T_POLL */	{ NULL, NULL },
4449		/* SIG_T_KA */		{ NULL, NULL },
4450		/* SIG_T_NR */		{ NULL, NULL },
4451		/* SIG_T_IDLE */	{ NULL, NULL },
4452		/* SIG_PDU_Q */		{ sscop_flush_pduq, NULL },
4453		/* SIG_USER_DATA */	{ NULL, NULL },
4454		/* SIG_ESTAB_REQ */	{ sscop_idle_establish_req, NULL },
4455		/* SIG_ESTAB_RESP */	{ NULL, NULL },
4456		/* SIG_RELEASE_REQ */	{ NULL, NULL },
4457		/* SIG_RECOVER */	{ NULL, NULL },
4458		/* SIG_SYNC_REQ */	{ NULL, NULL },
4459		/* SIG_SYNC_RESP */	{ NULL, NULL },
4460		/* SIG_UDATA */		{ sscop_udata_req, NULL },
4461		/* SIG_MDATA */		{ sscop_mdata_req, NULL },
4462		/* SIG_UPDU_Q */	{ sscop_upduq, NULL },
4463		/* SIG_MPDU_Q */	{ sscop_mpduq, NULL },
4464		/* SIG_RETRIEVE */	{ sscop_retrieve, NULL },
4465	},
4466	/* SSCOP_OUT_PEND */ {
4467		/* SIG_BGN */		{ sscop_outpend_bgn, NULL },
4468		/* SIG_BGAK */		{ sscop_outpend_bgak, NULL },
4469		/* SIG_END */		{ sscop_ignore_pdu, NULL },
4470		/* SIG_ENDAK */		{ sscop_ignore_pdu, NULL },
4471		/* SIG_RS */		{ sscop_ignore_pdu, NULL },
4472		/* SIG_RSAK */		{ sscop_ignore_pdu, NULL },
4473		/* SIG_BGREJ */		{ sscop_outpend_bgrej, NULL },
4474		/* SIG_SD */		{ sscop_ignore_pdu, NULL },
4475		/* SIG_ER */		{ sscop_ignore_pdu, NULL },
4476		/* SIG_POLL */		{ sscop_ignore_pdu, NULL },
4477		/* SIG_STAT */		{ sscop_ignore_pdu, NULL },
4478		/* SIG_USTAT */		{ sscop_ignore_pdu, NULL },
4479		/* SIG_UD */		{ sscop_ud, NULL },
4480		/* SIG_MD */		{ sscop_md, NULL },
4481		/* SIG_ERAK */		{ sscop_ignore_pdu, NULL },
4482		/* SIG_T_CC */		{ sscop_outpend_tcc, NULL },
4483		/* SIG_T_POLL */	{ NULL, NULL },
4484		/* SIG_T_KA */		{ NULL, NULL },
4485		/* SIG_T_NR */		{ NULL, NULL },
4486		/* SIG_T_IDLE */	{ NULL, NULL },
4487		/* SIG_PDU_Q */		{ sscop_flush_pduq, NULL },
4488		/* SIG_USER_DATA */	{ NULL, NULL },
4489		/* SIG_ESTAB_REQ */	{ NULL, NULL },
4490		/* SIG_ESTAB_RESP */	{ NULL, NULL },
4491		/* SIG_RELEASE_REQ */	{ sscop_outpend_release_req, NULL },
4492		/* SIG_RECOVER */	{ NULL, NULL },
4493		/* SIG_SYNC_REQ */	{ NULL, NULL },
4494		/* SIG_SYNC_RESP */	{ NULL, NULL },
4495		/* SIG_UDATA */		{ sscop_udata_req, NULL },
4496		/* SIG_MDATA */		{ sscop_mdata_req, NULL },
4497		/* SIG_UPDU_Q */	{ sscop_upduq, NULL },
4498		/* SIG_MPDU_Q */	{ sscop_mpduq, NULL },
4499		/* SIG_RETRIEVE */	{ NULL, NULL },
4500	},
4501	/* SSCOP_IN_PEND */ {
4502		/* SIG_BGN */		{ sscop_inpend_bgn, NULL },
4503		/* SIG_BGAK */		{ sscop_inpend_bgak, NULL },
4504		/* SIG_END */		{ sscop_inpend_end, NULL },
4505		/* SIG_ENDAK */		{ sscop_inpend_endak, NULL },
4506		/* SIG_RS */		{ sscop_inpend_rs, NULL },
4507		/* SIG_RSAK */		{ sscop_inpend_rsak, NULL },
4508		/* SIG_BGREJ */		{ sscop_inpend_bgrej, NULL },
4509		/* SIG_SD */		{ sscop_inpend_sd, NULL },
4510		/* SIG_ER */		{ sscop_inpend_er, NULL },
4511		/* SIG_POLL */		{ sscop_inpend_poll, NULL },
4512		/* SIG_STAT */		{ sscop_inpend_stat, NULL },
4513		/* SIG_USTAT */		{ sscop_inpend_ustat, NULL },
4514		/* SIG_UD */		{ sscop_ud, NULL },
4515		/* SIG_MD */		{ sscop_md, NULL },
4516		/* SIG_ERAK */		{ sscop_inpend_erak, NULL },
4517		/* SIG_T_CC */		{ NULL, NULL },
4518		/* SIG_T_POLL */	{ NULL, NULL },
4519		/* SIG_T_KA */		{ NULL, NULL },
4520		/* SIG_T_NR */		{ NULL, NULL },
4521		/* SIG_T_IDLE */	{ NULL, NULL },
4522		/* SIG_PDU_Q */		{ sscop_flush_pduq, NULL },
4523		/* SIG_USER_DATA */	{ NULL, NULL },
4524		/* SIG_ESTAB_REQ */	{ NULL, NULL },
4525		/* SIG_ESTAB_RESP */	{ sscop_inpend_establish_resp, NULL },
4526		/* SIG_RELEASE_REQ */	{ sscop_inpend_release_req, NULL },
4527		/* SIG_RECOVER */	{ NULL, NULL },
4528		/* SIG_SYNC_REQ */	{ NULL, NULL },
4529		/* SIG_SYNC_RESP */	{ NULL, NULL },
4530		/* SIG_UDATA */		{ sscop_udata_req, NULL },
4531		/* SIG_MDATA */		{ sscop_mdata_req, NULL },
4532		/* SIG_UPDU_Q */	{ sscop_upduq, NULL },
4533		/* SIG_MPDU_Q */	{ sscop_mpduq, NULL },
4534		/* SIG_RETRIEVE */	{ sscop_retrieve, NULL },
4535	},
4536	/* SSCOP_OUT_DIS_PEND */ {
4537		/* SIG_BGN */		{ sscop_outdis_bgn, NULL },
4538		/* SIG_BGAK */		{ sscop_ignore_pdu, NULL },
4539		/* SIG_END */		{ sscop_outdis_end, NULL },
4540		/* SIG_ENDAK */		{ sscop_outdis_endak, NULL },
4541		/* SIG_RS */		{ sscop_ignore_pdu, NULL },
4542		/* SIG_RSAK */		{ sscop_ignore_pdu, NULL },
4543		/* SIG_BGREJ */		{ sscop_outdis_endak, NULL },
4544		/* SIG_SD */		{ sscop_ignore_pdu, NULL },
4545		/* SIG_ER */		{ sscop_ignore_pdu, NULL },
4546		/* SIG_POLL */		{ sscop_ignore_pdu, NULL },
4547		/* SIG_STAT */		{ sscop_ignore_pdu, NULL },
4548		/* SIG_USTAT */		{ sscop_ignore_pdu, NULL },
4549		/* SIG_UD */		{ sscop_ud, NULL },
4550		/* SIG_MD */		{ sscop_md, NULL },
4551		/* SIG_ERAK */		{ sscop_ignore_pdu, NULL },
4552		/* SIG_T_CC */		{ sscop_outdis_cc, NULL },
4553		/* SIG_T_POLL */	{ NULL, NULL },
4554		/* SIG_T_KA */		{ NULL, NULL },
4555		/* SIG_T_NR */		{ NULL, NULL },
4556		/* SIG_T_IDLE */	{ NULL, NULL },
4557		/* SIG_PDU_Q */		{ sscop_flush_pduq, NULL },
4558		/* SIG_USER_DATA */	{ NULL, NULL },
4559		/* SIG_ESTAB_REQ */	{ sscop_outdis_establish_req, NULL },
4560		/* SIG_ESTAB_RESP */	{ NULL, NULL },
4561		/* SIG_RELEASE_REQ */	{ NULL, NULL },
4562		/* SIG_RECOVER */	{ NULL, NULL },
4563		/* SIG_SYNC_REQ */	{ NULL, NULL },
4564		/* SIG_SYNC_RESP */	{ NULL, NULL },
4565		/* SIG_UDATA */		{ sscop_udata_req, NULL },
4566		/* SIG_MDATA */		{ sscop_mdata_req, NULL },
4567		/* SIG_UPDU_Q */	{ sscop_upduq, NULL },
4568		/* SIG_MPDU_Q */	{ sscop_mpduq, NULL },
4569		/* SIG_RETRIEVE */	{ sscop_retrieve, NULL },
4570	},
4571	/* SSCOP_OUT_RESYNC_PEND */ {
4572		/* SIG_BGN */		{ sscop_outsync_bgn, NULL },
4573		/* SIG_BGAK */		{ sscop_ignore_pdu, NULL },
4574		/* SIG_END */		{ sscop_outsync_end, NULL },
4575		/* SIG_ENDAK */		{ sscop_outsync_endak, NULL },
4576		/* SIG_RS */		{ sscop_outsync_rs, NULL },
4577		/* SIG_RSAK */		{ sscop_outsync_rsak, NULL },
4578		/* SIG_BGREJ */		{ sscop_outsync_bgrej, NULL },
4579		/* SIG_SD */		{ sscop_ignore_pdu, NULL },
4580		/* SIG_ER */		{ sscop_ignore_pdu, NULL },
4581		/* SIG_POLL */		{ sscop_ignore_pdu, NULL },
4582		/* SIG_STAT */		{ sscop_ignore_pdu, NULL },
4583		/* SIG_USTAT */		{ sscop_ignore_pdu, NULL },
4584		/* SIG_UD */		{ sscop_ud, NULL },
4585		/* SIG_MD */		{ sscop_md, NULL },
4586		/* SIG_ERAK */		{ sscop_ignore_pdu, NULL },
4587		/* SIG_T_CC */		{ sscop_outsync_cc, NULL },
4588		/* SIG_T_POLL */	{ NULL, NULL },
4589		/* SIG_T_KA */		{ NULL, NULL },
4590		/* SIG_T_NR */		{ NULL, NULL },
4591		/* SIG_T_IDLE */	{ NULL, NULL },
4592		/* SIG_PDU_Q */		{ sscop_flush_pduq, NULL },
4593		/* SIG_USER_DATA */	{ NULL, NULL },
4594		/* SIG_ESTAB_REQ */	{ NULL, NULL },
4595		/* SIG_ESTAB_RESP */	{ NULL, NULL },
4596		/* SIG_RELEASE_REQ */	{ sscop_outsync_release_req, NULL },
4597		/* SIG_RECOVER */	{ NULL, NULL },
4598		/* SIG_SYNC_REQ */	{ NULL, NULL },
4599		/* SIG_SYNC_RESP */	{ NULL, NULL },
4600		/* SIG_UDATA */		{ sscop_udata_req, NULL },
4601		/* SIG_MDATA */		{ sscop_mdata_req, NULL },
4602		/* SIG_UPDU_Q */	{ sscop_upduq, NULL },
4603		/* SIG_MPDU_Q */	{ sscop_mpduq, NULL },
4604		/* SIG_RETRIEVE */	{ NULL, NULL },
4605	},
4606	/* SSCOP_IN_RESYNC_PEND */ {
4607		/* SIG_BGN */		{ sscop_insync_bgn, NULL },
4608		/* SIG_BGAK */		{ sscop_insync_bgak, NULL },
4609		/* SIG_END */		{ sscop_insync_end, NULL },
4610		/* SIG_ENDAK */		{ sscop_insync_endak, NULL },
4611		/* SIG_RS */		{ sscop_insync_rs, NULL },
4612		/* SIG_RSAK */		{ sscop_insync_rsak, NULL },
4613		/* SIG_BGREJ */		{ sscop_insync_bgrej, NULL },
4614		/* SIG_SD */		{ sscop_insync_sd, NULL },
4615		/* SIG_ER */		{ sscop_insync_er, NULL },
4616		/* SIG_POLL */		{ sscop_insync_poll, NULL },
4617		/* SIG_STAT */		{ sscop_insync_stat, NULL },
4618		/* SIG_USTAT */		{ sscop_insync_ustat, NULL },
4619		/* SIG_UD */		{ sscop_ud, NULL },
4620		/* SIG_MD */		{ sscop_md, NULL },
4621		/* SIG_ERAK */		{ sscop_insync_erak, NULL },
4622		/* SIG_T_CC */		{ NULL, NULL },
4623		/* SIG_T_POLL */	{ NULL, NULL },
4624		/* SIG_T_KA */		{ NULL, NULL },
4625		/* SIG_T_NR */		{ NULL, NULL },
4626		/* SIG_T_IDLE */	{ NULL, NULL },
4627		/* SIG_PDU_Q */		{ sscop_flush_pduq, NULL },
4628		/* SIG_USER_DATA */	{ NULL, NULL },
4629		/* SIG_ESTAB_REQ */	{ NULL, NULL },
4630		/* SIG_ESTAB_RESP */	{ NULL, NULL },
4631		/* SIG_RELEASE_REQ */	{ sscop_insync_release_req, NULL },
4632		/* SIG_RECOVER */	{ NULL, NULL },
4633		/* SIG_SYNC_REQ */	{ NULL, NULL },
4634		/* SIG_SYNC_RESP */	{ sscop_insync_sync_resp, NULL },
4635		/* SIG_UDATA */		{ sscop_udata_req, NULL },
4636		/* SIG_MDATA */		{ sscop_mdata_req, NULL },
4637		/* SIG_UPDU_Q */	{ sscop_upduq, NULL },
4638		/* SIG_MPDU_Q */	{ sscop_mpduq, NULL },
4639		/* SIG_RETRIEVE */	{ sscop_retrieve, NULL },
4640	},
4641	/* SSCOP_OUT_REC_PEND */ {
4642		/* SIG_BGN */		{ sscop_outrec_bgn, NULL },
4643		/* SIG_BGAK */		{ sscop_outrec_bgak, NULL },
4644		/* SIG_END */		{ sscop_outrec_end, NULL },
4645		/* SIG_ENDAK */		{ sscop_outrec_endak, NULL },
4646		/* SIG_RS */		{ sscop_outrec_rs, NULL },
4647		/* SIG_RSAK */		{ sscop_outrec_rsak, NULL },
4648		/* SIG_BGREJ */		{ sscop_outrec_bgrej, NULL },
4649		/* SIG_SD */		{ sscop_ignore_pdu, NULL },
4650		/* SIG_ER */		{ sscop_outrec_er, NULL },
4651		/* SIG_POLL */		{ sscop_ignore_pdu, NULL },
4652		/* SIG_STAT */		{ sscop_ignore_pdu, NULL },
4653		/* SIG_USTAT */		{ sscop_ignore_pdu, NULL },
4654		/* SIG_UD */		{ sscop_ud, NULL },
4655		/* SIG_MD */		{ sscop_md, NULL },
4656		/* SIG_ERAK */		{ sscop_outrec_erak, NULL },
4657		/* SIG_T_CC */		{ sscop_outrec_cc, NULL },
4658		/* SIG_T_POLL */	{ NULL, NULL },
4659		/* SIG_T_KA */		{ NULL, NULL },
4660		/* SIG_T_NR */		{ NULL, NULL },
4661		/* SIG_T_IDLE */	{ NULL, NULL },
4662		/* SIG_PDU_Q */		{ sscop_outrec_pduq, NULL },
4663		/* SIG_USER_DATA */	{ sscop_outrec_userdata, NULL },
4664		/* SIG_ESTAB_REQ */	{ NULL, NULL },
4665		/* SIG_ESTAB_RESP */	{ NULL, NULL },
4666		/* SIG_RELEASE_REQ */	{ sscop_outrec_release_req, NULL },
4667		/* SIG_RECOVER */	{ NULL, NULL },
4668		/* SIG_SYNC_REQ */	{ sscop_outrec_sync_req, NULL },
4669		/* SIG_SYNC_RESP */	{ NULL, NULL },
4670		/* SIG_UDATA */		{ sscop_udata_req, NULL },
4671		/* SIG_MDATA */		{ sscop_mdata_req, NULL },
4672		/* SIG_UPDU_Q */	{ sscop_upduq, NULL },
4673		/* SIG_MPDU_Q */	{ sscop_mpduq, NULL },
4674		/* SIG_RETRIEVE */	{ NULL, NULL },
4675	},
4676	/* SSCOP_REC_PEND */ {
4677		/* SIG_BGN */		{ sscop_rec_bgn, NULL },
4678		/* SIG_BGAK */		{ sscop_rec_bgak, NULL },
4679		/* SIG_END */		{ sscop_rec_end, NULL },
4680		/* SIG_ENDAK */		{ sscop_rec_endak, NULL },
4681		/* SIG_RS */		{ sscop_rec_rs, NULL },
4682		/* SIG_RSAK */		{ sscop_rec_rsak, NULL },
4683		/* SIG_BGREJ */		{ sscop_rec_bgrej, NULL },
4684		/* SIG_SD */		{ sscop_ignore_pdu, NULL },
4685		/* SIG_ER */		{ sscop_rec_er, NULL },
4686		/* SIG_POLL */		{ sscop_ignore_pdu, NULL },
4687		/* SIG_STAT */		{ sscop_rec_stat, NULL },
4688		/* SIG_USTAT */		{ sscop_rec_ustat, NULL },
4689		/* SIG_UD */		{ sscop_ud, NULL },
4690		/* SIG_MD */		{ sscop_md, NULL },
4691		/* SIG_ERAK */		{ sscop_ignore_pdu, NULL },
4692		/* SIG_T_CC */		{ NULL, NULL },
4693		/* SIG_T_POLL */	{ NULL, NULL },
4694		/* SIG_T_KA */		{ NULL, NULL },
4695		/* SIG_T_NR */		{ NULL, NULL },
4696		/* SIG_T_IDLE */	{ NULL, NULL },
4697		/* SIG_PDU_Q */		{ sscop_rec_pduq, NULL },
4698		/* SIG_USER_DATA */	{ NULL, NULL },
4699		/* SIG_ESTAB_REQ */	{ NULL, NULL },
4700		/* SIG_ESTAB_RESP */	{ NULL, NULL },
4701		/* SIG_RELEASE_REQ */	{ sscop_rec_release_req, NULL },
4702		/* SIG_RECOVER */	{ sscop_rec_recover, NULL },
4703		/* SIG_SYNC_REQ */	{ sscop_rec_sync_req, NULL },
4704		/* SIG_SYNC_RESP */	{ NULL, NULL },
4705		/* SIG_UDATA */		{ sscop_udata_req, NULL },
4706		/* SIG_MDATA */		{ sscop_mdata_req, NULL },
4707		/* SIG_UPDU_Q */	{ sscop_upduq, NULL },
4708		/* SIG_MPDU_Q */	{ sscop_mpduq, NULL },
4709		/* SIG_RETRIEVE */	{ sscop_retrieve, NULL },
4710	},
4711	/* SSCOP_IN_REC_PEND */ {
4712		/* SIG_BGN */		{ sscop_inrec_bgn, NULL },
4713		/* SIG_BGAK */		{ sscop_inrec_bgak, NULL },
4714		/* SIG_END */		{ sscop_inrec_end, NULL },
4715		/* SIG_ENDAK */		{ sscop_inrec_endak, NULL },
4716		/* SIG_RS */		{ sscop_inrec_rs, NULL },
4717		/* SIG_RSAK */		{ sscop_inrec_rsak, NULL },
4718		/* SIG_BGREJ */		{ sscop_inrec_bgrej, NULL },
4719		/* SIG_SD */		{ sscop_inrec_sd, NULL },
4720		/* SIG_ER */		{ sscop_inrec_er, NULL },
4721		/* SIG_POLL */		{ sscop_inrec_poll, NULL },
4722		/* SIG_STAT */		{ sscop_inrec_stat, NULL },
4723		/* SIG_USTAT */		{ sscop_inrec_ustat, NULL },
4724		/* SIG_UD */		{ sscop_ud, NULL },
4725		/* SIG_MD */		{ sscop_md, NULL },
4726		/* SIG_ERAK */		{ sscop_inrec_erak, NULL },
4727		/* SIG_T_CC */		{ NULL, NULL },
4728		/* SIG_T_POLL */	{ NULL, NULL },
4729		/* SIG_T_KA */		{ NULL, NULL },
4730		/* SIG_T_NR */		{ NULL, NULL },
4731		/* SIG_T_IDLE */	{ NULL, NULL },
4732		/* SIG_PDU_Q */		{ sscop_inrec_pduq, NULL },
4733		/* SIG_USER_DATA */	{ NULL, NULL },
4734		/* SIG_ESTAB_REQ */	{ NULL, NULL },
4735		/* SIG_ESTAB_RESP */	{ NULL, NULL },
4736		/* SIG_RELEASE_REQ */	{ sscop_inrec_release_req, NULL },
4737		/* SIG_RECOVER */	{ sscop_inrec_recover, NULL },
4738		/* SIG_SYNC_REQ */	{ sscop_inrec_sync_req, NULL },
4739		/* SIG_SYNC_RESP */	{ NULL, NULL },
4740		/* SIG_UDATA */		{ sscop_udata_req, NULL },
4741		/* SIG_MDATA */		{ sscop_mdata_req, NULL },
4742		/* SIG_UPDU_Q */	{ sscop_upduq, NULL },
4743		/* SIG_MPDU_Q */	{ sscop_mpduq, NULL },
4744		/* SIG_RETRIEVE */	{ sscop_retrieve, NULL },
4745	},
4746	/* SSCOP_READY */ {
4747		/* SIG_BGN */		{ sscop_ready_bgn, NULL },
4748		/* SIG_BGAK */		{ sscop_ignore_pdu, NULL },
4749		/* SIG_END */		{ sscop_ready_end, NULL },
4750		/* SIG_ENDAK */		{ sscop_ready_endak, NULL },
4751		/* SIG_RS */		{ sscop_ready_rs, NULL },
4752		/* SIG_RSAK */		{ sscop_ignore_pdu, NULL },
4753		/* SIG_BGREJ */		{ sscop_ready_bgrej, NULL },
4754		/* SIG_SD */		{ sscop_ready_sd, NULL },
4755		/* SIG_ER */		{ sscop_ready_er, NULL },
4756		/* SIG_POLL */		{ sscop_ready_poll, NULL },
4757		/* SIG_STAT */		{ sscop_ready_stat, NULL },
4758		/* SIG_USTAT */		{ sscop_ready_ustat, NULL },
4759		/* SIG_UD */		{ sscop_ud, NULL },
4760		/* SIG_MD */		{ sscop_md, NULL },
4761		/* SIG_ERAK */		{ sscop_ignore_pdu, NULL },
4762		/* SIG_T_CC */		{ NULL, NULL },
4763		/* SIG_T_POLL */	{ sscop_ready_tpoll, NULL },
4764		/* SIG_T_KA */		{ sscop_ready_tka, NULL },
4765		/* SIG_T_NR */		{ sscop_ready_nr, NULL },
4766		/* SIG_T_IDLE */	{ sscop_ready_tidle, NULL },
4767		/* SIG_PDU_Q */		{ sscop_ready_pduq, c_ready_pduq },
4768		/* SIG_USER_DATA */	{ sscop_ready_userdata, NULL },
4769		/* SIG_ESTAB_REQ */	{ NULL, NULL },
4770		/* SIG_ESTAB_RESP */	{ NULL, NULL },
4771		/* SIG_RELEASE_REQ */	{ sscop_ready_release_req, NULL },
4772		/* SIG_RECOVER */	{ NULL, NULL },
4773		/* SIG_SYNC_REQ */	{ sscop_ready_sync_req, NULL },
4774		/* SIG_SYNC_RESP */	{ NULL, NULL },
4775		/* SIG_UDATA */		{ sscop_udata_req, NULL },
4776		/* SIG_MDATA */		{ sscop_mdata_req, NULL },
4777		/* SIG_UPDU_Q */	{ sscop_upduq, NULL },
4778		/* SIG_MPDU_Q */	{ sscop_mpduq, NULL },
4779		/* SIG_RETRIEVE */	{ NULL, NULL },
4780	}
4781};
4782
4783/*
4784 * Try to execute a signal. It is executed if
4785 *   - it is illegal (in this case it is effectively ignored)
4786 *   - it has no condition
4787 *   - its condition is true
4788 * If it has a condition and that is false, the function does nothing and
4789 * returns 0.
4790 * If the signal gets executed, the signal function is responsible to release
4791 * the message (if any).
4792 */
4793static int
4794sig_exec(struct sscop *sscop, u_int sig, struct sscop_msg *msg)
4795{
4796	void (*func)(struct sscop *, struct sscop_msg *);
4797	int (*cond)(struct sscop *);
4798
4799	func = state_matrix[sscop->state][sig].func;
4800	cond = state_matrix[sscop->state][sig].cond;
4801
4802	if(func == NULL) {
4803		VERBOSE(sscop, SSCOP_DBG_BUG, (sscop, sscop->aarg,
4804		    "no handler for %s in state %s - ignored",
4805		    events[sig], states[sscop->state]));
4806		SSCOP_MSG_FREE(msg);
4807		return 1;
4808	}
4809	if(cond == NULL || (*cond)(sscop)) {
4810		VERBOSE(sscop, SSCOP_DBG_EXEC, (sscop, sscop->aarg,
4811		    "executing %s in %s", events[sig],
4812		    states[sscop->state]));
4813		(*func)(sscop, msg);
4814		return 1;
4815	}
4816	VERBOSE(sscop, SSCOP_DBG_EXEC, (sscop, sscop->aarg,
4817	    "delaying %s in %s", events[sig],
4818	    states[sscop->state]));
4819
4820	return 0;
4821}
4822
4823/*
4824 * Deliver a signal to the given sscop
4825 * If it is delivered from inside a signal handler - queue it. If not,
4826 * execute it. After execution loop through the queue and execute all
4827 * pending signals. Signals, that cannot be executed because of entry
4828 * conditions are skipped.
4829 */
4830static void
4831sscop_signal(struct sscop *sscop, u_int sig, struct sscop_msg *msg)
4832{
4833	struct sscop_sig *s;
4834
4835	VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg,
4836	    "got signal %s in state %s%s", events[sig],
4837	    states[sscop->state], sscop->in_sig ? " -- queuing" : ""));
4838
4839	SIG_ALLOC(s);
4840	if(s == NULL) {
4841		FAILURE("sscop: cannot allocate signal");
4842		SSCOP_MSG_FREE(msg);
4843		return;
4844	}
4845	s->sig = sig;
4846	s->msg = msg;
4847	SIGQ_APPEND(&sscop->sigs, s);
4848
4849	if(!sscop->in_sig)
4850		handle_sigs(sscop);
4851}
4852
4853/*
4854 * Loop through the signal queue until we can't execute any signals.
4855 */
4856static void
4857handle_sigs(struct sscop *sscop)
4858{
4859	struct sscop_sig *s;
4860	sscop_sigq_head_t dsigs, q;
4861	int exec;
4862
4863	sscop->in_sig++;
4864
4865	/*
4866	 * Copy the current signal queue to the local one and empty
4867	 * the signal queue. Then loop through the signals. After one
4868	 * pass we have a list of delayed signals because of entry
4869	 * conditions and a new list of signals. Merge them. Repeat until
4870	 * the signal queue is either empty or contains only delayed signals.
4871	 */
4872	SIGQ_INIT(&q);
4873	SIGQ_INIT(&dsigs);
4874	do {
4875		exec = 0;
4876
4877		/*
4878		 * Copy signal list and make sscop list empty
4879		 */
4880		SIGQ_MOVE(&sscop->sigs, &q);
4881
4882		/*
4883		 * Loop through the list
4884		 */
4885		while((s = SIGQ_GET(&q)) != NULL) {
4886			if(sig_exec(sscop, s->sig, s->msg)) {
4887				exec = 1;
4888				SIG_FREE(s);
4889			} else {
4890				SIGQ_APPEND(&dsigs, s);
4891			}
4892		}
4893
4894		/*
4895		 * Merge lists by inserting delayed signals in front of
4896		 * the signal list. preserving the order.
4897		 */
4898		SIGQ_PREPEND(&dsigs, &sscop->sigs);
4899	} while(exec);
4900	sscop->in_sig--;
4901}
4902
4903/*
4904 * Save a signal that should be executed only if state changes.
4905 */
4906static void
4907sscop_save_signal(struct sscop *sscop, u_int sig, struct sscop_msg *msg)
4908{
4909	struct sscop_sig *s;
4910
4911	SIG_ALLOC(s);
4912	if(s == NULL) {
4913		FAILURE("sscop: cannot allocate signal");
4914		SSCOP_MSG_FREE(msg);
4915		return;
4916	}
4917	s->sig = sig;
4918	s->msg = msg;
4919	SIGQ_APPEND(&sscop->saved_sigs, s);
4920}
4921
4922/*
4923 * Set a new state. If signals are waiting for a state change - append them to
4924 * the signal queue, so they get executed.
4925 */
4926static void
4927sscop_set_state(struct sscop *sscop, u_int nstate)
4928{
4929	VERBOSE(sscop, SSCOP_DBG_STATE, (sscop, sscop->aarg,
4930	    "changing state from %s to %s",
4931	    states[sscop->state], states[nstate]));
4932
4933	sscop->state = nstate;
4934	SIGQ_MOVE(&sscop->saved_sigs, &sscop->sigs);
4935}
4936
4937void
4938sscop_setdebug(struct sscop *sscop, u_int n)
4939{
4940	sscop->debug = n;
4941}
4942
4943u_int
4944sscop_getdebug(const struct sscop *sscop)
4945{
4946	return (sscop->debug);
4947}
4948