/* * Copyright (c) 1996-2003 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * Author: Hartmut Brandt * * $Begemot: libunimsg/netnatm/saal/saal_sscop.c,v 1.11 2004/07/08 08:22:13 brandt Exp $ * * Core SSCOP code (ITU-T Q.2110) */ #include #include #ifndef FAILURE #define FAILURE(S) #endif #define MKSTR(S) #S static const char *const sscop_sigs[] = { MKSTR(SSCOP_ESTABLISH_request), MKSTR(SSCOP_ESTABLISH_indication), MKSTR(SSCOP_ESTABLISH_response), MKSTR(SSCOP_ESTABLISH_confirm), MKSTR(SSCOP_RELEASE_request), MKSTR(SSCOP_RELEASE_indication), MKSTR(SSCOP_RELEASE_confirm), MKSTR(SSCOP_DATA_request), MKSTR(SSCOP_DATA_indication), MKSTR(SSCOP_UDATA_request), MKSTR(SSCOP_UDATA_indication), MKSTR(SSCOP_RECOVER_indication), MKSTR(SSCOP_RECOVER_response), MKSTR(SSCOP_RESYNC_request), MKSTR(SSCOP_RESYNC_indication), MKSTR(SSCOP_RESYNC_response), MKSTR(SSCOP_RESYNC_confirm), MKSTR(SSCOP_RETRIEVE_request), MKSTR(SSCOP_RETRIEVE_indication), MKSTR(SSCOP_RETRIEVE_COMPL_indication), }; static const char *const sscop_msigs[] = { MKSTR(SSCOP_MDATA_request), MKSTR(SSCOP_MDATA_indication), MKSTR(SSCOP_MERROR_indication), }; static const char *const states[] = { MKSTR(SSCOP_IDLE), MKSTR(SSCOP_OUT_PEND), MKSTR(SSCOP_IN_PEND), MKSTR(SSCOP_OUT_DIS_PEND), MKSTR(SSCOP_OUT_RESYNC_PEND), MKSTR(SSCOP_IN_RESYNC_PEND), MKSTR(SSCOP_OUT_REC_PEND), MKSTR(SSCOP_REC_PEND), MKSTR(SSCOP_IN_REC_PEND), MKSTR(SSCOP_READY), }; #ifdef SSCOP_DEBUG static const char *const events[] = { MKSTR(SIG_BGN), MKSTR(SIG_BGAK), MKSTR(SIG_END), MKSTR(SIG_ENDAK), MKSTR(SIG_RS), MKSTR(SIG_RSAK), MKSTR(SIG_BGREJ), MKSTR(SIG_SD), MKSTR(SIG_ER), MKSTR(SIG_POLL), MKSTR(SIG_STAT), MKSTR(SIG_USTAT), MKSTR(SIG_UD), MKSTR(SIG_MD), MKSTR(SIG_ERAK), MKSTR(SIG_T_CC), MKSTR(SIG_T_POLL), MKSTR(SIG_T_KA), MKSTR(SIG_T_NR), MKSTR(SIG_T_IDLE), MKSTR(SIG_PDU_Q), MKSTR(SIG_USER_DATA), MKSTR(SIG_ESTAB_REQ), MKSTR(SIG_ESTAB_RESP), MKSTR(SIG_RELEASE_REQ), MKSTR(SIG_RECOVER), MKSTR(SIG_SYNC_REQ), MKSTR(SIG_SYNC_RESP), MKSTR(SIG_UDATA), MKSTR(SIG_MDATA), MKSTR(SIG_UPDU_Q), MKSTR(SIG_MPDU_Q), MKSTR(SIG_RETRIEVE), }; static const char *const pdus[] = { "illegale PDU type 0", /* no PDU type 0 */ MKSTR(PDU_BGN), MKSTR(PDU_BGAK), MKSTR(PDU_END), MKSTR(PDU_ENDAK), MKSTR(PDU_RS), MKSTR(PDU_RSAK), MKSTR(PDU_BGREJ), MKSTR(PDU_SD), MKSTR(PDU_ER), MKSTR(PDU_POLL), MKSTR(PDU_STAT), MKSTR(PDU_USTAT), MKSTR(PDU_UD), MKSTR(PDU_MD), MKSTR(PDU_ERAK), }; #endif MEMINIT(); static void sscop_signal(struct sscop *, u_int, struct sscop_msg *); static void sscop_save_signal(struct sscop *, u_int, struct sscop_msg *); static void handle_sigs(struct sscop *); static void sscop_set_state(struct sscop *, u_int); /************************************************************/ /************************************************************/ /* * Queue macros */ #define SSCOP_MSG_FREE(MSG) \ do { \ if(MSG) { \ MBUF_FREE((MSG)->m); \ MSG_FREE((MSG)); \ } \ } while(0) #define QFIND(Q,RN) \ ({ \ struct sscop_msg *_msg = NULL, *_m; \ MSGQ_FOREACH(_m, (Q)) { \ if(_m->seqno == (RN)) { \ _msg = _m; \ break; \ } \ } \ _msg; \ }) #define QINSERT(Q,M) \ do { \ struct sscop_msg *_msg = NULL, *_m; \ MSGQ_FOREACH(_m, (Q)) { \ if (_m->seqno > (M)->seqno) { \ _msg = _m; \ break; \ } \ } \ if (_msg != NULL) \ MSGQ_INSERT_BEFORE(_msg, (M)); \ else \ MSGQ_APPEND((Q), (M)); \ } while (0) /* * Send an error indication to the management plane. */ #define MAAL_ERROR(S,E,C) \ do { \ VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \ "MAA-Signal %s in state %s", \ sscop_msigs[SSCOP_MERROR_indication], states[(S)->state])); \ (S)->funcs->send_manage((S), (S)->aarg, \ SSCOP_MERROR_indication, NULL, (E), (C)); \ } while(0) #define MAAL_DATA(S,M) \ do { \ VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \ "MAA-Signal %s in state %s", \ sscop_msigs[SSCOP_MDATA_indication], states[(S)->state])); \ (S)->funcs->send_manage((S), (S)->aarg, \ SSCOP_MDATA_indication, (M), 0, 0); \ } while(0) #define AAL_DATA(S,D,M,N) \ do { \ VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \ "AA-Signal %s in state %s", \ sscop_sigs[D], states[(S)->state])); \ (S)->funcs->send_upper((S), (S)->aarg, (D), (M), (N)); \ } while(0) #define AAL_SIG(S,D) \ do { \ VERBOSE(S, SSCOP_DBG_USIG, ((S), (S)->aarg, \ "AA-Signal %s in state %s", \ sscop_sigs[D], states[(S)->state])); \ (S)->funcs->send_upper((S), (S)->aarg, (D), NULL, 0); \ } while(0) #ifdef SSCOP_DEBUG #define AAL_SEND(S,M) do { \ if (ISVERBOSE(S, SSCOP_DBG_PDU)) \ sscop_dump_pdu(S, "tx", (M)); \ (S)->funcs->send_lower((S), (S)->aarg, (M)); \ } while(0) #else #define AAL_SEND(S,M) (S)->funcs->send_lower((S), (S)->aarg, (M)) #endif /* * Free a save user-to-user data buffer and set the pointer to zero * to signal, that it is free. */ #define FREE_UU(F) \ do { \ if(sscop->F) { \ MBUF_FREE(sscop->F); \ sscop->F = NULL; \ } \ } while(0) #define SET_UU(F,U) \ do { \ FREE_UU(F); \ sscop->F = U->m; \ U->m = NULL; \ SSCOP_MSG_FREE(U); \ } while(0) #define AAL_UU_SIGNAL(S, SIG, M, PL, SN) \ do { \ if(MBUF_LEN((M)->m) > 0) { \ MBUF_UNPAD((M)->m,(PL)); \ AAL_DATA((S), (SIG), (M)->m, (SN)); \ (M)->m = NULL; \ } else { \ AAL_DATA((S), (SIG), NULL, (SN)); \ } \ SSCOP_MSG_FREE((M)); \ } while(0) TIMER_FUNC(cc, CC) TIMER_FUNC(nr, NR) TIMER_FUNC(ka, KA) TIMER_FUNC(poll, POLL) TIMER_FUNC(idle, IDLE) /************************************************************/ /* * INSTANCE AND TYPE HANDLING. */ #ifdef SSCOP_DEBUG static void sscop_dump_pdu(struct sscop *sscop, const char *dir, const struct SSCOP_MBUF_T *m) { u_int32_t v1, v2, v3, v4; u_int size = MBUF_LEN(m); u_int n, i; if (size < 8) return; v1 = MBUF_TRAIL32(m, -1); v2 = MBUF_TRAIL32(m, -2); switch ((v1 >> 24) & 0xf) { case 0: return; case PDU_BGN: sscop->funcs->verbose(sscop, sscop->aarg, "%s BGN n(mr)=%u n(sq)=%u pl=%u", dir, v1 & 0xffffff, v2 & 0xff, (v1 >> 30) & 0x3); return; case PDU_BGAK: sscop->funcs->verbose(sscop, sscop->aarg, "%s BGAK n(mr)=%u pl=%u", dir, v1 & 0xffffff, (v1 >> 30) & 0x3); return; case PDU_END: sscop->funcs->verbose(sscop, sscop->aarg, "%s END r=%u s=%u pl=%u", dir, (v1 >> 29) & 1, (v1 >> 28) & 1, (v1 >> 30) & 0x3); return; case PDU_ENDAK: sscop->funcs->verbose(sscop, sscop->aarg, "%s ENDAK", dir); return; case PDU_RS: sscop->funcs->verbose(sscop, sscop->aarg, "%s RS n(mr)=%u n(sq)=%u pl=%u", dir, v1 & 0xffffff, v2 & 0xff, (v1 >> 30) & 0x3); return; case PDU_RSAK: sscop->funcs->verbose(sscop, sscop->aarg, "%s RSAK n(mr)=%u", dir, v1 & 0xffffff); return; case PDU_BGREJ: sscop->funcs->verbose(sscop, sscop->aarg, "%s BGREJ pl=%u", dir, (v1 >> 30) & 0x3); return; case PDU_SD: sscop->funcs->verbose(sscop, sscop->aarg, "%s SD n(s)=%u pl=%u", dir, v1 & 0xffffff, (v1 >> 30) & 0x3); return; case PDU_ER: sscop->funcs->verbose(sscop, sscop->aarg, "%s ER n(mr)=%u n(sq)=%u", dir, v1 & 0xffffff, v2 & 0xff); return; case PDU_POLL: sscop->funcs->verbose(sscop, sscop->aarg, "%s POLL n(s)=%u n(ps)=%u", dir, v1 & 0xffffff, v2 & 0xffffff); return; case PDU_STAT: if (size < 12) return; v3 = MBUF_TRAIL32(m, -3); sscop->funcs->verbose(sscop, sscop->aarg, "%s STAT n(r)=%u n(mr)=%u n(ps)=%u", dir, v1 & 0xffffff, v2 & 0xffffff, v3 & 0xffffff); n = (size - 12) / 4; for (i = 0; i < (size - 12) / 4; i++, n--) { v4 = MBUF_TRAIL32(m, -4 - (int)i); sscop->funcs->verbose(sscop, sscop->aarg, " LE(%u)=%u", n, v4 & 0xffffff); } return; case PDU_USTAT: if (size < 16) return; sscop->funcs->verbose(sscop, sscop->aarg, "%s STAT n(r)=%u n(mr)=%u LE1=%u LE2=%u", dir, v1 & 0xffffff, v2 & 0xffffff, MBUF_TRAIL32(m, -4) & 0xffffff, MBUF_TRAIL32(m, -3) & 0xffffff); return; case PDU_UD: sscop->funcs->verbose(sscop, sscop->aarg, "%s UD pl=%u", dir, (v1 >> 30) & 0x3); return; case PDU_MD: sscop->funcs->verbose(sscop, sscop->aarg, "%s MD pl=%u", dir, (v1 >> 30) & 0x3); return; case PDU_ERAK: sscop->funcs->verbose(sscop, sscop->aarg, "%s ERAK n(mr)=%u", dir, v1 & 0xffffff); return; } } #endif /* * Initialize state of variables */ static void sscop_init(struct sscop *sscop) { sscop->state = SSCOP_IDLE; sscop->vt_sq = 0; sscop->vr_sq = 0; sscop->clear_buffers = 1; sscop->ll_busy = 0; sscop->rxq = 0; } static void sscop_clear(struct sscop *sscop) { TIMER_STOP(sscop, cc); TIMER_STOP(sscop, ka); TIMER_STOP(sscop, nr); TIMER_STOP(sscop, idle); TIMER_STOP(sscop, poll); FREE_UU(uu_bgn); FREE_UU(uu_bgak); FREE_UU(uu_bgrej); FREE_UU(uu_end); FREE_UU(uu_rs); MSGQ_CLEAR(&sscop->xq); MSGQ_CLEAR(&sscop->uxq); MSGQ_CLEAR(&sscop->mxq); MSGQ_CLEAR(&sscop->xbuf); MSGQ_CLEAR(&sscop->rbuf); SIGQ_CLEAR(&sscop->sigs); SIGQ_CLEAR(&sscop->saved_sigs); } /* * Allocate instance memory, initialize the state of all variables. */ struct sscop * sscop_create(void *a, const struct sscop_funcs *funcs) { struct sscop *sscop; MEMZALLOC(sscop, struct sscop *, sizeof(struct sscop)); if (sscop == NULL) return (NULL); if (a == NULL) sscop->aarg = sscop; else sscop->aarg = a; sscop->funcs = funcs; sscop->maxk = MAXK; sscop->maxj = MAXJ; sscop->maxcc = MAXCC; sscop->maxpd = MAXPD; sscop->maxstat = MAXSTAT; sscop->timercc = TIMERCC; sscop->timerka = TIMERKA; sscop->timernr = TIMERNR; sscop->timerpoll = TIMERPOLL; sscop->timeridle = TIMERIDLE; sscop->robustness = 0; sscop->poll_after_rex = 0; sscop->mr = MAXMR; TIMER_INIT(sscop, cc); TIMER_INIT(sscop, nr); TIMER_INIT(sscop, ka); TIMER_INIT(sscop, poll); TIMER_INIT(sscop, idle); MSGQ_INIT(&sscop->xq); MSGQ_INIT(&sscop->uxq); MSGQ_INIT(&sscop->mxq); MSGQ_INIT(&sscop->rbuf); MSGQ_INIT(&sscop->xbuf); SIGQ_INIT(&sscop->sigs); SIGQ_INIT(&sscop->saved_sigs); sscop_init(sscop); return (sscop); } /* * Free all resources in a sscop instance */ void sscop_destroy(struct sscop *sscop) { sscop_reset(sscop); MEMFREE(sscop); } /* * Reset the SSCOP instance. */ void sscop_reset(struct sscop *sscop) { sscop_clear(sscop); sscop_init(sscop); } void sscop_getparam(const struct sscop *sscop, struct sscop_param *p) { p->timer_cc = sscop->timercc; p->timer_poll = sscop->timerpoll; p->timer_keep_alive = sscop->timerka; p->timer_no_response = sscop->timernr; p->timer_idle = sscop->timeridle; p->maxk = sscop->maxk; p->maxj = sscop->maxj; p->maxcc = sscop->maxcc; p->maxpd = sscop->maxpd; p->maxstat = sscop->maxstat; p->mr = sscop->mr; p->flags = 0; if(sscop->robustness) p->flags |= SSCOP_ROBUST; if(sscop->poll_after_rex) p->flags |= SSCOP_POLLREX; } int sscop_setparam(struct sscop *sscop, struct sscop_param *p, u_int *pmask) { u_int mask = *pmask; /* can change only in idle state */ if (sscop->state != SSCOP_IDLE) return (EISCONN); *pmask = 0; /* * first check all parameters */ if ((mask & SSCOP_SET_TCC) && p->timer_cc == 0) *pmask |= SSCOP_SET_TCC; if ((mask & SSCOP_SET_TPOLL) && p->timer_poll == 0) *pmask |= SSCOP_SET_TPOLL; if ((mask & SSCOP_SET_TKA) && p->timer_keep_alive == 0) *pmask |= SSCOP_SET_TKA; if ((mask & SSCOP_SET_TNR) && p->timer_no_response == 0) *pmask |= SSCOP_SET_TNR; if ((mask & SSCOP_SET_TIDLE) && p->timer_idle == 0) *pmask |= SSCOP_SET_TIDLE; if ((mask & SSCOP_SET_MAXK) && p->maxk > MAXMAXK) *pmask |= SSCOP_SET_MAXK; if ((mask & SSCOP_SET_MAXJ) && p->maxj > MAXMAXJ) *pmask |= SSCOP_SET_MAXJ; if ((mask & SSCOP_SET_MAXCC) && p->maxcc > 255) *pmask |= SSCOP_SET_MAXCC; if ((mask & SSCOP_SET_MAXPD) && p->maxpd >= (1 << 24)) *pmask |= SSCOP_SET_MAXPD; if ((mask & SSCOP_SET_MAXSTAT) && ((p->maxstat & 1) == 0 || p->maxstat == 1 || p->maxstat == 2 || p->maxstat * 4 > MAXMAXK - 8)) *pmask |= SSCOP_SET_MAXSTAT; if ((mask & SSCOP_SET_MR) && p->mr >= (1 << 24) - 1) *pmask |= SSCOP_SET_MR; if (*pmask) return (EINVAL); /* * now set it */ if (mask & SSCOP_SET_TCC) sscop->timercc = p->timer_cc; if (mask & SSCOP_SET_TPOLL) sscop->timerpoll = p->timer_poll; if (mask & SSCOP_SET_TKA) sscop->timerka = p->timer_keep_alive; if (mask & SSCOP_SET_TNR) sscop->timernr = p->timer_no_response; if (mask & SSCOP_SET_TIDLE) sscop->timeridle = p->timer_idle; if (mask & SSCOP_SET_MAXK) sscop->maxk = p->maxk; if (mask & SSCOP_SET_MAXJ) sscop->maxj = p->maxj; if (mask & SSCOP_SET_MAXCC) sscop->maxcc = p->maxcc; if (mask & SSCOP_SET_MAXPD) sscop->maxpd = p->maxpd; if (mask & SSCOP_SET_MAXSTAT) sscop->maxstat = p->maxstat; if (mask & SSCOP_SET_MR) sscop->mr = p->mr; if (mask & SSCOP_SET_ROBUST) sscop->robustness = ((p->flags & SSCOP_ROBUST) != 0); if (mask & SSCOP_SET_POLLREX) sscop->poll_after_rex = ((p->flags & SSCOP_POLLREX) != 0); return (0); } enum sscop_state sscop_getstate(const struct sscop *sscop) { return (sscop->state); } /************************************************************/ /* * EXTERNAL INPUT SIGNAL MAPPING */ /* * Map AA signal to SSCOP internal signal */ int sscop_aasig(struct sscop *sscop, enum sscop_aasig sig, struct SSCOP_MBUF_T *m, u_int arg) { struct sscop_msg *msg; if (sig >= sizeof(sscop_sigs)/sizeof(sscop_sigs[0])) { VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg, "AA-Signal %u - bad signal", sig)); MBUF_FREE(m); return (EINVAL); } VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg, "AA-Signal %s in state %s with%s message", sscop_sigs[sig], states[sscop->state], m ? "" : "out")); MSG_ALLOC(msg); if (msg == NULL) { FAILURE("sscop: cannot allocate aasig"); MBUF_FREE(m); return (ENOMEM); } switch(sig) { case SSCOP_ESTABLISH_request: msg->m = m; msg->rexmit = arg; sscop_signal(sscop, SIG_ESTAB_REQ, msg); break; case SSCOP_ESTABLISH_response: msg->m = m; msg->rexmit = arg; sscop_signal(sscop, SIG_ESTAB_RESP, msg); break; case SSCOP_RELEASE_request: msg->m = m; sscop_signal(sscop, SIG_RELEASE_REQ, msg); break; case SSCOP_DATA_request: msg->m = m; sscop_signal(sscop, SIG_USER_DATA, msg); break; case SSCOP_UDATA_request: msg->m = m; sscop_signal(sscop, SIG_UDATA, msg); break; case SSCOP_RECOVER_response: MBUF_FREE(m); MSG_FREE(msg); sscop_signal(sscop, SIG_RECOVER, NULL); break; case SSCOP_RESYNC_request: msg->m = m; sscop_signal(sscop, SIG_SYNC_REQ, msg); break; case SSCOP_RESYNC_response: MBUF_FREE(m); MSG_FREE(msg); sscop_signal(sscop, SIG_SYNC_RESP, NULL); break; case SSCOP_RETRIEVE_request: MBUF_FREE(m); msg->rexmit = arg; sscop_signal(sscop, SIG_RETRIEVE, msg); break; case SSCOP_ESTABLISH_indication: case SSCOP_ESTABLISH_confirm: case SSCOP_RELEASE_indication: case SSCOP_RELEASE_confirm: case SSCOP_DATA_indication: case SSCOP_UDATA_indication: case SSCOP_RECOVER_indication: case SSCOP_RESYNC_indication: case SSCOP_RESYNC_confirm: case SSCOP_RETRIEVE_indication: case SSCOP_RETRIEVE_COMPL_indication: MBUF_FREE(m); MSG_FREE(msg); return EINVAL; } return 0; } /* * Signal from layer management. */ int sscop_maasig(struct sscop *sscop, enum sscop_maasig sig, struct SSCOP_MBUF_T *m) { struct sscop_msg *msg; if (sig >= sizeof(sscop_msigs)/sizeof(sscop_msigs[0])) { VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg, "MAA-Signal %u - bad signal", sig)); MBUF_FREE(m); return (EINVAL); } VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg, "MAA-Signal %s in state %s with%s message", sscop_msigs[sig], states[sscop->state], m ? "" : "out")); MSG_ALLOC(msg); if (msg == NULL) { FAILURE("sscop: cannot allocate maasig"); MBUF_FREE(m); return (ENOMEM); } switch (sig) { case SSCOP_MDATA_request: msg->m = m; sscop_signal(sscop, SIG_MDATA, msg); break; case SSCOP_MDATA_indication: case SSCOP_MERROR_indication: MBUF_FREE(m); MSG_FREE(msg); return (EINVAL); } return (0); } /* * Map PDU to SSCOP signal. */ void sscop_input(struct sscop *sscop, struct SSCOP_MBUF_T *m) { struct sscop_msg *msg; union pdu pdu; u_int size; MSG_ALLOC(msg); if(msg == NULL) { FAILURE("sscop: cannot allocate in pdu msg"); MBUF_FREE(m); return; } msg->m = m; msg->rexmit = 0; size = MBUF_LEN(m); if(size % 4 != 0 || size < 4) goto err; pdu.sscop_null = MBUF_TRAIL32(m, -1); VERBOSE(sscop, SSCOP_DBG_PDU, (sscop, sscop->aarg, "got %s, size=%u", pdus[pdu.sscop_type], size)); #ifdef SSCOP_DEBUG #define ENSURE(C,F) if(!(C)) { VERBOSE(sscop, SSCOP_DBG_PDU, F); goto err; } #else #define ENSURE(C,F) if(!(C)) goto err #endif #ifdef SSCOP_DEBUG if (ISVERBOSE(sscop, SSCOP_DBG_PDU)) sscop_dump_pdu(sscop, "rx", m); #endif switch(pdu.sscop_type) { default: ENSURE(0, (sscop, sscop->aarg, "Bad PDU type %u", pdu.sscop_type)); break; case PDU_BGN: ENSURE(size >= 8U, (sscop, sscop->aarg, "PDU_BGN size=%u", size)); ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg, "PDU_BGN size=%u pl=%u", size, pdu.sscop_pl)); ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg, "PDU_BGN size=%u", size)); sscop_signal(sscop, SIG_BGN, msg); break; case PDU_BGAK: ENSURE(size >= 8U, (sscop, sscop->aarg, "PDU_BGAK size=%u", size)); ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg, "PDU_BGAK size=%u pl=%u", size, pdu.sscop_pl)); ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg, "PDU_BGAK size=%u", size)); sscop_signal(sscop, SIG_BGAK, msg); break; case PDU_END: ENSURE(size >= 8U, (sscop, sscop->aarg, "PDU_END size=%u", size)); ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg, "PDU_END size=%u pl=%u", size, pdu.sscop_pl)); ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg, "PDU_END size=%u", size)); sscop_signal(sscop, SIG_END, msg); break; case PDU_ENDAK: ENSURE(size == 8U, (sscop, sscop->aarg, "PDU_ENDAK size=%u", size)); sscop_signal(sscop, SIG_ENDAK, msg); break; case PDU_BGREJ: ENSURE(size >= 8U, (sscop, sscop->aarg, "PDU_BGREJ size=%u", size)); ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg, "PDU_BGREJ size=%u pl=%u", size, pdu.sscop_pl)); ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg, "PDU_BGREJ size=%u", size)); sscop_signal(sscop, SIG_BGREJ, msg); break; case PDU_SD: ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg, "PDU_SD size=%u pl=%u", size, pdu.sscop_pl)); ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg, "PDU_SD size=%u", size)); sscop_signal(sscop, SIG_SD, msg); break; case PDU_UD: ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg, "PDU_UD size=%u pl=%u", size, pdu.sscop_pl)); ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg, "PDU_UD size=%u", size)); sscop_signal(sscop, SIG_UD, msg); break; case PDU_MD: ENSURE(size >= 4U + pdu.sscop_pl, (sscop, sscop->aarg, "PDU_MD size=%u pl=%u", size, pdu.sscop_pl)); ENSURE(size <= 4U + sscop->maxk, (sscop, sscop->aarg, "PDU_MD size=%u", size)); sscop_signal(sscop, SIG_MD, msg); break; case PDU_POLL: ENSURE(size == 8U, (sscop, sscop->aarg, "PDU_POLL size=%u", size)); sscop_signal(sscop, SIG_POLL, msg); break; case PDU_STAT: ENSURE(size >= 12U, (sscop, sscop->aarg, "PDU_STAT size=%u", size)); ENSURE(size <= 12U + 4 * sscop->maxstat, (sscop, sscop->aarg, "PDU_STAT size=%u", size)); sscop_signal(sscop, SIG_STAT, msg); break; case PDU_RS: ENSURE(size >= 8U, (sscop, sscop->aarg, "PDU_RS size=%u", size)); ENSURE(size >= 8U + pdu.sscop_pl, (sscop, sscop->aarg, "PDU_RS size=%u pl=%u", size, pdu.sscop_pl)); ENSURE(size <= 8U + sscop->maxj, (sscop, sscop->aarg, "PDU_RS size=%u", size)); sscop_signal(sscop, SIG_RS, msg); break; case PDU_RSAK: ENSURE(size == 8U, (sscop, sscop->aarg, "PDU_RSAK size=%u", size)); sscop_signal(sscop, SIG_RSAK, msg); break; case PDU_ER: ENSURE(size == 8U, (sscop, sscop->aarg, "PDU_ER size=%u", size)); sscop_signal(sscop, SIG_ER, msg); break; case PDU_ERAK: ENSURE(size == 8U, (sscop, sscop->aarg, "PDU_ERAK size=%u", size)); sscop_signal(sscop, SIG_ERAK, msg); break; case PDU_USTAT: ENSURE(size == 16U, (sscop, sscop->aarg, "PDU_ERAK size=%u", size)); sscop_signal(sscop, SIG_USTAT, msg); break; } #undef ENSURE return; err: MAAL_ERROR(sscop, 'U', 0); SSCOP_MSG_FREE(msg); } /************************************************************/ /* * UTILITIES */ /* * Move the receiver window by N packets */ u_int sscop_window(struct sscop *sscop, u_int n) { sscop->vr_mr += n; return (SEQNO_DIFF(sscop->vr_mr, sscop->vr_r)); } /* * Lower layer busy handling */ u_int sscop_setbusy(struct sscop *sscop, int busy) { u_int old = sscop->ll_busy; if (busy > 0) sscop->ll_busy = 1; else if (busy == 0) { sscop->ll_busy = 0; if(old) handle_sigs(sscop); } return (old); } const char * sscop_signame(enum sscop_aasig sig) { static char str[40]; if (sig >= sizeof(sscop_sigs)/sizeof(sscop_sigs[0])) { sprintf(str, "BAD SSCOP_AASIG %u", sig); return (str); } else { return (sscop_sigs[sig]); } } const char * sscop_msigname(enum sscop_maasig sig) { static char str[40]; if (sig >= sizeof(sscop_msigs)/sizeof(sscop_msigs[0])) { sprintf(str, "BAD SSCOP_MAASIG %u", sig); return (str); } else { return (sscop_msigs[sig]); } } const char * sscop_statename(enum sscop_state s) { static char str[40]; if (s >= sizeof(states)/sizeof(states[0])) { sprintf(str, "BAD SSCOP_STATE %u", s); return (str); } else { return (states[s]); } } /************************************************************/ /* * MACROS */ /* * p 75: release buffers */ static void m_release_buffers(struct sscop *sscop) { MSGQ_CLEAR(&sscop->xq); MSGQ_CLEAR(&sscop->xbuf); sscop->rxq = 0; MSGQ_CLEAR(&sscop->rbuf); } /* * P 75: Prepare retrival */ static void m_prepare_retrieval(struct sscop *sscop) { struct sscop_msg *msg; if (sscop->clear_buffers) { MSGQ_CLEAR(&sscop->xq); MSGQ_CLEAR(&sscop->xbuf); } MSGQ_FOREACH(msg, &sscop->xbuf) msg->rexmit = 0; sscop->rxq = 0; MSGQ_CLEAR(&sscop->rbuf); } /* * P 75: Prepare retrival */ static void m_prepare_recovery(struct sscop *sscop) { struct sscop_msg *msg; if(sscop->clear_buffers) { MSGQ_CLEAR(&sscop->xq); MSGQ_CLEAR(&sscop->xbuf); } MSGQ_FOREACH(msg, &sscop->xbuf) msg->rexmit = 0; sscop->rxq = 0; } /* * P 75: Clear transmitter */ static void m_clear_transmitter(struct sscop *sscop) { if(!sscop->clear_buffers) { MSGQ_CLEAR(&sscop->xq); MSGQ_CLEAR(&sscop->xbuf); } } /* * p 75: Deliver data * Freeing the message is the responibility of the handler function. */ static void m_deliver_data(struct sscop *sscop) { struct sscop_msg *msg; u_int sn; if ((msg = MSGQ_GET(&sscop->rbuf)) == NULL) return; if (sscop->clear_buffers) { MSGQ_CLEAR(&sscop->rbuf); return; } sn = msg->seqno + 1; AAL_DATA(sscop, SSCOP_DATA_indication, msg->m, msg->seqno); MSG_FREE(msg); while ((msg = MSGQ_GET(&sscop->rbuf)) != NULL) { ASSERT(msg->seqno == sn); if (++sn == SSCOP_MAXSEQNO) sn = 0; AAL_DATA(sscop, SSCOP_DATA_indication, msg->m, msg->seqno); MSG_FREE(msg); } } /* * P 75: Initialize state variables */ static void m_initialize_state(struct sscop *sscop) { sscop->vt_s = 0; sscop->vt_ps = 0; sscop->vt_a = 0; sscop->vt_pa = 1; sscop->vt_pd = 0; sscop->credit = 1; sscop->vr_r = 0; sscop->vr_h = 0; } /* * p 76: Data retrieval */ static void m_data_retrieval(struct sscop *sscop, u_int rn) { struct sscop_msg *s; if (rn != SSCOP_RETRIEVE_UNKNOWN) { if(rn >= SSCOP_RETRIEVE_TOTAL) rn = sscop->vt_a; else rn++; while(rn >= sscop->vt_a && rn < sscop->vt_s) { if(rn == SSCOP_MAXSEQNO) rn = 0; if((s = QFIND(&sscop->xbuf, rn)) != NULL) { MSGQ_REMOVE(&sscop->xbuf, s); AAL_DATA(sscop, SSCOP_RETRIEVE_indication, s->m, 0); MSG_FREE(s); } rn++; } } while((s = MSGQ_GET(&sscop->xq)) != NULL) { AAL_DATA(sscop, SSCOP_RETRIEVE_indication, s->m, 0); MSG_FREE(s); } AAL_SIG(sscop, SSCOP_RETRIEVE_COMPL_indication); } /* * P 76: Detect retransmission. PDU type must already be stripped. */ static int m_detect_retransmission(struct sscop *sscop, struct sscop_msg *msg) { union bgn bgn; bgn.sscop_null = MBUF_TRAIL32(msg->m, -1); if (sscop->vr_sq == bgn.sscop_bgns) return (1); sscop->vr_sq = bgn.sscop_bgns; return (0); } /* * P 76: Set POLL timer */ static void m_set_poll_timer(struct sscop *sscop) { if(MSGQ_EMPTY(&sscop->xq) && sscop->vt_s == sscop->vt_a) TIMER_RESTART(sscop, ka); else TIMER_RESTART(sscop, poll); } /* * P 77: Reset data transfer timers */ static void m_reset_data_xfer_timers(struct sscop *sscop) { TIMER_STOP(sscop, ka); TIMER_STOP(sscop, nr); TIMER_STOP(sscop, idle); TIMER_STOP(sscop, poll); } /* * P 77: Set data transfer timers */ static void m_set_data_xfer_timers(struct sscop *sscop) { TIMER_RESTART(sscop, poll); TIMER_RESTART(sscop, nr); } /* * P 77: Initialize VR(MR) */ static void m_initialize_mr(struct sscop *sscop) { sscop->vr_mr = sscop->mr; } /************************************************************/ /* * CONDITIONS */ static int c_ready_pduq(struct sscop *sscop) { if (!sscop->ll_busy && (sscop->rxq != 0 || sscop->vt_s < sscop->vt_ms || TIMER_ISACT(sscop, idle))) return (1); return (0); } /************************************************************/ /* * SEND PDUS */ /* * Send BG PDU. */ static void send_bgn(struct sscop *sscop, struct SSCOP_MBUF_T *uu) { union pdu pdu; union bgn bgn; struct SSCOP_MBUF_T *m; pdu.sscop_null = 0; pdu.sscop_type = PDU_BGN; pdu.sscop_ns = sscop->vr_mr; bgn.sscop_null = 0; bgn.sscop_bgns = sscop->vt_sq; if(uu) { if ((m = MBUF_DUP(uu)) == NULL) { FAILURE("sscop: cannot allocate BGN"); return; } pdu.sscop_pl += MBUF_PAD4(m); } else { if ((m = MBUF_ALLOC(8)) == NULL) { FAILURE("sscop: cannot allocate BGN"); return; } } MBUF_APPEND32(m, bgn.sscop_null); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send BGREJ PDU. */ static void send_bgrej(struct sscop *sscop, struct SSCOP_MBUF_T *uu) { union pdu pdu; union bgn bgn; struct SSCOP_MBUF_T *m; pdu.sscop_null = 0; pdu.sscop_type = PDU_BGREJ; bgn.sscop_null = 0; if(uu) { if((m = MBUF_DUP(uu)) == NULL) { FAILURE("sscop: cannot allocate BGREJ"); return; } pdu.sscop_pl += MBUF_PAD4(m); } else { if((m = MBUF_ALLOC(8)) == NULL) { FAILURE("sscop: cannot allocate BGREJ"); return; } } MBUF_APPEND32(m, bgn.sscop_null); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send BGAK PDU. */ static void send_bgak(struct sscop *sscop, struct SSCOP_MBUF_T *uu) { union pdu pdu; union bgn bgn; struct SSCOP_MBUF_T *m; pdu.sscop_null = 0; pdu.sscop_type = PDU_BGAK; pdu.sscop_ns = sscop->vr_mr; bgn.sscop_null = 0; if(uu) { if((m = MBUF_DUP(uu)) == NULL) { FAILURE("sscop: cannot allocate BGAK"); return; } pdu.sscop_pl += MBUF_PAD4(m); } else { if((m = MBUF_ALLOC(8)) == NULL) { FAILURE("sscop: cannot allocate BGAK"); return; } } MBUF_APPEND32(m, bgn.sscop_null); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send SD PDU. The function makes a duplicate of the message. */ static void send_sd(struct sscop *sscop, struct SSCOP_MBUF_T *m, u_int seqno) { union pdu pdu; if((m = MBUF_DUP(m)) == NULL) { FAILURE("sscop: cannot allocate SD"); return; } pdu.sscop_null = 0; pdu.sscop_pl = 0; pdu.sscop_type = PDU_SD; pdu.sscop_ns = seqno; pdu.sscop_pl += MBUF_PAD4(m); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send a UD PDU. The caller must free the sscop msg part. */ static void send_ud(struct sscop *sscop, struct SSCOP_MBUF_T *m) { union pdu pdu; pdu.sscop_null = 0; pdu.sscop_type = PDU_UD; pdu.sscop_pl += MBUF_PAD4(m); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send a MD PDU. The caller must free the sscop msg part. */ static void send_md(struct sscop *sscop, struct SSCOP_MBUF_T *m) { union pdu pdu; pdu.sscop_null = 0; pdu.sscop_type = PDU_MD; pdu.sscop_pl += MBUF_PAD4(m); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send END PDU. */ static void send_end(struct sscop *sscop, int src, struct SSCOP_MBUF_T *uu) { union pdu pdu; struct SSCOP_MBUF_T *m; sscop->last_end_src = src; pdu.sscop_null = 0; pdu.sscop_s = src; pdu.sscop_type = PDU_END; if(uu) { if((m = MBUF_DUP(uu)) == NULL) { FAILURE("sscop: cannot allocate END"); return; } pdu.sscop_pl += MBUF_PAD4(m); } else { if((m = MBUF_ALLOC(8)) == NULL) { FAILURE("sscop: cannot allocate END"); return; } } MBUF_APPEND32(m, 0); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send USTAT PDU. List must be terminated by -1. */ static void send_ustat(struct sscop *sscop, ...) { va_list ap; int f; u_int n; union pdu pdu; union seqno seqno; struct SSCOP_MBUF_T *m; va_start(ap, sscop); n = 0; while((f = va_arg(ap, int)) >= 0) n++; va_end(ap); if((m = MBUF_ALLOC(n * 4 + 8)) == NULL) { FAILURE("sscop: cannot allocate USTAT"); return; } va_start(ap, sscop); while((f = va_arg(ap, int)) >= 0) { seqno.sscop_null = 0; seqno.sscop_n = f; MBUF_APPEND32(m, seqno.sscop_null); } va_end(ap); seqno.sscop_null = 0; seqno.sscop_n = sscop->vr_mr; MBUF_APPEND32(m, seqno.sscop_null); pdu.sscop_null = 0; pdu.sscop_type = PDU_USTAT; pdu.sscop_ns = sscop->vr_r; MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send ER PDU. */ static void send_er(struct sscop *sscop) { union pdu pdu; union bgn bgn; struct SSCOP_MBUF_T *m; pdu.sscop_null = 0; pdu.sscop_type = PDU_ER; pdu.sscop_ns = sscop->vr_mr; bgn.sscop_null = 0; bgn.sscop_bgns = sscop->vt_sq; if((m = MBUF_ALLOC(8)) == NULL) { FAILURE("sscop: cannot allocate ER"); return; } MBUF_APPEND32(m, bgn.sscop_null); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send POLL PDU. */ static void send_poll(struct sscop *sscop) { union pdu pdu; union seqno seqno; struct SSCOP_MBUF_T *m; seqno.sscop_null = 0; seqno.sscop_n = sscop->vt_ps; pdu.sscop_null = 0; pdu.sscop_ns = sscop->vt_s; pdu.sscop_type = PDU_POLL; if((m = MBUF_ALLOC(8)) == NULL) { FAILURE("sscop: cannot allocate POLL"); return; } MBUF_APPEND32(m, seqno.sscop_null); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send STAT PDU. List is already in buffer. */ static void send_stat(struct sscop *sscop, u_int nps, struct SSCOP_MBUF_T *m) { union pdu pdu; union seqno seqno; seqno.sscop_null = 0; seqno.sscop_n = nps; MBUF_APPEND32(m, seqno.sscop_null); seqno.sscop_null = 0; seqno.sscop_n = sscop->vr_mr; MBUF_APPEND32(m, seqno.sscop_null); pdu.sscop_null = 0; pdu.sscop_type = PDU_STAT; pdu.sscop_ns = sscop->vr_r; MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send ENDAK PDU. */ static void send_endak(struct sscop *sscop) { union pdu pdu; union seqno seqno; struct SSCOP_MBUF_T *m; seqno.sscop_null = 0; pdu.sscop_null = 0; pdu.sscop_type = PDU_ENDAK; if((m = MBUF_ALLOC(8)) == NULL) { FAILURE("sscop: cannot allocate ENDAK"); return; } MBUF_APPEND32(m, seqno.sscop_null); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send ERAK PDU. */ static void send_erak(struct sscop *sscop) { union pdu pdu; union seqno seqno; struct SSCOP_MBUF_T *m; seqno.sscop_null = 0; pdu.sscop_null = 0; pdu.sscop_type = PDU_ERAK; pdu.sscop_ns = sscop->vr_mr; if((m = MBUF_ALLOC(8)) == NULL) { FAILURE("sscop: cannot allocate ERAK"); return; } MBUF_APPEND32(m, seqno.sscop_null); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send RS PDU */ static void send_rs(struct sscop *sscop, int resend, struct SSCOP_MBUF_T *uu) { union pdu pdu; union bgn bgn; struct SSCOP_MBUF_T *m; pdu.sscop_null = 0; pdu.sscop_type = PDU_RS; pdu.sscop_ns = resend ? sscop->rs_mr : sscop->vr_mr; bgn.sscop_null = 0; bgn.sscop_bgns = resend ? sscop->rs_sq : sscop->vt_sq; sscop->rs_mr = pdu.sscop_ns; sscop->rs_sq = bgn.sscop_bgns; if(uu) { if((m = MBUF_DUP(uu)) == NULL) { FAILURE("sscop: cannot allocate RS"); return; } pdu.sscop_pl += MBUF_PAD4(m); } else { if((m = MBUF_ALLOC(8)) == NULL) { FAILURE("sscop: cannot allocate RS"); return; } } MBUF_APPEND32(m, bgn.sscop_null); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /* * Send RSAK pdu */ static void send_rsak(struct sscop *sscop) { union pdu pdu; union seqno seqno; struct SSCOP_MBUF_T *m; seqno.sscop_null = 0; pdu.sscop_null = 0; pdu.sscop_type = PDU_RSAK; pdu.sscop_ns = sscop->vr_mr; if((m = MBUF_ALLOC(8)) == NULL) { FAILURE("sscop: cannot allocate RSAK"); return; } MBUF_APPEND32(m, seqno.sscop_null); MBUF_APPEND32(m, pdu.sscop_null); AAL_SEND(sscop, m); } /************************************************************/ /* * P 31; IDLE && AA-ESTABLISH-request * arg is UU data (opt). */ static void sscop_idle_establish_req(struct sscop *sscop, struct sscop_msg *uu) { u_int br = uu->rexmit; SET_UU(uu_bgn, uu); m_clear_transmitter(sscop); sscop->clear_buffers = br; sscop->vt_cc = 1; sscop->vt_sq++; m_initialize_mr(sscop); send_bgn(sscop, sscop->uu_bgn); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_PEND); } /* * P 31: IDLE && BGN PDU * arg is the received PDU (freed). */ static void sscop_idle_bgn(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; union bgn bgn; pdu.sscop_null = MBUF_STRIP32(msg->m); if(sscop->robustness) { bgn.sscop_null = MBUF_STRIP32(msg->m); sscop->vr_sq = bgn.sscop_bgns; } else { if(m_detect_retransmission(sscop, msg)) { send_bgrej(sscop, sscop->uu_bgrej); SSCOP_MSG_FREE(msg); return; } (void)MBUF_STRIP32(msg->m); } sscop->vt_ms = pdu.sscop_ns; sscop_set_state(sscop, SSCOP_IN_PEND); AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); } /* * p 31: IDLE && ENDAK PDU * p 34: OUT_PEND && ENDAK PDU * p 34: OUT_PEND && SD PDU * p 34: OUT_PEND && ERAK PDU * p 34: OUT_PEND && END PDU * p 34: OUT_PEND && STAT PDU * p 34: OUT_PEND && USTAT PDU * p 34: OUT_PEND && POLL PDU * p 36: OUT_PEND && RS PDU * p 36: OUT_PEND && RSAK PDU * p 40: OUTGOING_DISCONNECT_PENDING && SD PDU * p 40: OUTGOING_DISCONNECT_PENDING && BGAK PDU * p 40: OUTGOING_DISCONNECT_PENDING && POLL PDU * p 40: OUTGOING_DISCONNECT_PENDING && STAT PDU * p 40: OUTGOING_DISCONNECT_PENDING && USTAT PDU * p 41: OUTGOING_DISCONNECT_PENDING && ERAK PDU * p 42: OUTGOING_DISCONNECT_PENDING && ER PDU * p 42: OUTGOING_DISCONNECT_PENDING && RS PDU * p 42: OUTGOING_DISCONNECT_PENDING && RSAK PDU * p 43: OUTGOING_RESYNC && ER PDU * p 43: OUTGOING_RESYNC && POLL PDU * p 44: OUTGOING_RESYNC && STAT PDU * p 44: OUTGOING_RESYNC && USTAT PDU * p 45: OUTGOING_RESYNC && BGAK PDU * p 45: OUTGOING_RESYNC && SD PDU * p 45: OUTGOING_RESYNC && ERAK PDU * P 60: READY && BGAK PDU * P 60: READY && ERAK PDU * arg is pdu (freed). */ static void sscop_ignore_pdu(struct sscop *sscop __unused, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); } /* * p 31: IDLE && END PDU * arg is pdu (freed). */ static void sscop_idle_end(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); send_endak(sscop); } /* * p 31: IDLE && ER PDU * arg is pdu (freed). */ static void sscop_idle_er(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'L', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); } /* * p 31: IDLE && BGREJ PDU * arg is pdu (freed). */ static void sscop_idle_bgrej(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'D', 0); FREE_UU(uu_end); } /* * p 32: IDLE && POLL PDU * arg is pdu (freed). */ static void sscop_idle_poll(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'G', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); } /* * p 32: IDLE && SD PDU * arg is pdu (freed). */ static void sscop_idle_sd(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'A', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); } /* * p 32: IDLE && BGAK PDU * arg is pdu (freed). */ static void sscop_idle_bgak(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'C', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); } /* * p 32: IDLE && ERAK PDU * arg is pdu (freed). */ static void sscop_idle_erak(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'M', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); } /* * p 32: IDLE && STAT PDU * arg is pdu (freed). */ static void sscop_idle_stat(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'H', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); } /* * p 32: IDLE && USTAT PDU * arg is pdu (freed). */ static void sscop_idle_ustat(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'I', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); } /* * p 33: IDLE & RS PDU * arg is pdu (freed). */ static void sscop_idle_rs(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'J', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); } /* * p 33: IDLE & RSAK PDU * arg is pdu (freed). */ static void sscop_idle_rsak(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'K', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); } /* * p 33: IDLE && PDU_Q * p XX: OUTPEND && PDU_Q * p 39: IN_PEND && PDU_Q * p 45: OUT_RESYNC_PEND && PDU_Q * p 48: IN_RESYNC_PEND && PDU_Q * no arg */ static void sscop_flush_pduq(struct sscop *sscop __unused, struct sscop_msg *unused __unused) { #if 0 MSGQ_CLEAR(&sscop->xq); #endif } /* * p 34: OUT_PEND && BGAK PDU * arg is pdu (freed). */ static void sscop_outpend_bgak(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); sscop->vt_ms = pdu.sscop_ns; AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_confirm, msg, pdu.sscop_pl, 0); m_initialize_state(sscop); m_set_data_xfer_timers(sscop); sscop_set_state(sscop, SSCOP_READY); } /* * P 34: OUT_PEND && BGREJ PDU */ static void sscop_outpend_bgrej(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, 0); sscop_set_state(sscop, SSCOP_IDLE); } /* * P 35: OUT_PEND && TIMER_CC expiry * no arg */ static void sscop_outpend_tcc(struct sscop *sscop, struct sscop_msg *unused __unused) { if(sscop->vt_cc >= sscop->maxcc) { MAAL_ERROR(sscop, 'O', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } else { sscop->vt_cc++; send_bgn(sscop, sscop->uu_bgn); TIMER_RESTART(sscop, cc); } } /* * P 35: OUT_PEND && RELEASE_REQ * arg is UU */ static void sscop_outpend_release_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_end, uu); TIMER_STOP(sscop, cc); sscop->vt_cc = 1; send_end(sscop, 0, sscop->uu_end); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); } /* * P 36: OUT_PEND && BGN PDU * arg is the received PDU (freed). */ static void sscop_outpend_bgn(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { SSCOP_MSG_FREE(msg); return; } (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); sscop->vt_ms = pdu.sscop_ns; m_initialize_mr(sscop); send_bgak(sscop, sscop->uu_bgak); AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_confirm, msg, pdu.sscop_pl, 0); m_initialize_state(sscop); m_set_data_xfer_timers(sscop); sscop_set_state(sscop, SSCOP_READY); } /* * p 37: IN_PEND && AA-ESTABLISH.response * arg is UU */ static void sscop_inpend_establish_resp(struct sscop *sscop, struct sscop_msg *uu) { u_int br = uu->rexmit; SET_UU(uu_bgak, uu); m_clear_transmitter(sscop); sscop->clear_buffers = br; m_initialize_mr(sscop); send_bgak(sscop, sscop->uu_bgak); m_initialize_state(sscop); m_set_data_xfer_timers(sscop); sscop_set_state(sscop, SSCOP_READY); } /* * p 37: IN_PEND && AA-RELEASE.request * arg is uu. */ static void sscop_inpend_release_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_bgrej, uu); send_bgrej(sscop, sscop->uu_bgrej); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 37: IN_PEND && BGN PDU * arg is pdu. (freed) */ static void sscop_inpend_bgn(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { SSCOP_MSG_FREE(msg); return; } (void)MBUF_STRIP32(msg->m); sscop->vt_ms = pdu.sscop_ns; AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); } /* * p 37: IN_PEND && ER PDU * arg is pdu (freed). */ static void sscop_inpend_er(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'L', 0); SSCOP_MSG_FREE(msg); } /* * p 37: IN_PEND && ENDAK PDU * arg is pdu (freed). */ static void sscop_inpend_endak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'F', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); SSCOP_MSG_FREE(msg); } /* * p 38: IN_PEND && BGAK PDU * arg is pdu (freed). */ static void sscop_inpend_bgak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'C', 0); SSCOP_MSG_FREE(msg); } /* * p 38: IN_PEND && BGREJ PDU * arg is pdu (freed). */ static void sscop_inpend_bgrej(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'D', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); SSCOP_MSG_FREE(msg); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 38: IN_PEND && SD PDU * arg is pdu (freed). */ static void sscop_inpend_sd(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'A', 0); SSCOP_MSG_FREE(msg); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 38: IN_PEND && USTAT PDU * arg is pdu (freed). */ static void sscop_inpend_ustat(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'I', 0); SSCOP_MSG_FREE(msg); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 38: IN_PEND && STAT PDU * arg is pdu (freed). */ static void sscop_inpend_stat(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'H', 0); SSCOP_MSG_FREE(msg); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 38: IN_PEND && POLL PDU * arg is pdu (freed). */ static void sscop_inpend_poll(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'G', 0); SSCOP_MSG_FREE(msg); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 39: IN_PEND && ERAK PDU * arg is pdu (freed). */ static void sscop_inpend_erak(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'M', 0); } /* * p 39: IN_PEND & RS PDU * arg is pdu (freed). */ static void sscop_inpend_rs(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'J', 0); } /* * p 39: IN_PEND & RSAK PDU * arg is pdu (freed). */ static void sscop_inpend_rsak(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'K', 0); } /* * p 39: IN_PEND && END PDU * arg is pdu (freed). * no uui */ static void sscop_inpend_end(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); send_endak(sscop); AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, (u_int)pdu.sscop_s); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 40: OUT_DIS_PEND && SSCOP_ESTABLISH_request * no arg. * no uui. */ static void sscop_outdis_establish_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_bgn, uu); TIMER_STOP(sscop, cc); m_clear_transmitter(sscop); sscop->clear_buffers = 1; sscop->vt_cc = 1; sscop->vt_sq++; m_initialize_mr(sscop); send_bgn(sscop, sscop->uu_bgn); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_PEND); } /* * p 41: OUT_DIS_PEND && END PDU * arg is pdu (freed). */ static void sscop_outdis_end(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); send_endak(sscop); AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_confirm, msg, pdu.sscop_pl, 0); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 41: OUT_DIS_PEND && ENDAK PDU * p 41: OUT_DIS_PEND && BGREJ PDU * arg is pdu (freed) */ static void sscop_outdis_endak(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_confirm, msg, pdu.sscop_pl, 0); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 41: OUT_DIS_PEND && TIMER CC expiry * no arg */ static void sscop_outdis_cc(struct sscop *sscop, struct sscop_msg *unused __unused) { if(sscop->vt_cc >= sscop->maxcc) { MAAL_ERROR(sscop, 'O', 0); AAL_SIG(sscop, SSCOP_RELEASE_confirm); sscop_set_state(sscop, SSCOP_IDLE); } else { sscop->vt_cc++; send_end(sscop, sscop->last_end_src, sscop->uu_end); TIMER_RESTART(sscop, cc); } } /* * p 42: OUT_DIS_PEND && BGN PDU * arg is pdu (freed). */ static void sscop_outdis_bgn(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { FREE_UU(uu_bgak); send_bgak(sscop, NULL); send_end(sscop, sscop->last_end_src, sscop->uu_end); SSCOP_MSG_FREE(msg); } else { (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); sscop->vt_ms = pdu.sscop_ns; AAL_SIG(sscop, SSCOP_RELEASE_confirm); AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); sscop_set_state(sscop, SSCOP_IN_PEND); } } /* * p 43: OUT_RESYNC_PEND && BGN PDU * arg is pdu (freed). */ static void sscop_outsync_bgn(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { send_bgak(sscop, sscop->uu_bgak); send_rs(sscop, 1, sscop->uu_rs); SSCOP_MSG_FREE(msg); } else { (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); sscop->vt_ms = pdu.sscop_ns; AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); sscop_set_state(sscop, SSCOP_IN_PEND); } } /* * p 43: OUT_RESYNC_PEND && ENDAK PDU * arg is pdu (freed). */ static void sscop_outsync_endak(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); TIMER_STOP(sscop, cc); MAAL_ERROR(sscop, 'F', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 43: OUT_RESYNC_PEND && BGREJ PDU * arg is pdu (freed). */ static void sscop_outsync_bgrej(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); TIMER_STOP(sscop, cc); MAAL_ERROR(sscop, 'D', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 43: OUT_RESYNC_PEND && END PDU * arg is pdu (freed). * no UU-data */ static void sscop_outsync_end(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); send_endak(sscop); AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, (u_int)pdu.sscop_s); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 44: OUT_RESYNC && TIMER CC expiry */ static void sscop_outsync_cc(struct sscop *sscop, struct sscop_msg *msg __unused) { if(sscop->vt_cc == sscop->maxcc) { MAAL_ERROR(sscop, 'O', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } else { sscop->vt_cc++; send_rs(sscop, 1, sscop->uu_rs); TIMER_RESTART(sscop, cc); } } /* * p 44: OUT_RESYNC && AA-RELEASE.request * arg is UU */ static void sscop_outsync_release_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_end, uu); TIMER_STOP(sscop, cc); sscop->vt_cc = 1; send_end(sscop, 0, sscop->uu_end); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); } /* * p 45: OUT_RESYNC && RS PDU * arg is pdu (freed). */ static void sscop_outsync_rs(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { SSCOP_MSG_FREE(msg); return; } (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); sscop->vt_ms = pdu.sscop_ns; m_initialize_mr(sscop); send_rsak(sscop); AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_confirm, msg, pdu.sscop_pl, 0); m_initialize_state(sscop); m_set_data_xfer_timers(sscop); sscop_set_state(sscop, SSCOP_READY); } /* * p 45: OUT_RESYNC && RSAK PDU * arg is pdu (freed). */ static void sscop_outsync_rsak(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); SSCOP_MSG_FREE(msg); TIMER_STOP(sscop, cc); sscop->vt_ms = pdu.sscop_ns; AAL_SIG(sscop, SSCOP_RESYNC_confirm); m_initialize_state(sscop); m_set_data_xfer_timers(sscop); sscop_set_state(sscop, SSCOP_READY); } /* * p 46: IN_RESYNC_PEND && AA-RESYNC.response */ static void sscop_insync_sync_resp(struct sscop *sscop, struct sscop_msg *noarg __unused) { m_initialize_mr(sscop); send_rsak(sscop); m_clear_transmitter(sscop); m_initialize_state(sscop); m_set_data_xfer_timers(sscop); sscop_set_state(sscop, SSCOP_READY); } /* * p 46: IN_RESYNC_PEND && AA-RELEASE.request * arg is uu */ static void sscop_insync_release_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_end, uu); sscop->vt_cc = 1; send_end(sscop, 0, sscop->uu_end); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); } /* * p 46: IN_RESYNC_PEND && ENDAK PDU * arg is pdu (freed). */ static void sscop_insync_endak(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'F', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 46: IN_RESYNC_PEND && BGREJ PDU * arg is pdu (freed). */ static void sscop_insync_bgrej(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'D', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 46: IN_RESYNC_PEND && END PDU * arg is pdu (freed). */ static void sscop_insync_end(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); send_endak(sscop); AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, (u_int)pdu.sscop_s); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 47: IN_RESYNC_PEND && ER PDU * arg is pdu (freed). */ static void sscop_insync_er(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'L', 0); } /* * p 47: IN_RESYNC_PEND && BGN PDU * arg is pdu (freed). */ static void sscop_insync_bgn(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { MAAL_ERROR(sscop, 'B', 0); SSCOP_MSG_FREE(msg); return; } (void)MBUF_STRIP32(msg->m); sscop->vt_ms = pdu.sscop_ns; AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); sscop_set_state(sscop, SSCOP_IN_PEND); } /* * p 47: IN_RESYNC_PEND && SD PDU * arg is pdu (freed). */ static void sscop_insync_sd(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'A', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 47: IN_RESYNC_PEND && POLL PDU * arg is pdu (freed). */ static void sscop_insync_poll(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'G', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 47: IN_RESYNC_PEND && STAT PDU * arg is pdu (freed). */ static void sscop_insync_stat(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'H', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 47: IN_RESYNC_PEND && USTAT PDU * arg is pdu (freed). */ static void sscop_insync_ustat(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'I', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 48: IN_RESYNC_PEND && BGAK PDU * arg is pdu (freed). */ static void sscop_insync_bgak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'C', 0); SSCOP_MSG_FREE(msg); } /* * p 48: IN_RESYNC_PEND && ERAK PDU * arg is pdu (freed). */ static void sscop_insync_erak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'M', 0); SSCOP_MSG_FREE(msg); } /* * p 48: IN_RESYNC_PEND && RS PDU * arg is pdu (freed). */ static void sscop_insync_rs(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { SSCOP_MSG_FREE(msg); return; } SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'J', 0); } /* * p 48: IN_RESYNC_PEND && RSAK PDU * arg is pdu (freed). */ static void sscop_insync_rsak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'K', 0); SSCOP_MSG_FREE(msg); } /* * p 49: OUT_REC_PEND && AA-DATA.request * arg is message (queued). */ static void sscop_outrec_userdata(struct sscop *sscop, struct sscop_msg *msg) { if(!sscop->clear_buffers) { MSGQ_APPEND(&sscop->xq, msg); sscop_signal(sscop, SIG_PDU_Q, msg); } else { SSCOP_MSG_FREE(msg); } } /* * p 49: OUT_REC_PEND && BGAK PDU * arg is pdu (freed) */ static void sscop_outrec_bgak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'C', 0); SSCOP_MSG_FREE(msg); } /* * p 49: OUT_REC_PEND && ERAK PDU * arg is pdu (freed) */ static void sscop_outrec_erak(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); sscop->vt_ms = pdu.sscop_ns; m_deliver_data(sscop); AAL_SIG(sscop, SSCOP_RECOVER_indication); sscop_set_state(sscop, SSCOP_REC_PEND); SSCOP_MSG_FREE(msg); } /* * p 49: OUT_REC_PEND && END PDU * arg is pdu (freed) */ static void sscop_outrec_end(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); send_endak(sscop); AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, (u_int)pdu.sscop_s); MSGQ_CLEAR(&sscop->rbuf); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 49: OUT_REC_PEND && ENDAK PDU * arg is pdu (freed) */ static void sscop_outrec_endak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'F', 0); TIMER_STOP(sscop, cc); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); MSGQ_CLEAR(&sscop->rbuf); sscop_set_state(sscop, SSCOP_IDLE); SSCOP_MSG_FREE(msg); } /* * p 49: OUT_REC_PEND && BGREJ PDU * arg is pdu (freed) */ static void sscop_outrec_bgrej(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'D', 0); TIMER_STOP(sscop, cc); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); MSGQ_CLEAR(&sscop->rbuf); sscop_set_state(sscop, SSCOP_IDLE); SSCOP_MSG_FREE(msg); } /* * p 50: OUT_REC_PEND && TIMER CC expiry * no arg. */ static void sscop_outrec_cc(struct sscop *sscop, struct sscop_msg *unused __unused) { if(sscop->vt_cc >= sscop->maxcc) { MAAL_ERROR(sscop, 'O', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); MSGQ_CLEAR(&sscop->rbuf); sscop_set_state(sscop, SSCOP_IDLE); } else { sscop->vt_cc++; send_er(sscop); TIMER_RESTART(sscop, cc); } } /* * p 50: OUT_REC_PEND && SSCOP_RELEASE_request * arg is UU */ static void sscop_outrec_release_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_end, uu); TIMER_STOP(sscop, cc); sscop->vt_cc = 1; send_end(sscop, 0, sscop->uu_end); MSGQ_CLEAR(&sscop->rbuf); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); } /* * p 51: OUT_REC_PEND && AA-RESYNC.request * arg is uu */ static void sscop_outrec_sync_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_rs, uu); TIMER_STOP(sscop, cc); sscop->vt_cc = 1; sscop->vt_sq++; m_initialize_mr(sscop); send_rs(sscop, 0, sscop->uu_rs); m_clear_transmitter(sscop); MSGQ_CLEAR(&sscop->rbuf); TIMER_RESTART(sscop, cc); } /* * p 51: OUT_REC_PEND && BGN PDU * arg is pdu (freed). * no uui */ static void sscop_outrec_bgn(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { MAAL_ERROR(sscop, 'B', 0); SSCOP_MSG_FREE(msg); } else { (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); sscop->vt_ms = pdu.sscop_ns; AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); MSGQ_CLEAR(&sscop->rbuf); sscop_set_state(sscop, SSCOP_IN_PEND); } } /* * p 51: OUT_REC_PEND && ER PDU * arg is pdu (freed). */ static void sscop_outrec_er(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { MAAL_ERROR(sscop, 'L', 0); } else { TIMER_STOP(sscop, cc); sscop->vt_ms = pdu.sscop_ns; m_initialize_mr(sscop); send_erak(sscop); m_deliver_data(sscop); AAL_SIG(sscop, SSCOP_RECOVER_indication); sscop_set_state(sscop, SSCOP_REC_PEND); } SSCOP_MSG_FREE(msg); } /* * p 52: OUT_REC_PEND && SD PDU queued * no arg. */ static void sscop_outrec_pduq(struct sscop *sscop, struct sscop_msg *msg) { sscop_save_signal(sscop, SIG_PDU_Q, msg); } /* * p 52: OUT_REC_PEND && RSAK PDU * arg is pdu (freed). */ static void sscop_outrec_rsak(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'K', 0); } /* * p 52: OUT_REC_PEND && RS PDU * arg is pdu (freed). */ static void sscop_outrec_rs(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'J', 0); return; } (void)MBUF_STRIP32(msg->m); TIMER_STOP(sscop, cc); sscop->vt_ms = pdu.sscop_ns; AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0); MSGQ_CLEAR(&sscop->rbuf); sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND); } /* * p 53: REC_PEND && BGAK PDU * arg is pdu (freed) */ static void sscop_rec_bgak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'C', 0); SSCOP_MSG_FREE(msg); } /* * p 53: REC_PEND && END PDU * arg is pdu (freed) * no uui */ static void sscop_rec_end(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); send_endak(sscop); AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, (u_int)pdu.sscop_s); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 53: REC_PEND && ENDAK PDU * arg is pdu (freed) */ static void sscop_rec_endak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'F', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); SSCOP_MSG_FREE(msg); } /* * p 53: REC_PEND && BGREJ PDU * arg is pdu (freed) */ static void sscop_rec_bgrej(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'D', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); SSCOP_MSG_FREE(msg); } /* * p 54: REC_PEND && RELEASE * arg is UU */ static void sscop_rec_release_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_end, uu); sscop->vt_cc = 1; send_end(sscop, 0, sscop->uu_end); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); } /* * p 54: REC_PEND && RSAK PDU * arg is pdu (freed). */ static void sscop_rec_rsak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'K', 0); SSCOP_MSG_FREE(msg); } /* * p 54: REC_PEND && RS PDU * arg is pdu (freed). */ static void sscop_rec_rs(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'J', 0); return; } (void)MBUF_STRIP32(msg->m); sscop->vt_ms = pdu.sscop_ns; AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0); sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND); } /* * p 54: REC_PEND && RECOVER response * no arg */ static void sscop_rec_recover(struct sscop *sscop, struct sscop_msg *unused __unused) { if(!sscop->clear_buffers) { MSGQ_CLEAR(&sscop->xbuf); } m_initialize_state(sscop); m_set_data_xfer_timers(sscop); sscop_set_state(sscop, SSCOP_READY); } /* * p 54: REC_PEND && RESYNC request * arg is uu */ static void sscop_rec_sync_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_rs, uu); m_clear_transmitter(sscop); sscop->vt_cc = 1; sscop->vt_sq++; m_initialize_mr(sscop); send_rs(sscop, 0, sscop->uu_rs); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND); } /* * p 55: REC_PEND && SD PDU queued * no arg */ static void sscop_rec_pduq(struct sscop *sscop, struct sscop_msg *msg) { sscop_save_signal(sscop, SIG_PDU_Q, msg); } /* * p 55: REC_PEND && ER PDU * arg is pdu (freed). */ static void sscop_rec_er(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { send_erak(sscop); } else { MAAL_ERROR(sscop, 'L', 0); } SSCOP_MSG_FREE(msg); } /* * p 55: REC_PEND && BGN PDU * arg is pdu (freed) * no uui */ static void sscop_rec_bgn(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { MAAL_ERROR(sscop, 'B', 0); SSCOP_MSG_FREE(msg); return; } (void)MBUF_STRIP32(msg->m); sscop->vt_ms = pdu.sscop_ns; AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); sscop_set_state(sscop, SSCOP_IN_PEND); } /* * p 55: REC_PEND && STAT PDU * arg is pdu (freed) */ static void sscop_rec_stat(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'H', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); SSCOP_MSG_FREE(msg); } /* * p 55: REC_PEND && USTAT PDU * arg is pdu (freed) */ static void sscop_rec_ustat(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'I', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); sscop_set_state(sscop, SSCOP_IDLE); SSCOP_MSG_FREE(msg); } /* * p 56: IN_REC_PEND && AA-RECOVER.response * no arg */ static void sscop_inrec_recover(struct sscop *sscop, struct sscop_msg *unused __unused) { if(!sscop->clear_buffers) { MSGQ_CLEAR(&sscop->xbuf); } m_initialize_mr(sscop); send_erak(sscop); m_initialize_state(sscop); m_set_data_xfer_timers(sscop); sscop_set_state(sscop, SSCOP_READY); } /* * p 56: IN_REC_PEND && SD PDU queued * no arg */ static void sscop_inrec_pduq(struct sscop *sscop, struct sscop_msg *msg) { sscop_save_signal(sscop, SIG_PDU_Q, msg); } /* * p 56: IN_REC_PEND && AA-RELEASE.request * arg is UU */ static void sscop_inrec_release_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_end, uu); sscop->vt_cc = 1; send_end(sscop, 0, sscop->uu_end); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); } /* * p 56: IN_REC_PEND && END PDU * arg is pdu (freed). * no uui */ static void sscop_inrec_end(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); send_endak(sscop); AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, (u_int)pdu.sscop_s); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 56: IN_REC_PEND && RESYNC_REQ */ static void sscop_inrec_sync_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_rs, uu); m_clear_transmitter(sscop); sscop->vt_cc = 1; sscop->vt_sq++; m_initialize_mr(sscop); send_rs(sscop, 0, sscop->uu_rs); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND); } /* * p 57: IN_REC_PEND && ENDAK PDU * arg is pdu (freed) */ static void sscop_inrec_endak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'F', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); SSCOP_MSG_FREE(msg); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 57: IN_REC_PEND && BGREJ PDU * arg is pdu (freed) */ static void sscop_inrec_bgrej(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'D', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); SSCOP_MSG_FREE(msg); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 57: IN_REC_PEND && USTAT PDU * arg is pdu (freed) */ static void sscop_inrec_ustat(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'I', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); SSCOP_MSG_FREE(msg); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 57: IN_REC_PEND && STAT PDU * arg is pdu (freed) */ static void sscop_inrec_stat(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'H', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); SSCOP_MSG_FREE(msg); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 57: IN_REC_PEND && POLL PDU * arg is pdu (freed) */ static void sscop_inrec_poll(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'G', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); SSCOP_MSG_FREE(msg); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 57: IN_REC_PEND && SD PDU * arg is pdu (freed) */ static void sscop_inrec_sd(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'A', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); SSCOP_MSG_FREE(msg); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 58: IN_REC_PEND && RSAK PDU * arg is pdu (freed). */ static void sscop_inrec_rsak(struct sscop *sscop, struct sscop_msg *msg) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'K', 0); } /* * p 58: IN_REC_PEND && RS PDU * arg is pdu (freed). */ static void sscop_inrec_rs(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { SSCOP_MSG_FREE(msg); MAAL_ERROR(sscop, 'J', 0); return; } (void)MBUF_STRIP32(msg->m); sscop->vt_ms = pdu.sscop_ns; AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0); sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND); } /* * p 59: IN_REC_PEND && ER PDU * arg is pdu (freed) */ static void sscop_inrec_er(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(!m_detect_retransmission(sscop, msg)) { MAAL_ERROR(sscop, 'L', 0); } SSCOP_MSG_FREE(msg); } /* * p 59: IN_REC_PEND && BGN PDU * arg is pdu (freed). * no uui */ static void sscop_inrec_bgn(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { MAAL_ERROR(sscop, 'B', 0); SSCOP_MSG_FREE(msg); return; } (void)MBUF_STRIP32(msg->m); sscop->vt_ms = pdu.sscop_ns; AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); sscop_set_state(sscop, SSCOP_IN_PEND); } /* * p 59: IN_REC_PEND && BGAK PDU * arg is pdu (freed) * no uui */ static void sscop_inrec_bgak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'C', 0); SSCOP_MSG_FREE(msg); } /* * p 59: IN_REC_PEND && ERAK PDU * arg is pdu (freed) * no uui */ static void sscop_inrec_erak(struct sscop *sscop, struct sscop_msg *msg) { MAAL_ERROR(sscop, 'M', 0); SSCOP_MSG_FREE(msg); } /* * p 60: READY && RESYNC request * arg is UU */ static void sscop_ready_sync_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_rs, uu); m_reset_data_xfer_timers(sscop); sscop->vt_cc = 1; sscop->vt_sq++; m_initialize_mr(sscop); send_rs(sscop, 0, sscop->uu_rs); m_release_buffers(sscop); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_RESYNC_PEND); } /* * p 60: READY && AA-RELEASE.request * arg is uu. */ static void sscop_ready_release_req(struct sscop *sscop, struct sscop_msg *uu) { SET_UU(uu_end, uu); m_reset_data_xfer_timers(sscop); sscop->vt_cc = 1; send_end(sscop, 0, sscop->uu_end); m_prepare_retrieval(sscop); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_DIS_PEND); } /* * p 61: READY && ER PDU * arg is pdu (freed). */ static void sscop_ready_er(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { TIMER_RESTART(sscop, nr); send_erak(sscop); } else { m_reset_data_xfer_timers(sscop); sscop->vt_ms = pdu.sscop_ns; m_prepare_recovery(sscop); m_deliver_data(sscop); AAL_SIG(sscop, SSCOP_RECOVER_indication); sscop_set_state(sscop, SSCOP_IN_REC_PEND); } SSCOP_MSG_FREE(msg); } /* * p 61: READY && BGN PDU * arg is pdu (freed) */ static void sscop_ready_bgn(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { TIMER_RESTART(sscop, nr); send_bgak(sscop, sscop->uu_bgak); SSCOP_MSG_FREE(msg); return; } (void)MBUF_STRIP32(msg->m); m_reset_data_xfer_timers(sscop); sscop->vt_ms = pdu.sscop_ns; AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 0); AAL_UU_SIGNAL(sscop, SSCOP_ESTABLISH_indication, msg, pdu.sscop_pl, 0); m_prepare_retrieval(sscop); sscop_set_state(sscop, SSCOP_IN_PEND); } /* * p 62: READY && ENDAK PDU * arg is pdu (freed) */ static void sscop_ready_endak(struct sscop *sscop, struct sscop_msg *msg) { m_reset_data_xfer_timers(sscop); MAAL_ERROR(sscop, 'F', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); m_prepare_retrieval(sscop); SSCOP_MSG_FREE(msg); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 62: READY && BGREJ PDU * arg is pdu (freed) */ static void sscop_ready_bgrej(struct sscop *sscop, struct sscop_msg *msg) { m_reset_data_xfer_timers(sscop); MAAL_ERROR(sscop, 'D', 0); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); m_prepare_retrieval(sscop); SSCOP_MSG_FREE(msg); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 62: READY && RS PDU * arg is pdu (freed) */ static void sscop_ready_rs(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); if(m_detect_retransmission(sscop, msg)) { SSCOP_MSG_FREE(msg); TIMER_RESTART(sscop, nr); send_rsak(sscop); return; } (void)MBUF_STRIP32(msg->m); m_reset_data_xfer_timers(sscop); sscop->vt_ms = pdu.sscop_ns; AAL_UU_SIGNAL(sscop, SSCOP_RESYNC_indication, msg, pdu.sscop_pl, 0); m_prepare_retrieval(sscop); sscop_set_state(sscop, SSCOP_IN_RESYNC_PEND); } /* * p 62: READY && END PDU * arg is pdu (freed) */ static void sscop_ready_end(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); (void)MBUF_STRIP32(msg->m); m_reset_data_xfer_timers(sscop); send_endak(sscop); AAL_UU_SIGNAL(sscop, SSCOP_RELEASE_indication, msg, pdu.sscop_pl, (u_int)pdu.sscop_s); m_prepare_retrieval(sscop); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 63: READY && POLL expiry */ static void sscop_ready_tpoll(struct sscop *sscop, struct sscop_msg *unused __unused) { sscop->vt_ps++; send_poll(sscop); sscop->vt_pd = 0; m_set_poll_timer(sscop); } /* * p 63: READY && KEEP_ALIVE expiry */ static void sscop_ready_tka(struct sscop *sscop, struct sscop_msg *unused __unused) { sscop->vt_ps++; send_poll(sscop); sscop->vt_pd = 0; m_set_poll_timer(sscop); } /* * p 63: READY && IDLE expiry */ static void sscop_ready_tidle(struct sscop *sscop, struct sscop_msg *unused __unused) { TIMER_RESTART(sscop, nr); sscop->vt_ps++; send_poll(sscop); sscop->vt_pd = 0; m_set_poll_timer(sscop); } /* * p 63: READY && NO_RESPONSE expiry * no arg */ static void sscop_ready_nr(struct sscop *sscop, struct sscop_msg *unused __unused) { m_reset_data_xfer_timers(sscop); MAAL_ERROR(sscop, 'P', 0); FREE_UU(uu_end); send_end(sscop, 1, NULL); AAL_DATA(sscop, SSCOP_RELEASE_indication, NULL, 1); m_prepare_retrieval(sscop); sscop_set_state(sscop, SSCOP_IDLE); } /* * p 63: READY && AA-DATA.request * arg is message (queued). */ static void sscop_ready_userdata(struct sscop *sscop, struct sscop_msg *msg) { MSGQ_APPEND(&sscop->xq, msg); sscop_signal(sscop, SIG_PDU_Q, msg); } /* * p 64: READY && SD PDU queued up * arg is unused. */ static void sscop_ready_pduq(struct sscop *sscop, struct sscop_msg *unused __unused) { struct sscop_msg *msg; if(sscop->rxq != 0) { TAILQ_FOREACH(msg, &sscop->xbuf, link) if(msg->rexmit) break; ASSERT(msg != NULL); msg->rexmit = 0; sscop->rxq--; send_sd(sscop, msg->m, msg->seqno); msg->poll_seqno = sscop->vt_ps; if(sscop->poll_after_rex && sscop->rxq == 0) goto poll; /* -> A */ else goto maybe_poll; /* -> B */ } if(MSGQ_EMPTY(&sscop->xq)) return; if(sscop->vt_s >= sscop->vt_ms) { /* Send windows closed */ TIMER_STOP(sscop, idle); TIMER_RESTART(sscop, nr); goto poll; /* -> A */ } else { msg = MSGQ_GET(&sscop->xq); msg->seqno = sscop->vt_s; send_sd(sscop, msg->m, msg->seqno); msg->poll_seqno = sscop->vt_ps; sscop->vt_s++; MSGQ_APPEND(&sscop->xbuf, msg); goto maybe_poll; /* -> B */ } /* * p 65: Poll handling */ maybe_poll: /* label B */ sscop->vt_pd++; if(TIMER_ISACT(sscop, poll)) { if(sscop->vt_pd < sscop->maxpd) return; } else { if(TIMER_ISACT(sscop, idle)) { TIMER_STOP(sscop, idle); TIMER_RESTART(sscop, nr); } else { TIMER_STOP(sscop, ka); } if(sscop->vt_pd < sscop->maxpd) { TIMER_RESTART(sscop, poll); return; } } poll: /* label A */ sscop->vt_ps++; send_poll(sscop); sscop->vt_pd = 0; TIMER_RESTART(sscop, poll); } /* * p 67: common recovery start */ static void sscop_recover(struct sscop *sscop) { sscop->vt_cc = 1; sscop->vt_sq++; m_initialize_mr(sscop); send_er(sscop); m_prepare_recovery(sscop); TIMER_RESTART(sscop, cc); sscop_set_state(sscop, SSCOP_OUT_REC_PEND); } /* * p 66: READY && SD PDU * arg is received message. */ static void sscop_ready_sd(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; u_int sn; pdu.sscop_null = MBUF_STRIP32(msg->m); msg->seqno = pdu.sscop_ns; /* Fix padding */ MBUF_UNPAD(msg->m, pdu.sscop_pl); if(msg->seqno >= sscop->vr_mr) { /* message outside window */ if(sscop->vr_h < sscop->vr_mr) { send_ustat(sscop, sscop->vr_h, sscop->vr_mr, -1); sscop->vr_h = sscop->vr_mr; } SSCOP_MSG_FREE(msg); return; } if(msg->seqno == sscop->vr_r) { if(msg->seqno == sscop->vr_h) { sscop->vr_r = msg->seqno + 1; sscop->vr_h = msg->seqno + 1; AAL_DATA(sscop, SSCOP_DATA_indication, msg->m, msg->seqno); msg->m = NULL; SSCOP_MSG_FREE(msg); return; } for(;;) { AAL_DATA(sscop, SSCOP_DATA_indication, msg->m, msg->seqno); msg->m = NULL; SSCOP_MSG_FREE(msg); sscop->vr_r++; if((msg = MSGQ_PEEK(&sscop->rbuf)) == NULL) break; sn = msg->seqno; ASSERT(sn >= sscop->vr_r); if(sn != sscop->vr_r) break; msg = MSGQ_GET(&sscop->rbuf); } return; } /* Messages were lost */ /* XXX Flow control */ if(msg->seqno == sscop->vr_h) { QINSERT(&sscop->rbuf, msg); sscop->vr_h++; return; } if(sscop->vr_h < msg->seqno) { QINSERT(&sscop->rbuf, msg); send_ustat(sscop, sscop->vr_h, msg->seqno, -1); sscop->vr_h = msg->seqno + 1; return; } if(QFIND(&sscop->rbuf, msg->seqno) == NULL) { QINSERT(&sscop->rbuf, msg); return; } /* error: start recovery */ SSCOP_MSG_FREE(msg); m_reset_data_xfer_timers(sscop); MAAL_ERROR(sscop, 'Q', 0); sscop_recover(sscop); } /* * p 67: READY && POLL PDU */ static void sscop_ready_poll(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; union seqno seqno; u_int sn, nps; struct SSCOP_MBUF_T *m; pdu.sscop_null = MBUF_STRIP32(msg->m); seqno.sscop_null = MBUF_STRIP32(msg->m); if((u_int)pdu.sscop_ns < sscop->vr_h) { SSCOP_MSG_FREE(msg); m_reset_data_xfer_timers(sscop); MAAL_ERROR(sscop, 'Q', 0); sscop_recover(sscop); return; } nps = seqno.sscop_n; if((u_int)pdu.sscop_ns > sscop->vr_mr) sscop->vr_h = sscop->vr_mr; else sscop->vr_h = pdu.sscop_ns; SSCOP_MSG_FREE(msg); /* build stat pdu */ if((m = MBUF_ALLOC(sscop->maxstat * 4 + 12)) == NULL) { FAILURE("sscop: cannot allocate STAT"); return; } sn = sscop->vr_r; while(sn != sscop->vr_h) { /* loop through burst we already have */ for(;;) { if(sn >= sscop->vr_h) { seqno.sscop_null = 0; seqno.sscop_n = sn; MBUF_APPEND32(m, seqno.sscop_null); goto out; } if(QFIND(&sscop->rbuf, sn) == NULL) break; sn++; } /* start of a hole */ seqno.sscop_null = 0; seqno.sscop_n = sn; MBUF_APPEND32(m, seqno.sscop_null); if(MBUF_LEN(m)/4 >= sscop->maxstat) { send_stat(sscop, nps, m); if((m = MBUF_ALLOC(sscop->maxstat * 4 + 12)) == NULL) { FAILURE("sscop: cannot allocate STAT"); return; } seqno.sscop_null = 0; seqno.sscop_n = sn; MBUF_APPEND32(m, seqno.sscop_null); } do { sn++; } while(sn < sscop->vr_h && !QFIND(&sscop->rbuf, sn)); seqno.sscop_null = 0; seqno.sscop_n = sn; MBUF_APPEND32(m, seqno.sscop_null); } out: send_stat(sscop, nps, m); } /* * p 69: READY && USTAT PDU * arg is msg (freed) */ static void sscop_ready_ustat(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; union seqno nmr, sq1, sq2; u_int cnt; pdu.sscop_null = MBUF_STRIP32(msg->m); nmr.sscop_null = MBUF_STRIP32(msg->m); sq2.sscop_null = MBUF_STRIP32(msg->m); sq1.sscop_null = MBUF_STRIP32(msg->m); SSCOP_MSG_FREE(msg); cnt = sq1.sscop_n - sq2.sscop_n; if((u_int)pdu.sscop_ns < sscop->vt_a || (u_int)pdu.sscop_ns >= sscop->vt_s) { VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, "USTAT: N(R) outside VT(A)...VT(S)-1: N(R)=%u VT(A)=%u " "VT(S)=%u", (u_int)pdu.sscop_ns, sscop->vt_a, sscop->vt_s)); goto err_f; } /* Acknowledge all messages between VT(A) and N(R)-1. N(R) is the new * next in sequence-SD-number of the receiver and means, it has all * messages below N(R). Remove all message below N(R) from the * transmission buffer. It may already be removed because of an * earlier selective ACK in a STAT message. */ while((msg = MSGQ_PEEK(&sscop->xbuf)) != NULL && msg->seqno < (u_int)pdu.sscop_ns) { ASSERT(msg->seqno >= sscop->vt_a); MSGQ_REMOVE(&sscop->xbuf, msg); SSCOP_MSG_FREE(msg); } /* Update the in-sequence acknowledge and the send window */ sscop->vt_a = pdu.sscop_ns; sscop->vt_ms = nmr.sscop_n; /* check, that the range of requested re-transmissions is between * the in-sequence-ack and the highest up-to-now transmitted SD */ if(sq1.sscop_n >= sq2.sscop_n || (u_int)sq1.sscop_n < sscop->vt_a || (u_int)sq2.sscop_n >= sscop->vt_s) { VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, "USTAT: seq1 or seq2 outside VT(A)...VT(S)-1 or seq1>=seq2:" " seq1=%u seq2=%u VT(A)=%u VT(S)=%u", sq1.sscop_n, sq2.sscop_n, sscop->vt_a, sscop->vt_s)); goto err_f; } /* * Retransmit all messages from seq1 to seq2-1 */ do { /* * The message may not be in the transmit buffer if it was * already acked by a STAT. This means, the receiver is * confused. */ if((msg = QFIND(&sscop->xbuf, sq1.sscop_n)) == NULL) { VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, "USTAT: message %u not found in xmit buffer", sq1.sscop_n)); goto err_f; } /* * If it is not yet in the re-transmission queue, put it there */ if(!msg->rexmit) { msg->rexmit = 1; sscop->rxq++; sscop_signal(sscop, SIG_PDU_Q, msg); } sq1.sscop_n++; } while(sq1.sscop_n != sq2.sscop_n); /* * report the re-transmission to the management */ MAAL_ERROR(sscop, 'V', cnt); return; err_f: m_reset_data_xfer_timers(sscop); MAAL_ERROR(sscop, 'T', 0); sscop_recover(sscop); } /* * p 70: READY && STAT PDU * arg is msg (freed). */ static void sscop_ready_stat(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; union seqno nps, nmr; u_int len, seq1, seq2, cnt; struct sscop_msg *m; pdu.sscop_null = MBUF_STRIP32(msg->m); nmr.sscop_null = MBUF_STRIP32(msg->m); nps.sscop_null = MBUF_STRIP32(msg->m); len = MBUF_LEN(msg->m) / 4; if((u_int)nps.sscop_n < sscop->vt_pa || (u_int)nps.sscop_n > sscop->vt_ps) { SSCOP_MSG_FREE(msg); m_reset_data_xfer_timers(sscop); MAAL_ERROR(sscop, 'R', 0); sscop_recover(sscop); return; } if((u_int)pdu.sscop_ns < sscop->vt_a || (u_int)pdu.sscop_ns > sscop->vt_s) { /* * The in-sequence acknowledge, i.e. the receivers's next * expected in-sequence msg is outside the window between * the transmitters in-sequence ack and highest seqno - * the receiver seems to be confused. */ VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, "STAT: N(R) outside VT(A)...VT(S)-1: N(R)=%u VT(A)=%u " "VT(S)=%u", (u_int)pdu.sscop_ns, sscop->vt_a, sscop->vt_s)); err_H: SSCOP_MSG_FREE(msg); m_reset_data_xfer_timers(sscop); MAAL_ERROR(sscop, 'S', 0); sscop_recover(sscop); return; } /* Acknowledge all messages between VT(A) and N(R)-1. N(R) is the new * next in sequence-SD-number of the receiver and means, it has all * messages below N(R). Remove all message below N(R) from the * transmission buffer. It may already be removed because of an * earlier selective ACK in a STAT message. */ while((m = MSGQ_PEEK(&sscop->xbuf)) != NULL && m->seqno < (u_int)pdu.sscop_ns) { ASSERT(m->seqno >= sscop->vt_a); MSGQ_REMOVE(&sscop->xbuf, m); SSCOP_MSG_FREE(m); } /* * Update in-sequence ack, poll-ack and send window. */ sscop->vt_a = pdu.sscop_ns; sscop->vt_pa = nps.sscop_n; sscop->vt_ms = nmr.sscop_n; cnt = 0; if(len > 1) { seq1 = MBUF_GET32(msg->m); len--; if(seq1 >= sscop->vt_s) { VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, "STAT: seq1 >= VT(S): seq1=%u VT(S)=%u", seq1, sscop->vt_s)); goto err_H; } for(;;) { seq2 = MBUF_GET32(msg->m); len--; if(seq1 >= seq2 || seq2 > sscop->vt_s) { VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, "STAT: seq1 >= seq2 or " "seq2 > VT(S): seq1=%u seq2=%u VT(S)=%u", seq1, seq2, sscop->vt_s)); goto err_H; } do { /* * The receiver requests the re-transmission * of some message, but has acknowledged it * already in an earlier STAT (it isn't in the * transmitt buffer anymore). */ if((m = QFIND(&sscop->xbuf, seq1)) == NULL) { VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, "STAT: message" " %u not found in xmit buffer", seq1)); goto err_H; } if(m->poll_seqno < (u_int)nps.sscop_n && (u_int)nps.sscop_n <= sscop->vt_ps) if(!m->rexmit) { m->rexmit = 1; sscop->rxq++; cnt++; sscop_signal(sscop, SIG_PDU_Q, msg); } } while(++seq1 < seq2); if(len == 0) break; seq2 = MBUF_GET32(msg->m); len--; if(seq1 >= seq2 || seq2 > sscop->vt_s) { VERBERR(sscop, SSCOP_DBG_ERR, (sscop, sscop->aarg, "STAT: seq1 >= seq2 or " "seq2 > VT(S): seq1=%u seq2=%u VT(S)=%u", seq1, seq2, sscop->vt_s)); goto err_H; } /* OK now the sucessful transmitted messages. Note, that * some messages may already be out of the buffer because * of earlier STATS */ do { if(sscop->clear_buffers) { if((m = QFIND(&sscop->xbuf, seq1)) != NULL) { MSGQ_REMOVE(&sscop->xbuf, m); SSCOP_MSG_FREE(m); } } } while(++seq1 != seq2); if(len == 0) break; } MAAL_ERROR(sscop, 'V', cnt); } SSCOP_MSG_FREE(msg); /* label L: */ if(sscop->vt_s >= sscop->vt_ms) { /* * The receiver has closed the window: report to management */ if(sscop->credit) { sscop->credit = 0; MAAL_ERROR(sscop, 'W', 0); } } else if(!sscop->credit) { /* * The window was forcefully closed above, but * now re-opened. Report to management. */ sscop->credit = 1; MAAL_ERROR(sscop, 'X', 0); } if(TIMER_ISACT(sscop, poll)) { TIMER_RESTART(sscop, nr); } else if(!TIMER_ISACT(sscop, idle)) { TIMER_STOP(sscop, ka); TIMER_STOP(sscop, nr); TIMER_RESTART(sscop, idle); } } /* * P. 73: any state & UDATA_REQUEST * arg is pdu (queued) */ static void sscop_udata_req(struct sscop *sscop, struct sscop_msg *msg) { MSGQ_APPEND(&sscop->uxq, msg); sscop_signal(sscop, SIG_UPDU_Q, msg); } /* * P. 73: any state & MDATA_REQUEST * arg is pdu (queued) */ static void sscop_mdata_req(struct sscop *sscop, struct sscop_msg *msg) { MSGQ_APPEND(&sscop->mxq, msg); sscop_signal(sscop, SIG_MPDU_Q, msg); } /* * P. 74: any state & UDATA queued * no arg. */ static void sscop_upduq(struct sscop *sscop, struct sscop_msg *unused __unused) { struct sscop_msg *msg; if(sscop->ll_busy) return; while((msg = MSGQ_GET(&sscop->uxq)) != NULL) { send_ud(sscop, msg->m); msg->m = NULL; SSCOP_MSG_FREE(msg); } } /* * P. 74: any state & MDATA queued * no arg. */ static void sscop_mpduq(struct sscop *sscop, struct sscop_msg *unused __unused) { struct sscop_msg *msg; if(sscop->ll_busy) return; while((msg = MSGQ_GET(&sscop->mxq)) != NULL) { send_md(sscop, msg->m); msg->m = NULL; SSCOP_MSG_FREE(msg); } } /* * p 73: MD PDU * arg is PDU */ static void sscop_md(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); MBUF_UNPAD(msg->m, pdu.sscop_pl); MAAL_DATA(sscop, msg->m); msg->m = NULL; SSCOP_MSG_FREE(msg); } /* * p 73: UD PDU * arg is PDU */ static void sscop_ud(struct sscop *sscop, struct sscop_msg *msg) { union pdu pdu; pdu.sscop_null = MBUF_STRIP32(msg->m); MBUF_UNPAD(msg->m, pdu.sscop_pl); AAL_DATA(sscop, SSCOP_UDATA_indication, msg->m, 0); msg->m = NULL; SSCOP_MSG_FREE(msg); } /* * p 33: IDLE & RETRIEVE * p 39: IN_PEND & RETRIEVE * p 42: OUT_DIS_PEND & RETRIEVE * p 48: IN_RESYNC_PEND & RETRIEVE * p 53: REC_PEND & RETRIEVE * p 58: IN_REC_PEND & RETRIEVE */ static void sscop_retrieve(struct sscop *sscop, struct sscop_msg *msg) { m_data_retrieval(sscop, msg->rexmit); SSCOP_MSG_FREE(msg); } /************************************************************/ /* * GENERAL EVENT HANDLING */ /* * State/event matrix. * * Entries marked with Z are not specified in Q.2110, but are added for * the sake of stability. */ static struct { void (*func)(struct sscop *, struct sscop_msg *); int (*cond)(struct sscop *); } state_matrix[SSCOP_NSTATES][SIG_NUM] = { /* SSCOP_IDLE */ { /* SIG_BGN */ { sscop_idle_bgn, NULL }, /* SIG_BGAK */ { sscop_idle_bgak, NULL }, /* SIG_END */ { sscop_idle_end, NULL }, /* SIG_ENDAK */ { sscop_ignore_pdu, NULL }, /* SIG_RS */ { sscop_idle_rs, NULL }, /* SIG_RSAK */ { sscop_idle_rsak, NULL }, /* SIG_BGREJ */ { sscop_idle_bgrej, NULL }, /* SIG_SD */ { sscop_idle_sd, NULL }, /* SIG_ER */ { sscop_idle_er, NULL }, /* SIG_POLL */ { sscop_idle_poll, NULL }, /* SIG_STAT */ { sscop_idle_stat, NULL }, /* SIG_USTAT */ { sscop_idle_ustat, NULL }, /* SIG_UD */ { sscop_ud, NULL }, /* SIG_MD */ { sscop_md, NULL }, /* SIG_ERAK */ { sscop_idle_erak, NULL }, /* SIG_T_CC */ { NULL, NULL }, /* SIG_T_POLL */ { NULL, NULL }, /* SIG_T_KA */ { NULL, NULL }, /* SIG_T_NR */ { NULL, NULL }, /* SIG_T_IDLE */ { NULL, NULL }, /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, /* SIG_USER_DATA */ { NULL, NULL }, /* SIG_ESTAB_REQ */ { sscop_idle_establish_req, NULL }, /* SIG_ESTAB_RESP */ { NULL, NULL }, /* SIG_RELEASE_REQ */ { NULL, NULL }, /* SIG_RECOVER */ { NULL, NULL }, /* SIG_SYNC_REQ */ { NULL, NULL }, /* SIG_SYNC_RESP */ { NULL, NULL }, /* SIG_UDATA */ { sscop_udata_req, NULL }, /* SIG_MDATA */ { sscop_mdata_req, NULL }, /* SIG_UPDU_Q */ { sscop_upduq, NULL }, /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, }, /* SSCOP_OUT_PEND */ { /* SIG_BGN */ { sscop_outpend_bgn, NULL }, /* SIG_BGAK */ { sscop_outpend_bgak, NULL }, /* SIG_END */ { sscop_ignore_pdu, NULL }, /* SIG_ENDAK */ { sscop_ignore_pdu, NULL }, /* SIG_RS */ { sscop_ignore_pdu, NULL }, /* SIG_RSAK */ { sscop_ignore_pdu, NULL }, /* SIG_BGREJ */ { sscop_outpend_bgrej, NULL }, /* SIG_SD */ { sscop_ignore_pdu, NULL }, /* SIG_ER */ { sscop_ignore_pdu, NULL }, /* SIG_POLL */ { sscop_ignore_pdu, NULL }, /* SIG_STAT */ { sscop_ignore_pdu, NULL }, /* SIG_USTAT */ { sscop_ignore_pdu, NULL }, /* SIG_UD */ { sscop_ud, NULL }, /* SIG_MD */ { sscop_md, NULL }, /* SIG_ERAK */ { sscop_ignore_pdu, NULL }, /* SIG_T_CC */ { sscop_outpend_tcc, NULL }, /* SIG_T_POLL */ { NULL, NULL }, /* SIG_T_KA */ { NULL, NULL }, /* SIG_T_NR */ { NULL, NULL }, /* SIG_T_IDLE */ { NULL, NULL }, /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, /* SIG_USER_DATA */ { NULL, NULL }, /* SIG_ESTAB_REQ */ { NULL, NULL }, /* SIG_ESTAB_RESP */ { NULL, NULL }, /* SIG_RELEASE_REQ */ { sscop_outpend_release_req, NULL }, /* SIG_RECOVER */ { NULL, NULL }, /* SIG_SYNC_REQ */ { NULL, NULL }, /* SIG_SYNC_RESP */ { NULL, NULL }, /* SIG_UDATA */ { sscop_udata_req, NULL }, /* SIG_MDATA */ { sscop_mdata_req, NULL }, /* SIG_UPDU_Q */ { sscop_upduq, NULL }, /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, /* SIG_RETRIEVE */ { NULL, NULL }, }, /* SSCOP_IN_PEND */ { /* SIG_BGN */ { sscop_inpend_bgn, NULL }, /* SIG_BGAK */ { sscop_inpend_bgak, NULL }, /* SIG_END */ { sscop_inpend_end, NULL }, /* SIG_ENDAK */ { sscop_inpend_endak, NULL }, /* SIG_RS */ { sscop_inpend_rs, NULL }, /* SIG_RSAK */ { sscop_inpend_rsak, NULL }, /* SIG_BGREJ */ { sscop_inpend_bgrej, NULL }, /* SIG_SD */ { sscop_inpend_sd, NULL }, /* SIG_ER */ { sscop_inpend_er, NULL }, /* SIG_POLL */ { sscop_inpend_poll, NULL }, /* SIG_STAT */ { sscop_inpend_stat, NULL }, /* SIG_USTAT */ { sscop_inpend_ustat, NULL }, /* SIG_UD */ { sscop_ud, NULL }, /* SIG_MD */ { sscop_md, NULL }, /* SIG_ERAK */ { sscop_inpend_erak, NULL }, /* SIG_T_CC */ { NULL, NULL }, /* SIG_T_POLL */ { NULL, NULL }, /* SIG_T_KA */ { NULL, NULL }, /* SIG_T_NR */ { NULL, NULL }, /* SIG_T_IDLE */ { NULL, NULL }, /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, /* SIG_USER_DATA */ { NULL, NULL }, /* SIG_ESTAB_REQ */ { NULL, NULL }, /* SIG_ESTAB_RESP */ { sscop_inpend_establish_resp, NULL }, /* SIG_RELEASE_REQ */ { sscop_inpend_release_req, NULL }, /* SIG_RECOVER */ { NULL, NULL }, /* SIG_SYNC_REQ */ { NULL, NULL }, /* SIG_SYNC_RESP */ { NULL, NULL }, /* SIG_UDATA */ { sscop_udata_req, NULL }, /* SIG_MDATA */ { sscop_mdata_req, NULL }, /* SIG_UPDU_Q */ { sscop_upduq, NULL }, /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, }, /* SSCOP_OUT_DIS_PEND */ { /* SIG_BGN */ { sscop_outdis_bgn, NULL }, /* SIG_BGAK */ { sscop_ignore_pdu, NULL }, /* SIG_END */ { sscop_outdis_end, NULL }, /* SIG_ENDAK */ { sscop_outdis_endak, NULL }, /* SIG_RS */ { sscop_ignore_pdu, NULL }, /* SIG_RSAK */ { sscop_ignore_pdu, NULL }, /* SIG_BGREJ */ { sscop_outdis_endak, NULL }, /* SIG_SD */ { sscop_ignore_pdu, NULL }, /* SIG_ER */ { sscop_ignore_pdu, NULL }, /* SIG_POLL */ { sscop_ignore_pdu, NULL }, /* SIG_STAT */ { sscop_ignore_pdu, NULL }, /* SIG_USTAT */ { sscop_ignore_pdu, NULL }, /* SIG_UD */ { sscop_ud, NULL }, /* SIG_MD */ { sscop_md, NULL }, /* SIG_ERAK */ { sscop_ignore_pdu, NULL }, /* SIG_T_CC */ { sscop_outdis_cc, NULL }, /* SIG_T_POLL */ { NULL, NULL }, /* SIG_T_KA */ { NULL, NULL }, /* SIG_T_NR */ { NULL, NULL }, /* SIG_T_IDLE */ { NULL, NULL }, /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, /* SIG_USER_DATA */ { NULL, NULL }, /* SIG_ESTAB_REQ */ { sscop_outdis_establish_req, NULL }, /* SIG_ESTAB_RESP */ { NULL, NULL }, /* SIG_RELEASE_REQ */ { NULL, NULL }, /* SIG_RECOVER */ { NULL, NULL }, /* SIG_SYNC_REQ */ { NULL, NULL }, /* SIG_SYNC_RESP */ { NULL, NULL }, /* SIG_UDATA */ { sscop_udata_req, NULL }, /* SIG_MDATA */ { sscop_mdata_req, NULL }, /* SIG_UPDU_Q */ { sscop_upduq, NULL }, /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, }, /* SSCOP_OUT_RESYNC_PEND */ { /* SIG_BGN */ { sscop_outsync_bgn, NULL }, /* SIG_BGAK */ { sscop_ignore_pdu, NULL }, /* SIG_END */ { sscop_outsync_end, NULL }, /* SIG_ENDAK */ { sscop_outsync_endak, NULL }, /* SIG_RS */ { sscop_outsync_rs, NULL }, /* SIG_RSAK */ { sscop_outsync_rsak, NULL }, /* SIG_BGREJ */ { sscop_outsync_bgrej, NULL }, /* SIG_SD */ { sscop_ignore_pdu, NULL }, /* SIG_ER */ { sscop_ignore_pdu, NULL }, /* SIG_POLL */ { sscop_ignore_pdu, NULL }, /* SIG_STAT */ { sscop_ignore_pdu, NULL }, /* SIG_USTAT */ { sscop_ignore_pdu, NULL }, /* SIG_UD */ { sscop_ud, NULL }, /* SIG_MD */ { sscop_md, NULL }, /* SIG_ERAK */ { sscop_ignore_pdu, NULL }, /* SIG_T_CC */ { sscop_outsync_cc, NULL }, /* SIG_T_POLL */ { NULL, NULL }, /* SIG_T_KA */ { NULL, NULL }, /* SIG_T_NR */ { NULL, NULL }, /* SIG_T_IDLE */ { NULL, NULL }, /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, /* SIG_USER_DATA */ { NULL, NULL }, /* SIG_ESTAB_REQ */ { NULL, NULL }, /* SIG_ESTAB_RESP */ { NULL, NULL }, /* SIG_RELEASE_REQ */ { sscop_outsync_release_req, NULL }, /* SIG_RECOVER */ { NULL, NULL }, /* SIG_SYNC_REQ */ { NULL, NULL }, /* SIG_SYNC_RESP */ { NULL, NULL }, /* SIG_UDATA */ { sscop_udata_req, NULL }, /* SIG_MDATA */ { sscop_mdata_req, NULL }, /* SIG_UPDU_Q */ { sscop_upduq, NULL }, /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, /* SIG_RETRIEVE */ { NULL, NULL }, }, /* SSCOP_IN_RESYNC_PEND */ { /* SIG_BGN */ { sscop_insync_bgn, NULL }, /* SIG_BGAK */ { sscop_insync_bgak, NULL }, /* SIG_END */ { sscop_insync_end, NULL }, /* SIG_ENDAK */ { sscop_insync_endak, NULL }, /* SIG_RS */ { sscop_insync_rs, NULL }, /* SIG_RSAK */ { sscop_insync_rsak, NULL }, /* SIG_BGREJ */ { sscop_insync_bgrej, NULL }, /* SIG_SD */ { sscop_insync_sd, NULL }, /* SIG_ER */ { sscop_insync_er, NULL }, /* SIG_POLL */ { sscop_insync_poll, NULL }, /* SIG_STAT */ { sscop_insync_stat, NULL }, /* SIG_USTAT */ { sscop_insync_ustat, NULL }, /* SIG_UD */ { sscop_ud, NULL }, /* SIG_MD */ { sscop_md, NULL }, /* SIG_ERAK */ { sscop_insync_erak, NULL }, /* SIG_T_CC */ { NULL, NULL }, /* SIG_T_POLL */ { NULL, NULL }, /* SIG_T_KA */ { NULL, NULL }, /* SIG_T_NR */ { NULL, NULL }, /* SIG_T_IDLE */ { NULL, NULL }, /* SIG_PDU_Q */ { sscop_flush_pduq, NULL }, /* SIG_USER_DATA */ { NULL, NULL }, /* SIG_ESTAB_REQ */ { NULL, NULL }, /* SIG_ESTAB_RESP */ { NULL, NULL }, /* SIG_RELEASE_REQ */ { sscop_insync_release_req, NULL }, /* SIG_RECOVER */ { NULL, NULL }, /* SIG_SYNC_REQ */ { NULL, NULL }, /* SIG_SYNC_RESP */ { sscop_insync_sync_resp, NULL }, /* SIG_UDATA */ { sscop_udata_req, NULL }, /* SIG_MDATA */ { sscop_mdata_req, NULL }, /* SIG_UPDU_Q */ { sscop_upduq, NULL }, /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, }, /* SSCOP_OUT_REC_PEND */ { /* SIG_BGN */ { sscop_outrec_bgn, NULL }, /* SIG_BGAK */ { sscop_outrec_bgak, NULL }, /* SIG_END */ { sscop_outrec_end, NULL }, /* SIG_ENDAK */ { sscop_outrec_endak, NULL }, /* SIG_RS */ { sscop_outrec_rs, NULL }, /* SIG_RSAK */ { sscop_outrec_rsak, NULL }, /* SIG_BGREJ */ { sscop_outrec_bgrej, NULL }, /* SIG_SD */ { sscop_ignore_pdu, NULL }, /* SIG_ER */ { sscop_outrec_er, NULL }, /* SIG_POLL */ { sscop_ignore_pdu, NULL }, /* SIG_STAT */ { sscop_ignore_pdu, NULL }, /* SIG_USTAT */ { sscop_ignore_pdu, NULL }, /* SIG_UD */ { sscop_ud, NULL }, /* SIG_MD */ { sscop_md, NULL }, /* SIG_ERAK */ { sscop_outrec_erak, NULL }, /* SIG_T_CC */ { sscop_outrec_cc, NULL }, /* SIG_T_POLL */ { NULL, NULL }, /* SIG_T_KA */ { NULL, NULL }, /* SIG_T_NR */ { NULL, NULL }, /* SIG_T_IDLE */ { NULL, NULL }, /* SIG_PDU_Q */ { sscop_outrec_pduq, NULL }, /* SIG_USER_DATA */ { sscop_outrec_userdata, NULL }, /* SIG_ESTAB_REQ */ { NULL, NULL }, /* SIG_ESTAB_RESP */ { NULL, NULL }, /* SIG_RELEASE_REQ */ { sscop_outrec_release_req, NULL }, /* SIG_RECOVER */ { NULL, NULL }, /* SIG_SYNC_REQ */ { sscop_outrec_sync_req, NULL }, /* SIG_SYNC_RESP */ { NULL, NULL }, /* SIG_UDATA */ { sscop_udata_req, NULL }, /* SIG_MDATA */ { sscop_mdata_req, NULL }, /* SIG_UPDU_Q */ { sscop_upduq, NULL }, /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, /* SIG_RETRIEVE */ { NULL, NULL }, }, /* SSCOP_REC_PEND */ { /* SIG_BGN */ { sscop_rec_bgn, NULL }, /* SIG_BGAK */ { sscop_rec_bgak, NULL }, /* SIG_END */ { sscop_rec_end, NULL }, /* SIG_ENDAK */ { sscop_rec_endak, NULL }, /* SIG_RS */ { sscop_rec_rs, NULL }, /* SIG_RSAK */ { sscop_rec_rsak, NULL }, /* SIG_BGREJ */ { sscop_rec_bgrej, NULL }, /* SIG_SD */ { sscop_ignore_pdu, NULL }, /* SIG_ER */ { sscop_rec_er, NULL }, /* SIG_POLL */ { sscop_ignore_pdu, NULL }, /* SIG_STAT */ { sscop_rec_stat, NULL }, /* SIG_USTAT */ { sscop_rec_ustat, NULL }, /* SIG_UD */ { sscop_ud, NULL }, /* SIG_MD */ { sscop_md, NULL }, /* SIG_ERAK */ { sscop_ignore_pdu, NULL }, /* SIG_T_CC */ { NULL, NULL }, /* SIG_T_POLL */ { NULL, NULL }, /* SIG_T_KA */ { NULL, NULL }, /* SIG_T_NR */ { NULL, NULL }, /* SIG_T_IDLE */ { NULL, NULL }, /* SIG_PDU_Q */ { sscop_rec_pduq, NULL }, /* SIG_USER_DATA */ { NULL, NULL }, /* SIG_ESTAB_REQ */ { NULL, NULL }, /* SIG_ESTAB_RESP */ { NULL, NULL }, /* SIG_RELEASE_REQ */ { sscop_rec_release_req, NULL }, /* SIG_RECOVER */ { sscop_rec_recover, NULL }, /* SIG_SYNC_REQ */ { sscop_rec_sync_req, NULL }, /* SIG_SYNC_RESP */ { NULL, NULL }, /* SIG_UDATA */ { sscop_udata_req, NULL }, /* SIG_MDATA */ { sscop_mdata_req, NULL }, /* SIG_UPDU_Q */ { sscop_upduq, NULL }, /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, }, /* SSCOP_IN_REC_PEND */ { /* SIG_BGN */ { sscop_inrec_bgn, NULL }, /* SIG_BGAK */ { sscop_inrec_bgak, NULL }, /* SIG_END */ { sscop_inrec_end, NULL }, /* SIG_ENDAK */ { sscop_inrec_endak, NULL }, /* SIG_RS */ { sscop_inrec_rs, NULL }, /* SIG_RSAK */ { sscop_inrec_rsak, NULL }, /* SIG_BGREJ */ { sscop_inrec_bgrej, NULL }, /* SIG_SD */ { sscop_inrec_sd, NULL }, /* SIG_ER */ { sscop_inrec_er, NULL }, /* SIG_POLL */ { sscop_inrec_poll, NULL }, /* SIG_STAT */ { sscop_inrec_stat, NULL }, /* SIG_USTAT */ { sscop_inrec_ustat, NULL }, /* SIG_UD */ { sscop_ud, NULL }, /* SIG_MD */ { sscop_md, NULL }, /* SIG_ERAK */ { sscop_inrec_erak, NULL }, /* SIG_T_CC */ { NULL, NULL }, /* SIG_T_POLL */ { NULL, NULL }, /* SIG_T_KA */ { NULL, NULL }, /* SIG_T_NR */ { NULL, NULL }, /* SIG_T_IDLE */ { NULL, NULL }, /* SIG_PDU_Q */ { sscop_inrec_pduq, NULL }, /* SIG_USER_DATA */ { NULL, NULL }, /* SIG_ESTAB_REQ */ { NULL, NULL }, /* SIG_ESTAB_RESP */ { NULL, NULL }, /* SIG_RELEASE_REQ */ { sscop_inrec_release_req, NULL }, /* SIG_RECOVER */ { sscop_inrec_recover, NULL }, /* SIG_SYNC_REQ */ { sscop_inrec_sync_req, NULL }, /* SIG_SYNC_RESP */ { NULL, NULL }, /* SIG_UDATA */ { sscop_udata_req, NULL }, /* SIG_MDATA */ { sscop_mdata_req, NULL }, /* SIG_UPDU_Q */ { sscop_upduq, NULL }, /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, /* SIG_RETRIEVE */ { sscop_retrieve, NULL }, }, /* SSCOP_READY */ { /* SIG_BGN */ { sscop_ready_bgn, NULL }, /* SIG_BGAK */ { sscop_ignore_pdu, NULL }, /* SIG_END */ { sscop_ready_end, NULL }, /* SIG_ENDAK */ { sscop_ready_endak, NULL }, /* SIG_RS */ { sscop_ready_rs, NULL }, /* SIG_RSAK */ { sscop_ignore_pdu, NULL }, /* SIG_BGREJ */ { sscop_ready_bgrej, NULL }, /* SIG_SD */ { sscop_ready_sd, NULL }, /* SIG_ER */ { sscop_ready_er, NULL }, /* SIG_POLL */ { sscop_ready_poll, NULL }, /* SIG_STAT */ { sscop_ready_stat, NULL }, /* SIG_USTAT */ { sscop_ready_ustat, NULL }, /* SIG_UD */ { sscop_ud, NULL }, /* SIG_MD */ { sscop_md, NULL }, /* SIG_ERAK */ { sscop_ignore_pdu, NULL }, /* SIG_T_CC */ { NULL, NULL }, /* SIG_T_POLL */ { sscop_ready_tpoll, NULL }, /* SIG_T_KA */ { sscop_ready_tka, NULL }, /* SIG_T_NR */ { sscop_ready_nr, NULL }, /* SIG_T_IDLE */ { sscop_ready_tidle, NULL }, /* SIG_PDU_Q */ { sscop_ready_pduq, c_ready_pduq }, /* SIG_USER_DATA */ { sscop_ready_userdata, NULL }, /* SIG_ESTAB_REQ */ { NULL, NULL }, /* SIG_ESTAB_RESP */ { NULL, NULL }, /* SIG_RELEASE_REQ */ { sscop_ready_release_req, NULL }, /* SIG_RECOVER */ { NULL, NULL }, /* SIG_SYNC_REQ */ { sscop_ready_sync_req, NULL }, /* SIG_SYNC_RESP */ { NULL, NULL }, /* SIG_UDATA */ { sscop_udata_req, NULL }, /* SIG_MDATA */ { sscop_mdata_req, NULL }, /* SIG_UPDU_Q */ { sscop_upduq, NULL }, /* SIG_MPDU_Q */ { sscop_mpduq, NULL }, /* SIG_RETRIEVE */ { NULL, NULL }, } }; /* * Try to execute a signal. It is executed if * - it is illegal (in this case it is effectively ignored) * - it has no condition * - its condition is true * If it has a condition and that is false, the function does nothing and * returns 0. * If the signal gets executed, the signal function is responsible to release * the message (if any). */ static int sig_exec(struct sscop *sscop, u_int sig, struct sscop_msg *msg) { void (*func)(struct sscop *, struct sscop_msg *); int (*cond)(struct sscop *); func = state_matrix[sscop->state][sig].func; cond = state_matrix[sscop->state][sig].cond; if(func == NULL) { VERBOSE(sscop, SSCOP_DBG_BUG, (sscop, sscop->aarg, "no handler for %s in state %s - ignored", events[sig], states[sscop->state])); SSCOP_MSG_FREE(msg); return 1; } if(cond == NULL || (*cond)(sscop)) { VERBOSE(sscop, SSCOP_DBG_EXEC, (sscop, sscop->aarg, "executing %s in %s", events[sig], states[sscop->state])); (*func)(sscop, msg); return 1; } VERBOSE(sscop, SSCOP_DBG_EXEC, (sscop, sscop->aarg, "delaying %s in %s", events[sig], states[sscop->state])); return 0; } /* * Deliver a signal to the given sscop * If it is delivered from inside a signal handler - queue it. If not, * execute it. After execution loop through the queue and execute all * pending signals. Signals, that cannot be executed because of entry * conditions are skipped. */ static void sscop_signal(struct sscop *sscop, u_int sig, struct sscop_msg *msg) { struct sscop_sig *s; VERBOSE(sscop, SSCOP_DBG_INSIG, (sscop, sscop->aarg, "got signal %s in state %s%s", events[sig], states[sscop->state], sscop->in_sig ? " -- queuing" : "")); SIG_ALLOC(s); if(s == NULL) { FAILURE("sscop: cannot allocate signal"); SSCOP_MSG_FREE(msg); return; } s->sig = sig; s->msg = msg; SIGQ_APPEND(&sscop->sigs, s); if(!sscop->in_sig) handle_sigs(sscop); } /* * Loop through the signal queue until we can't execute any signals. */ static void handle_sigs(struct sscop *sscop) { struct sscop_sig *s; sscop_sigq_head_t dsigs, q; int exec; sscop->in_sig++; /* * Copy the current signal queue to the local one and empty * the signal queue. Then loop through the signals. After one * pass we have a list of delayed signals because of entry * conditions and a new list of signals. Merge them. Repeat until * the signal queue is either empty or contains only delayed signals. */ SIGQ_INIT(&q); SIGQ_INIT(&dsigs); do { exec = 0; /* * Copy signal list and make sscop list empty */ SIGQ_MOVE(&sscop->sigs, &q); /* * Loop through the list */ while((s = SIGQ_GET(&q)) != NULL) { if(sig_exec(sscop, s->sig, s->msg)) { exec = 1; SIG_FREE(s); } else { SIGQ_APPEND(&dsigs, s); } } /* * Merge lists by inserting delayed signals in front of * the signal list. preserving the order. */ SIGQ_PREPEND(&dsigs, &sscop->sigs); } while(exec); sscop->in_sig--; } /* * Save a signal that should be executed only if state changes. */ static void sscop_save_signal(struct sscop *sscop, u_int sig, struct sscop_msg *msg) { struct sscop_sig *s; SIG_ALLOC(s); if(s == NULL) { FAILURE("sscop: cannot allocate signal"); SSCOP_MSG_FREE(msg); return; } s->sig = sig; s->msg = msg; SIGQ_APPEND(&sscop->saved_sigs, s); } /* * Set a new state. If signals are waiting for a state change - append them to * the signal queue, so they get executed. */ static void sscop_set_state(struct sscop *sscop, u_int nstate) { VERBOSE(sscop, SSCOP_DBG_STATE, (sscop, sscop->aarg, "changing state from %s to %s", states[sscop->state], states[nstate])); sscop->state = nstate; SIGQ_MOVE(&sscop->saved_sigs, &sscop->sigs); } void sscop_setdebug(struct sscop *sscop, u_int n) { sscop->debug = n; } u_int sscop_getdebug(const struct sscop *sscop) { return (sscop->debug); }