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