This is merely a historical archive of years 2008-2021, before the migration to mailman3.
A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.
pespin gerrit-no-reply at lists.osmocom.orgpespin has submitted this change. ( https://gerrit.osmocom.org/c/libosmocore/+/20819 )
Change subject: lapdm: Split lapd_rx_u() spaghetti into one function per message type
......................................................................
lapdm: Split lapd_rx_u() spaghetti into one function per message type
Change-Id: Ia1a49f7ae1d133174fad7a396db72867612fa619
---
M src/gsm/lapd_core.c
1 file changed, 451 insertions(+), 402 deletions(-)
Approvals:
laforge: Looks good to me, but someone else must approve
fixeria: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/src/gsm/lapd_core.c b/src/gsm/lapd_core.c
index 6a56572..bcb64b0 100644
--- a/src/gsm/lapd_core.c
+++ b/src/gsm/lapd_core.c
@@ -814,422 +814,471 @@
/* L1 -> L2 */
-/* Receive a LAPD U (Unnumbered) message from L1 */
-static int lapd_rx_u(struct msgb *msg, struct lapd_msg_ctx *lctx)
+/* Receive a LAPD U SABM(E) message from L1 */
+static int lapd_rx_u_sabm(struct msgb *msg, struct lapd_msg_ctx *lctx)
{
struct lapd_datalink *dl = lctx->dl;
int length = lctx->length;
int rc = 0;
uint8_t prim, op;
- switch (lctx->s_u) {
- case LAPD_U_SABM:
- case LAPD_U_SABME:
- prim = PRIM_DL_EST;
- op = PRIM_OP_INDICATION;
+ prim = PRIM_DL_EST;
+ op = PRIM_OP_INDICATION;
- LOGDL(dl, LOGL_INFO, "SABM(E) received in state %s\n", lapd_state_name(dl->state));
- /* 5.7.1 */
- dl->seq_err_cond = 0;
- /* G.2.2 Wrong value of the C/R bit */
- if (lctx->cr == dl->cr.rem2loc.resp) {
- LOGDL(dl, LOGL_ERROR, "SABM response error\n");
- msgb_free(msg);
- mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
- return -EINVAL;
- }
-
- /* G.4.5 If SABM is received with L>N201 or with M bit
- * set, AN MDL-ERROR-INDICATION is sent to MM.
- */
- if (lctx->more || length > lctx->n201) {
- LOGDL(dl, LOGL_ERROR, "SABM too large error\n");
- msgb_free(msg);
- mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx);
- return -EIO;
- }
-
- switch (dl->state) {
- case LAPD_STATE_IDLE:
- break;
- case LAPD_STATE_MF_EST:
- LOGDL(dl, LOGL_INFO, "SABM command, multiple frame established state\n");
- /* If link is lost on the remote side, we start over
- * and send DL-ESTABLISH indication again. */
- /* Additionally, continue in case of content resoltion
- * (GSM network). This happens, if the mobile has not
- * yet received UA or another mobile (collision) tries
- * to establish connection. The mobile must receive
- * UA again. */
- /* 5.4.2.1 */
- if (!length) {
- /* If no content resolution, this is a
- * re-establishment. */
- LOGDL(dl, LOGL_INFO, "Remote reestablish\n");
- break;
- }
- if (!dl->cont_res) {
- LOGDL(dl, LOGL_INFO, "SABM command not allowed in state %s\n",
- lapd_state_name(dl->state));
- mdl_error(MDL_CAUSE_SABM_MF, lctx);
- msgb_free(msg);
- return 0;
- }
- /* Ignore SABM if content differs from first SABM. */
- if (dl->mode == LAPD_MODE_NETWORK && length) {
-#ifdef TEST_CONTENT_RESOLUTION_NETWORK
- dl->cont_res->data[0] ^= 0x01;
-#endif
- if (memcmp(dl->cont_res->data, msg->data,
- length)) {
- LOGDL(dl, LOGL_INFO, "Another SABM with different content - "
- "ignoring!\n");
- msgb_free(msg);
- return 0;
- }
- }
- /* send UA again */
- lapd_send_ua(lctx, length, msg->l3h);
- msgb_free(msg);
- return 0;
- case LAPD_STATE_DISC_SENT:
- /* 5.4.6.2 send DM with F=P */
- lapd_send_dm(lctx);
- /* stop Timer T200 */
- lapd_stop_t200(dl);
- msgb_free(msg);
- return send_dl_simple(prim, op, lctx);
- default:
- /* collision: Send UA, but still wait for rx UA, then
- * change to MF_EST state.
- */
- /* check for contention resoultion */
- if (dl->tx_hist[0].msg && dl->tx_hist[0].msg->len) {
- LOGDL(dl, LOGL_NOTICE, "SABM not allowed during contention "
- "resolution (state=%s)\n", lapd_state_name(dl->state));
- mdl_error(MDL_CAUSE_SABM_INFO_NOTALL, lctx);
- }
- lapd_send_ua(lctx, length, msg->l3h);
- msgb_free(msg);
- return 0;
- }
- /* save message context for further use */
- memcpy(&dl->lctx, lctx, sizeof(dl->lctx));
-#ifndef TEST_CONTENT_RESOLUTION_NETWORK
- /* send UA response */
- lapd_send_ua(lctx, length, msg->l3h);
-#endif
- /* set Vs, Vr and Va to 0 */
- dl->v_send = dl->v_recv = dl->v_ack = 0;
- /* clear tx_hist */
- lapd_dl_flush_hist(dl);
- /* enter multiple-frame-established state */
- lapd_dl_newstate(dl, LAPD_STATE_MF_EST);
- /* store content resolution data on network side
- * Note: cont_res will be removed when changing state again,
- * so it must be allocated AFTER lapd_dl_newstate(). */
- if (dl->mode == LAPD_MODE_NETWORK && length) {
- dl->cont_res = lapd_msgb_alloc(length, "CONT RES");
- memcpy(msgb_put(dl->cont_res, length), msg->l3h,
- length);
- LOGDL(dl, LOGL_NOTICE, "Store content res.\n");
- }
- /* send notification to L3 */
- if (length == 0) {
- /* 5.4.1.2 Normal establishment procedures */
- rc = send_dl_simple(prim, op, lctx);
- msgb_free(msg);
- } else {
- /* 5.4.1.4 Contention resolution establishment */
- msgb_trim(msg, length);
- rc = send_dl_l3(prim, op, lctx, msg);
- }
- break;
- case LAPD_U_DM:
- LOGDL(dl, LOGL_INFO, "DM received in state %s\n", lapd_state_name(dl->state));
- /* G.2.2 Wrong value of the C/R bit */
- if (lctx->cr == dl->cr.rem2loc.cmd) {
- LOGDL(dl, LOGL_ERROR, "DM command error\n");
- msgb_free(msg);
- mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
- return -EINVAL;
- }
- if (!lctx->p_f) {
- /* 5.4.1.2 DM responses with the F bit set to "0"
- * shall be ignored.
- */
- msgb_free(msg);
- return 0;
- }
- switch (dl->state) {
- case LAPD_STATE_SABM_SENT:
- break;
- case LAPD_STATE_MF_EST:
- if (lctx->p_f) {
- LOGDL(dl, LOGL_INFO, "unsolicited DM response\n");
- mdl_error(MDL_CAUSE_UNSOL_DM_RESP, lctx);
- } else {
- LOGDL(dl, LOGL_INFO, "unsolicited DM response, "
- "multiple frame established state\n");
- mdl_error(MDL_CAUSE_UNSOL_DM_RESP_MF, lctx);
- /* reestablish */
- if (!dl->reestablish) {
- msgb_free(msg);
- return 0;
- }
- LOGDL(dl, LOGL_NOTICE, "Performing reestablishment\n");
- lapd_reestablish(dl);
- }
- msgb_free(msg);
- return 0;
- case LAPD_STATE_TIMER_RECOV:
- /* FP = 0 (DM is normal in case PF = 1) */
- if (!lctx->p_f) {
- LOGDL(dl, LOGL_INFO, "unsolicited DM response, multiple frame "
- "established state\n");
- mdl_error(MDL_CAUSE_UNSOL_DM_RESP_MF, lctx);
- msgb_free(msg);
- /* reestablish */
- if (!dl->reestablish)
- return 0;
- LOGDL(dl, LOGL_NOTICE, "Performing reestablishment\n");
- return lapd_reestablish(dl);
- }
- break;
- case LAPD_STATE_DISC_SENT:
- /* stop Timer T200 */
- lapd_stop_t200(dl);
- /* go to idle state */
- lapd_dl_flush_tx(dl);
- lapd_dl_flush_send(dl);
- lapd_dl_newstate(dl, LAPD_STATE_IDLE);
- rc = send_dl_simple(PRIM_DL_REL, PRIM_OP_CONFIRM, lctx);
- msgb_free(msg);
- return 0;
- case LAPD_STATE_IDLE:
- /* 5.4.5 all other frame types shall be discarded */
- default:
- LOGDL(dl, LOGL_INFO, "unsolicited DM response! (discarding)\n");
- msgb_free(msg);
- return 0;
- }
- /* stop timer T200 */
- lapd_stop_t200(dl);
- /* go to idle state */
- lapd_dl_newstate(dl, LAPD_STATE_IDLE);
- rc = send_dl_simple(PRIM_DL_REL, PRIM_OP_INDICATION, lctx);
- msgb_free(msg);
- break;
- case LAPD_U_UI:
- LOGDL(dl, LOGL_INFO, "UI received\n");
- /* G.2.2 Wrong value of the C/R bit */
- if (lctx->cr == dl->cr.rem2loc.resp) {
- LOGDL(dl, LOGL_ERROR, "UI indicates response error\n");
- msgb_free(msg);
- mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
- return -EINVAL;
- }
-
- /* G.4.5 If UI is received with L>N201 or with M bit
- * set, AN MDL-ERROR-INDICATION is sent to MM.
- */
- if (length > lctx->n201 || lctx->more) {
- LOGDL(dl, LOGL_ERROR, "UI too large error (%d > N201(%d) or M=%d)\n",
- length, lctx->n201, lctx->more);
- msgb_free(msg);
- mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx);
- return -EIO;
- }
-
- /* do some length checks */
- if (length == 0) {
- /* 5.3.3 UI frames received with the length indicator
- * set to "0" shall be ignored
- */
- LOGDL(dl, LOGL_INFO, "length=0 (discarding)\n");
- msgb_free(msg);
- return 0;
- }
- msgb_trim(msg, length);
- rc = send_dl_l3(PRIM_DL_UNIT_DATA, PRIM_OP_INDICATION, lctx,
- msg);
- break;
- case LAPD_U_DISC:
- prim = PRIM_DL_REL;
- op = PRIM_OP_INDICATION;
-
- LOGDL(dl, LOGL_INFO, "DISC received in state %s\n", lapd_state_name(dl->state));
- /* flush tx and send buffers */
- lapd_dl_flush_tx(dl);
- lapd_dl_flush_send(dl);
- /* 5.7.1 */
- dl->seq_err_cond = 0;
- /* G.2.2 Wrong value of the C/R bit */
- if (lctx->cr == dl->cr.rem2loc.resp) {
- LOGDL(dl, LOGL_ERROR, "DISC response error\n");
- msgb_free(msg);
- mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
- return -EINVAL;
- }
- if (length > 0 || lctx->more) {
- /* G.4.4 If a DISC or DM frame is received with L>0 or
- * with the M bit set to "1", an MDL-ERROR-INDICATION
- * primitive with cause "U frame with incorrect
- * parameters" is sent to the mobile management entity.
- */
- LOGDL(dl, LOGL_ERROR, "U frame iwth incorrect parameters\n");
- msgb_free(msg);
- mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx);
- return -EIO;
- }
- switch (dl->state) {
- case LAPD_STATE_IDLE:
- LOGDL(dl, LOGL_INFO, "DISC in idle state\n");
- /* send DM with F=P */
- msgb_free(msg);
- return lapd_send_dm(lctx);
- case LAPD_STATE_SABM_SENT:
- LOGDL(dl, LOGL_INFO, "DISC in SABM state\n");
- /* 5.4.6.2 send DM with F=P */
- lapd_send_dm(lctx);
- /* stop Timer T200 */
- lapd_stop_t200(dl);
- /* go to idle state */
- lapd_dl_newstate(dl, LAPD_STATE_IDLE);
- msgb_free(msg);
- return send_dl_simple(PRIM_DL_REL, PRIM_OP_INDICATION,
- lctx);
- case LAPD_STATE_MF_EST:
- case LAPD_STATE_TIMER_RECOV:
- LOGDL(dl, LOGL_INFO, "DISC in est state\n");
- break;
- case LAPD_STATE_DISC_SENT:
- LOGDL(dl, LOGL_INFO, "DISC in disc state\n");
- prim = PRIM_DL_REL;
- op = PRIM_OP_CONFIRM;
- break;
- default:
- lapd_send_ua(lctx, length, msg->l3h);
- msgb_free(msg);
- return 0;
- }
- /* send UA response */
- lapd_send_ua(lctx, length, msg->l3h);
- /* stop Timer T200 */
- lapd_stop_t200(dl);
- /* enter idle state, keep tx-buffer with UA response */
- lapd_dl_newstate(dl, LAPD_STATE_IDLE);
- /* send notification to L3 */
- rc = send_dl_simple(prim, op, lctx);
- msgb_free(msg);
- break;
- case LAPD_U_UA:
- LOGDL(dl, LOGL_INFO, "UA received in state %s\n", lapd_state_name(dl->state));
- /* G.2.2 Wrong value of the C/R bit */
- if (lctx->cr == dl->cr.rem2loc.cmd) {
- LOGDL(dl, LOGL_ERROR, "UA indicates command error\n");
- msgb_free(msg);
- mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
- return -EINVAL;
- }
-
- /* G.4.5 If UA is received with L>N201 or with M bit
- * set, AN MDL-ERROR-INDICATION is sent to MM.
- */
- if (lctx->more || length > lctx->n201) {
- LOGDL(dl, LOGL_ERROR, "UA too large error\n");
- msgb_free(msg);
- mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx);
- return -EIO;
- }
-
- if (!lctx->p_f) {
- /* 5.4.1.2 A UA response with the F bit set to "0"
- * shall be ignored.
- */
- LOGDL(dl, LOGL_INFO, "F=0 (discarding)\n");
- msgb_free(msg);
- return 0;
- }
- switch (dl->state) {
- case LAPD_STATE_SABM_SENT:
- break;
- case LAPD_STATE_MF_EST:
- case LAPD_STATE_TIMER_RECOV:
- LOGDL(dl, LOGL_INFO, "unsolicited UA response! (discarding)\n");
- mdl_error(MDL_CAUSE_UNSOL_UA_RESP, lctx);
- msgb_free(msg);
- return 0;
- case LAPD_STATE_DISC_SENT:
- LOGDL(dl, LOGL_INFO, "UA in disconnect state\n");
- /* stop Timer T200 */
- lapd_stop_t200(dl);
- /* go to idle state */
- lapd_dl_flush_tx(dl);
- lapd_dl_flush_send(dl);
- lapd_dl_newstate(dl, LAPD_STATE_IDLE);
- rc = send_dl_simple(PRIM_DL_REL, PRIM_OP_CONFIRM, lctx);
- msgb_free(msg);
- return 0;
- case LAPD_STATE_IDLE:
- /* 5.4.5 all other frame types shall be discarded */
- default:
- LOGDL(dl, LOGL_INFO, "unsolicited UA response! (discarding)\n");
- msgb_free(msg);
- return 0;
- }
- LOGDL(dl, LOGL_INFO, "UA in SABM state\n");
- /* stop Timer T200 */
- lapd_stop_t200(dl);
- /* compare UA with SABME if contention resolution is applied */
- if (dl->tx_hist[0].msg->len) {
- if (length != (dl->tx_hist[0].msg->len)
- || !!memcmp(dl->tx_hist[0].msg->data, msg->l3h,
- length)) {
- LOGDL(dl, LOGL_INFO, "**** UA response mismatches ****\n");
- rc = send_dl_simple(PRIM_DL_REL,
- PRIM_OP_INDICATION, lctx);
- msgb_free(msg);
- /* go to idle state */
- lapd_dl_flush_tx(dl);
- lapd_dl_flush_send(dl);
- lapd_dl_newstate(dl, LAPD_STATE_IDLE);
- return 0;
- }
- }
- /* set Vs, Vr and Va to 0 */
- dl->v_send = dl->v_recv = dl->v_ack = 0;
- /* clear tx_hist */
- lapd_dl_flush_hist(dl);
- /* enter multiple-frame-established state */
- lapd_dl_newstate(dl, LAPD_STATE_MF_EST);
- /* send outstanding frames, if any (resume / reconnect) */
- lapd_send_i(lctx, __LINE__);
- /* send notification to L3 */
- rc = send_dl_simple(PRIM_DL_EST, PRIM_OP_CONFIRM, lctx);
- msgb_free(msg);
- break;
- case LAPD_U_FRMR:
- LOGDL(dl, LOGL_NOTICE, "Frame reject received\n");
- /* send MDL ERROR INIDCATION to L3 */
- mdl_error(MDL_CAUSE_FRMR, lctx);
- msgb_free(msg);
- /* reestablish */
- if (!dl->reestablish)
- break;
- LOGDL(dl, LOGL_NOTICE, "Performing reestablishment\n");
- rc = lapd_reestablish(dl);
- break;
- default:
- /* G.3.1 */
- LOGDL(dl, LOGL_NOTICE, "Unnumbered frame not allowed\n");
+ LOGDL(dl, LOGL_INFO, "SABM(E) received in state %s\n", lapd_state_name(dl->state));
+ /* 5.7.1 */
+ dl->seq_err_cond = 0;
+ /* G.2.2 Wrong value of the C/R bit */
+ if (lctx->cr == dl->cr.rem2loc.resp) {
+ LOGDL(dl, LOGL_ERROR, "SABM response error\n");
msgb_free(msg);
mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
return -EINVAL;
}
+
+ /* G.4.5 If SABM is received with L>N201 or with M bit
+ * set, AN MDL-ERROR-INDICATION is sent to MM.
+ */
+ if (lctx->more || length > lctx->n201) {
+ LOGDL(dl, LOGL_ERROR, "SABM too large error\n");
+ msgb_free(msg);
+ mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx);
+ return -EIO;
+ }
+
+ switch (dl->state) {
+ case LAPD_STATE_IDLE:
+ break;
+ case LAPD_STATE_MF_EST:
+ LOGDL(dl, LOGL_INFO, "SABM command, multiple frame established state\n");
+ /* If link is lost on the remote side, we start over
+ * and send DL-ESTABLISH indication again. */
+ /* Additionally, continue in case of content resoltion
+ * (GSM network). This happens, if the mobile has not
+ * yet received UA or another mobile (collision) tries
+ * to establish connection. The mobile must receive
+ * UA again. */
+ /* 5.4.2.1 */
+ if (!length) {
+ /* If no content resolution, this is a
+ * re-establishment. */
+ LOGDL(dl, LOGL_INFO, "Remote reestablish\n");
+ break;
+ }
+ if (!dl->cont_res) {
+ LOGDL(dl, LOGL_INFO, "SABM command not allowed in state %s\n",
+ lapd_state_name(dl->state));
+ mdl_error(MDL_CAUSE_SABM_MF, lctx);
+ msgb_free(msg);
+ return 0;
+ }
+ /* Ignore SABM if content differs from first SABM. */
+ if (dl->mode == LAPD_MODE_NETWORK && length) {
+#ifdef TEST_CONTENT_RESOLUTION_NETWORK
+ dl->cont_res->data[0] ^= 0x01;
+#endif
+ if (memcmp(dl->cont_res->data, msg->data,
+ length)) {
+ LOGDL(dl, LOGL_INFO, "Another SABM with different content - "
+ "ignoring!\n");
+ msgb_free(msg);
+ return 0;
+ }
+ }
+ /* send UA again */
+ lapd_send_ua(lctx, length, msg->l3h);
+ msgb_free(msg);
+ return 0;
+ case LAPD_STATE_DISC_SENT:
+ /* 5.4.6.2 send DM with F=P */
+ lapd_send_dm(lctx);
+ /* stop Timer T200 */
+ lapd_stop_t200(dl);
+ msgb_free(msg);
+ return send_dl_simple(prim, op, lctx);
+ default:
+ /* collision: Send UA, but still wait for rx UA, then
+ * change to MF_EST state.
+ */
+ /* check for contention resoultion */
+ if (dl->tx_hist[0].msg && dl->tx_hist[0].msg->len) {
+ LOGDL(dl, LOGL_NOTICE, "SABM not allowed during contention "
+ "resolution (state=%s)\n", lapd_state_name(dl->state));
+ mdl_error(MDL_CAUSE_SABM_INFO_NOTALL, lctx);
+ }
+ lapd_send_ua(lctx, length, msg->l3h);
+ msgb_free(msg);
+ return 0;
+ }
+ /* save message context for further use */
+ memcpy(&dl->lctx, lctx, sizeof(dl->lctx));
+#ifndef TEST_CONTENT_RESOLUTION_NETWORK
+ /* send UA response */
+ lapd_send_ua(lctx, length, msg->l3h);
+#endif
+ /* set Vs, Vr and Va to 0 */
+ dl->v_send = dl->v_recv = dl->v_ack = 0;
+ /* clear tx_hist */
+ lapd_dl_flush_hist(dl);
+ /* enter multiple-frame-established state */
+ lapd_dl_newstate(dl, LAPD_STATE_MF_EST);
+ /* store content resolution data on network side
+ * Note: cont_res will be removed when changing state again,
+ * so it must be allocated AFTER lapd_dl_newstate(). */
+ if (dl->mode == LAPD_MODE_NETWORK && length) {
+ dl->cont_res = lapd_msgb_alloc(length, "CONT RES");
+ memcpy(msgb_put(dl->cont_res, length), msg->l3h,
+ length);
+ LOGDL(dl, LOGL_NOTICE, "Store content res.\n");
+ }
+ /* send notification to L3 */
+ if (length == 0) {
+ /* 5.4.1.2 Normal establishment procedures */
+ rc = send_dl_simple(prim, op, lctx);
+ msgb_free(msg);
+ } else {
+ /* 5.4.1.4 Contention resolution establishment */
+ msgb_trim(msg, length);
+ rc = send_dl_l3(prim, op, lctx, msg);
+ }
return rc;
}
+/* Receive a LAPD U DM message from L1 */
+static int lapd_rx_u_dm(struct msgb *msg, struct lapd_msg_ctx *lctx)
+{
+ struct lapd_datalink *dl = lctx->dl;
+ int rc = 0;
+
+ LOGDL(dl, LOGL_INFO, "DM received in state %s\n", lapd_state_name(dl->state));
+ /* G.2.2 Wrong value of the C/R bit */
+ if (lctx->cr == dl->cr.rem2loc.cmd) {
+ LOGDL(dl, LOGL_ERROR, "DM command error\n");
+ msgb_free(msg);
+ mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
+ return -EINVAL;
+ }
+ if (!lctx->p_f) {
+ /* 5.4.1.2 DM responses with the F bit set to "0"
+ * shall be ignored.
+ */
+ msgb_free(msg);
+ return 0;
+ }
+ switch (dl->state) {
+ case LAPD_STATE_SABM_SENT:
+ break;
+ case LAPD_STATE_MF_EST:
+ if (lctx->p_f) {
+ LOGDL(dl, LOGL_INFO, "unsolicited DM response\n");
+ mdl_error(MDL_CAUSE_UNSOL_DM_RESP, lctx);
+ } else {
+ LOGDL(dl, LOGL_INFO, "unsolicited DM response, "
+ "multiple frame established state\n");
+ mdl_error(MDL_CAUSE_UNSOL_DM_RESP_MF, lctx);
+ /* reestablish */
+ if (!dl->reestablish) {
+ msgb_free(msg);
+ return 0;
+ }
+ LOGDL(dl, LOGL_NOTICE, "Performing reestablishment\n");
+ lapd_reestablish(dl);
+ }
+ msgb_free(msg);
+ return 0;
+ case LAPD_STATE_TIMER_RECOV:
+ /* FP = 0 (DM is normal in case PF = 1) */
+ if (!lctx->p_f) {
+ LOGDL(dl, LOGL_INFO, "unsolicited DM response, multiple frame "
+ "established state\n");
+ mdl_error(MDL_CAUSE_UNSOL_DM_RESP_MF, lctx);
+ msgb_free(msg);
+ /* reestablish */
+ if (!dl->reestablish)
+ return 0;
+ LOGDL(dl, LOGL_NOTICE, "Performing reestablishment\n");
+ return lapd_reestablish(dl);
+ }
+ break;
+ case LAPD_STATE_DISC_SENT:
+ /* stop Timer T200 */
+ lapd_stop_t200(dl);
+ /* go to idle state */
+ lapd_dl_flush_tx(dl);
+ lapd_dl_flush_send(dl);
+ lapd_dl_newstate(dl, LAPD_STATE_IDLE);
+ rc = send_dl_simple(PRIM_DL_REL, PRIM_OP_CONFIRM, lctx);
+ msgb_free(msg);
+ return 0;
+ case LAPD_STATE_IDLE:
+ /* 5.4.5 all other frame types shall be discarded */
+ default:
+ LOGDL(dl, LOGL_INFO, "unsolicited DM response! (discarding)\n");
+ msgb_free(msg);
+ return 0;
+ }
+ /* stop timer T200 */
+ lapd_stop_t200(dl);
+ /* go to idle state */
+ lapd_dl_newstate(dl, LAPD_STATE_IDLE);
+ rc = send_dl_simple(PRIM_DL_REL, PRIM_OP_INDICATION, lctx);
+ msgb_free(msg);
+ return rc;
+}
+
+/* Receive a LAPD U UI message from L1 */
+static int lapd_rx_u_ui(struct msgb *msg, struct lapd_msg_ctx *lctx)
+{
+ struct lapd_datalink *dl = lctx->dl;
+ int length = lctx->length;
+
+ LOGDL(dl, LOGL_INFO, "UI received\n");
+ /* G.2.2 Wrong value of the C/R bit */
+ if (lctx->cr == dl->cr.rem2loc.resp) {
+ LOGDL(dl, LOGL_ERROR, "UI indicates response error\n");
+ msgb_free(msg);
+ mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
+ return -EINVAL;
+ }
+
+ /* G.4.5 If UI is received with L>N201 or with M bit
+ * set, AN MDL-ERROR-INDICATION is sent to MM.
+ */
+ if (length > lctx->n201 || lctx->more) {
+ LOGDL(dl, LOGL_ERROR, "UI too large error (%d > N201(%d) or M=%d)\n",
+ length, lctx->n201, lctx->more);
+ msgb_free(msg);
+ mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx);
+ return -EIO;
+ }
+
+ /* do some length checks */
+ if (length == 0) {
+ /* 5.3.3 UI frames received with the length indicator
+ * set to "0" shall be ignored
+ */
+ LOGDL(dl, LOGL_INFO, "length=0 (discarding)\n");
+ msgb_free(msg);
+ return 0;
+ }
+ msgb_trim(msg, length);
+ return send_dl_l3(PRIM_DL_UNIT_DATA, PRIM_OP_INDICATION, lctx, msg);
+}
+
+/* Receive a LAPD U DISC message from L1 */
+static int lapd_rx_u_disc(struct msgb *msg, struct lapd_msg_ctx *lctx)
+{
+ struct lapd_datalink *dl = lctx->dl;
+ int length = lctx->length;
+ int rc = 0;
+ uint8_t prim, op;
+
+ prim = PRIM_DL_REL;
+ op = PRIM_OP_INDICATION;
+
+ LOGDL(dl, LOGL_INFO, "DISC received in state %s\n", lapd_state_name(dl->state));
+ /* flush tx and send buffers */
+ lapd_dl_flush_tx(dl);
+ lapd_dl_flush_send(dl);
+ /* 5.7.1 */
+ dl->seq_err_cond = 0;
+ /* G.2.2 Wrong value of the C/R bit */
+ if (lctx->cr == dl->cr.rem2loc.resp) {
+ LOGDL(dl, LOGL_ERROR, "DISC response error\n");
+ msgb_free(msg);
+ mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
+ return -EINVAL;
+ }
+ if (length > 0 || lctx->more) {
+ /* G.4.4 If a DISC or DM frame is received with L>0 or
+ * with the M bit set to "1", an MDL-ERROR-INDICATION
+ * primitive with cause "U frame with incorrect
+ * parameters" is sent to the mobile management entity.
+ */
+ LOGDL(dl, LOGL_ERROR, "U frame iwth incorrect parameters\n");
+ msgb_free(msg);
+ mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx);
+ return -EIO;
+ }
+ switch (dl->state) {
+ case LAPD_STATE_IDLE:
+ LOGDL(dl, LOGL_INFO, "DISC in idle state\n");
+ /* send DM with F=P */
+ msgb_free(msg);
+ return lapd_send_dm(lctx);
+ case LAPD_STATE_SABM_SENT:
+ LOGDL(dl, LOGL_INFO, "DISC in SABM state\n");
+ /* 5.4.6.2 send DM with F=P */
+ lapd_send_dm(lctx);
+ /* stop Timer T200 */
+ lapd_stop_t200(dl);
+ /* go to idle state */
+ lapd_dl_newstate(dl, LAPD_STATE_IDLE);
+ msgb_free(msg);
+ return send_dl_simple(PRIM_DL_REL, PRIM_OP_INDICATION,
+ lctx);
+ case LAPD_STATE_MF_EST:
+ case LAPD_STATE_TIMER_RECOV:
+ LOGDL(dl, LOGL_INFO, "DISC in est state\n");
+ break;
+ case LAPD_STATE_DISC_SENT:
+ LOGDL(dl, LOGL_INFO, "DISC in disc state\n");
+ prim = PRIM_DL_REL;
+ op = PRIM_OP_CONFIRM;
+ break;
+ default:
+ lapd_send_ua(lctx, length, msg->l3h);
+ msgb_free(msg);
+ return 0;
+ }
+ /* send UA response */
+ lapd_send_ua(lctx, length, msg->l3h);
+ /* stop Timer T200 */
+ lapd_stop_t200(dl);
+ /* enter idle state, keep tx-buffer with UA response */
+ lapd_dl_newstate(dl, LAPD_STATE_IDLE);
+ /* send notification to L3 */
+ rc = send_dl_simple(prim, op, lctx);
+ msgb_free(msg);
+ return rc;
+}
+
+/* Receive a LAPD U UA message from L1 */
+static int lapd_rx_u_ua(struct msgb *msg, struct lapd_msg_ctx *lctx)
+{
+ struct lapd_datalink *dl = lctx->dl;
+ int length = lctx->length;
+ int rc = 0;
+
+ LOGDL(dl, LOGL_INFO, "UA received in state %s\n", lapd_state_name(dl->state));
+ /* G.2.2 Wrong value of the C/R bit */
+ if (lctx->cr == dl->cr.rem2loc.cmd) {
+ LOGDL(dl, LOGL_ERROR, "UA indicates command error\n");
+ msgb_free(msg);
+ mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
+ return -EINVAL;
+ }
+
+ /* G.4.5 If UA is received with L>N201 or with M bit
+ * set, AN MDL-ERROR-INDICATION is sent to MM.
+ */
+ if (lctx->more || length > lctx->n201) {
+ LOGDL(dl, LOGL_ERROR, "UA too large error\n");
+ msgb_free(msg);
+ mdl_error(MDL_CAUSE_UFRM_INC_PARAM, lctx);
+ return -EIO;
+ }
+
+ if (!lctx->p_f) {
+ /* 5.4.1.2 A UA response with the F bit set to "0"
+ * shall be ignored.
+ */
+ LOGDL(dl, LOGL_INFO, "F=0 (discarding)\n");
+ msgb_free(msg);
+ return 0;
+ }
+ switch (dl->state) {
+ case LAPD_STATE_SABM_SENT:
+ break;
+ case LAPD_STATE_MF_EST:
+ case LAPD_STATE_TIMER_RECOV:
+ LOGDL(dl, LOGL_INFO, "unsolicited UA response! (discarding)\n");
+ mdl_error(MDL_CAUSE_UNSOL_UA_RESP, lctx);
+ msgb_free(msg);
+ return 0;
+ case LAPD_STATE_DISC_SENT:
+ LOGDL(dl, LOGL_INFO, "UA in disconnect state\n");
+ /* stop Timer T200 */
+ lapd_stop_t200(dl);
+ /* go to idle state */
+ lapd_dl_flush_tx(dl);
+ lapd_dl_flush_send(dl);
+ lapd_dl_newstate(dl, LAPD_STATE_IDLE);
+ rc = send_dl_simple(PRIM_DL_REL, PRIM_OP_CONFIRM, lctx);
+ msgb_free(msg);
+ return 0;
+ case LAPD_STATE_IDLE:
+ /* 5.4.5 all other frame types shall be discarded */
+ default:
+ LOGDL(dl, LOGL_INFO, "unsolicited UA response! (discarding)\n");
+ msgb_free(msg);
+ return 0;
+ }
+ LOGDL(dl, LOGL_INFO, "UA in SABM state\n");
+ /* stop Timer T200 */
+ lapd_stop_t200(dl);
+ /* compare UA with SABME if contention resolution is applied */
+ if (dl->tx_hist[0].msg->len) {
+ if (length != (dl->tx_hist[0].msg->len)
+ || !!memcmp(dl->tx_hist[0].msg->data, msg->l3h,
+ length)) {
+ LOGDL(dl, LOGL_INFO, "**** UA response mismatches ****\n");
+ rc = send_dl_simple(PRIM_DL_REL,
+ PRIM_OP_INDICATION, lctx);
+ msgb_free(msg);
+ /* go to idle state */
+ lapd_dl_flush_tx(dl);
+ lapd_dl_flush_send(dl);
+ lapd_dl_newstate(dl, LAPD_STATE_IDLE);
+ return 0;
+ }
+ }
+ /* set Vs, Vr and Va to 0 */
+ dl->v_send = dl->v_recv = dl->v_ack = 0;
+ /* clear tx_hist */
+ lapd_dl_flush_hist(dl);
+ /* enter multiple-frame-established state */
+ lapd_dl_newstate(dl, LAPD_STATE_MF_EST);
+ /* send outstanding frames, if any (resume / reconnect) */
+ lapd_send_i(lctx, __LINE__);
+ /* send notification to L3 */
+ rc = send_dl_simple(PRIM_DL_EST, PRIM_OP_CONFIRM, lctx);
+ msgb_free(msg);
+ return rc;
+}
+
+/* Receive a LAPD U FRMR message from L1 */
+static int lapd_rx_u_frmr(struct msgb *msg, struct lapd_msg_ctx *lctx)
+{
+ struct lapd_datalink *dl = lctx->dl;
+
+ LOGDL(dl, LOGL_NOTICE, "Frame reject received\n");
+ /* send MDL ERROR INIDCATION to L3 */
+ mdl_error(MDL_CAUSE_FRMR, lctx);
+ msgb_free(msg);
+ /* reestablish */
+ if (!dl->reestablish)
+ return 0;
+ LOGDL(dl, LOGL_NOTICE, "Performing reestablishment\n");
+ return lapd_reestablish(dl);
+}
+
+/* Receive a LAPD U (Unnumbered) message from L1 */
+static int lapd_rx_u(struct msgb *msg, struct lapd_msg_ctx *lctx)
+{
+ switch (lctx->s_u) {
+ case LAPD_U_SABM:
+ case LAPD_U_SABME:
+ return lapd_rx_u_sabm(msg, lctx);
+ case LAPD_U_DM:
+ return lapd_rx_u_dm(msg, lctx);
+ case LAPD_U_UI:
+ return lapd_rx_u_ui(msg, lctx);
+ case LAPD_U_DISC:
+ return lapd_rx_u_disc(msg, lctx);
+ case LAPD_U_UA:
+ return lapd_rx_u_ua(msg, lctx);
+ case LAPD_U_FRMR:
+ return lapd_rx_u_frmr(msg, lctx);
+ default:
+ /* G.3.1 */
+ LOGDL(lctx->dl, LOGL_NOTICE, "Unnumbered frame not allowed\n");
+ msgb_free(msg);
+ mdl_error(MDL_CAUSE_FRM_UNIMPL, lctx);
+ return -EINVAL;
+ }
+}
+
/* Receive a LAPD S (Supervisory) message from L1 */
static int lapd_rx_s(struct msgb *msg, struct lapd_msg_ctx *lctx)
{
--
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/20819
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings
Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Ia1a49f7ae1d133174fad7a396db72867612fa619
Gerrit-Change-Number: 20819
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin at sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy at sysmocom.de>
Gerrit-Reviewer: laforge <laforge at osmocom.org>
Gerrit-Reviewer: pespin <pespin at sysmocom.de>
Gerrit-MessageType: merged
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20201021/1e2b42be/attachment.htm>