#include <osmocom/bb/common/lapdm.h>
#include <osmocom/bb/common/logging.h>
-#include <l1a_l23_interface.h>
+#include <l1ctl_proto.h>
/* TS 04.06 Figure 4 / Section 3.2 */
#define LAPDm_LPD_NORMAL 0
};
static void lapdm_t200_cb(void *data);
-static int rslms_send_i(struct lapdm_msg_ctx *mctx);
+static int rslms_send_i(struct lapdm_msg_ctx *mctx, int line);
/* UTILITY FUNCTIONS */
}
/* send the frame now */
- le->tx_pending = 1;
-#if 0
-printf("-> tx chan_nr 0x%x link_id 0x%x len %d data", chan_nr, link_id, msgb_l2len(msg));
-int i;
-for (i = 0; i < msgb_l2len(msg); i++)
- printf(" %02x", msg->l2h[i]);
-printf("\n");
-#endif
+ le->tx_pending = 0; /* disabled flow control */
lapdm_pad_msgb(msg, n201);
- return tx_ph_data_req(ms, msg, chan_nr, link_id);
+ return l1ctl_tx_data_req(ms, msg, chan_nr, link_id);
}
/* get next frame from the tx queue. because the ms has multiple datalinks,
/* we may send again */
le->tx_pending = 0;
-#if 0
-printf("-> tx confirm\n");
-#endif
/* free confirm message */
msgb_free(msg);
/* Pad the frame, we can transmit now */
le->tx_pending = 1;
-#if 0
-printf("-> more tx chan_nr 0x%x link_id 0x%x len %d data", chan_nr, link_id, msgb_l2len(msg));
-for (i = 0; i < msgb_l2len(msg); i++)
- printf(" %02x", msg->l2h[i]);
-printf("\n");
-#endif
lapdm_pad_msgb(msg, n201);
- return tx_ph_data_req(ms, msg, chan_nr, link_id);
+ return l1ctl_tx_data_req(ms, msg, chan_nr, link_id);
}
/* Create RSLms various RSLms messages */
mctx->link_id, 1);
rllh = (struct abis_rsl_rll_hdr *)msgb_l2(msg);
- rllh->data[0] = RSL_IE_ACCESS_DELAY;
+ rllh->data[0] = RSL_IE_TIMING_ADVANCE;
rllh->data[1] = mctx->ta_ind;
rllh->data[2] = RSL_IE_MS_POWER;
send_rll_simple(RSL_MT_REL_IND, &dl->mctx);
/* send MDL ERROR INIDCATION to L3 */
rsl_rll_error(RLL_CAUSE_T200_EXPIRED, &dl->mctx);
+ /* flush tx buffers */
+ lapdm_dl_flush_tx(dl);
/* go back to idle state */
lapdm_dl_newstate(dl, LAPDm_STATE_IDLE);
/* NOTE: we must not change any other states or buffers
send_rll_simple(RSL_MT_REL_CONF, &dl->mctx);
/* send MDL ERROR INIDCATION to L3 */
rsl_rll_error(RLL_CAUSE_T200_EXPIRED, &dl->mctx);
+ /* flush buffers */
+ lapdm_dl_flush_tx(dl);
+ lapdm_dl_flush_send(dl);
/* go back to idle state */
lapdm_dl_newstate(dl, LAPDm_STATE_IDLE);
/* NOTE: we must not change any other states or buffers
/* 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. */
+ * parameters" is sent to the mobile management entity.
+ */
LOGP(DLAPDM, LOGL_NOTICE,
"U frame iwth incorrect parameters ");
msgb_free(msg);
if (length != (dl->tx_hist[0][2] >> 2)
|| !!memcmp(dl->tx_hist[0] + 3, msg->l2h + 3,
length)) {
- LOGP(DLAPDM, LOGL_INFO, "UA response "
- "mismatches\n");
-int i;
-for (i = 0; i < (dl->tx_hist[0][2] >> 2); i++)
- printf(" %02x", dl->tx_hist[0][3+i]);
-printf(" == SENT\n");
-for (i = 0; i < length; i++)
- printf(" %02x", msg->l2h[3+i]);
-printf(" == RECEIVED (len=%d,%d)\n", msg->l2h[2] >> 2, length);
+ LOGP(DLAPDM, LOGL_INFO, "**** UA response "
+ "mismatches ****\n");
rc = send_rll_simple(RSL_MT_REL_IND, mctx);
msgb_free(msg);
/* go to idle state */
/* enter multiple-frame-established state */
lapdm_dl_newstate(dl, LAPDm_STATE_MF_EST);
/* send outstanding frames, if any (resume / reconnect) */
- rslms_send_i(mctx);
+ rslms_send_i(mctx, __LINE__);
/* send notification to L3 */
rc = send_rll_simple(RSL_MT_EST_CONF, mctx);
msgb_free(msg);
if (LAPDm_ADDR_CR(mctx->addr) == CR_BS2MS_CMD
&& LAPDm_CTRL_PF_BIT(mctx->ctrl)) {
if (!dl->own_busy && !dl->seq_err_cond) {
- LOGP(DLAPDM, LOGL_NOTICE, "RR frame command with polling bit set and we are not busy, so we reply with RR frame\n");
+ LOGP(DLAPDM, LOGL_NOTICE, "RR frame command "
+ "with polling bit set and we are not "
+ "busy, so we reply with RR frame\n");
lapdm_send_rr(mctx, 1);
/* NOTE: In case of sequence error condition,
* the REJ frame has been transmitted when
* done here
*/
} else if (dl->own_busy) {
- LOGP(DLAPDM, LOGL_NOTICE, "RR frame command with polling bit set and we are busy, so we reply with RR frame\n");
+ LOGP(DLAPDM, LOGL_NOTICE, "RR frame command "
+ "with polling bit set and we are busy, "
+ "so we reply with RR frame\n");
lapdm_send_rnr(mctx, 1);
}
}
/* Send message, if possible due to acknowledged data */
- rslms_send_i(mctx);
+ rslms_send_i(mctx, __LINE__);
break;
case LAPDm_S_RNR:
"received\n");
/* Send message, if possible due to acknowledged data */
- rslms_send_i(mctx);
+ rslms_send_i(mctx, __LINE__);
break;
case LAPDm_S_REJ:
/* FIXME: 5.5.4.2 2) */
/* Send message, if possible due to acknowledged data */
- rslms_send_i(mctx);
+ rslms_send_i(mctx, __LINE__);
break;
default:
/* send a DATA INDICATION to L3 */
msg->l3h = msg->l2h + 3;
msgb_pull_l2h(msg);
+ msg->len = length;
+ msg->tail = msg->data + length;
rc = send_rslms_rll_l3(RSL_MT_DATA_IND, mctx, msg);
} else {
/* create rcv_buffer */
if (!dl->rcv_buffer) {
LOGP(DLAPDM, LOGL_INFO, "message in multiple I "
"frames (first message)\n");
- dl->rcv_buffer = msgb_alloc_headroom(200+10, 10,
+ dl->rcv_buffer = msgb_alloc_headroom(200+56, 56,
"LAPDm RX");
dl->rcv_buffer->l3h = dl->rcv_buffer->data;
}
/* if the last segment was received */
if (!(msg->l2h[2] & LAPDm_MORE)) {
LOGP(DLAPDM, LOGL_INFO, "message in multiple I "
- "frames (next message)\n");
+ "frames (last message)\n");
rc = send_rslms_rll_l3(RSL_MT_DATA_IND, mctx,
dl->rcv_buffer);
dl->rcv_buffer = NULL;
} else
LOGP(DLAPDM, LOGL_INFO, "message in multiple I "
- "frames (last message)\n");
+ "frames (next message)\n");
msgb_free(msg);
}
/* check if we are not in own receiver busy */
if (!dl->own_busy) {
/* NOTE: V(R) is already set above */
- rc = rslms_send_i(mctx);
+ rc = rslms_send_i(mctx, __LINE__);
if (rc) {
LOGP(DLAPDM, LOGL_INFO, "we are not busy and "
"have no pending data, send RR\n");
/* Send RR with F=0 */
return lapdm_send_rr(mctx, 0);
}
+ /* all I or one RR is sent, we are done */
+ return 0;
} else {
LOGP(DLAPDM, LOGL_INFO, "we are busy, send RNR\n");
/* Send RNR with F=0 */
}
/* Send message, if possible due to acknowledged data */
- rslms_send_i(mctx);
+ rslms_send_i(mctx, __LINE__);
return rc;
}
{
int rc;
-#if 0
-printf("-> rx chan_nr 0x%x link_id 0x%x len %d data", mctx->chan_nr, mctx->link_id, msgb_l2len(msg));
-int i;
-for (i = 0; i < msgb_l2len(msg); i++)
- printf(" %02x", msg->l2h[i]);
-printf("\n");
-#endif
/* G.2.3 EA bit set to "0" is not allowed in GSM */
if (!LAPDm_ADDR_EA(mctx->addr)) {
LOGP(DLAPDM, LOGL_NOTICE, "EA bit 0 is not allowed in GSM\n");
* command shall contain the layer 3 message unit */
length = TLVP_LEN(&tv, RSL_IE_L3_INFO);
LOGP(DLAPDM, LOGL_INFO, "perform establishment with content "
- "(SAMB)\n");
+ "(SABM)\n");
} else {
/* normal establishment procedure */
length = 0;
- LOGP(DLAPDM, LOGL_INFO, "perform normal establishm. (SAMB)\n");
+ LOGP(DLAPDM, LOGL_INFO, "perform normal establishm. (SABM)\n");
}
/* check if the layer3 message length exceeds N201 */
/* Transmit-buffer carries exactly one segment */
memcpy(dl->tx_hist[0], msg->l2h, 3 + length);
dl->tx_length[0] = 3 + length;
+ /* set Vs to 0, because it is used as index when resending SABM */
+ dl->V_send = 0;
/* Set states */
dl->own_busy = dl->peer_busy = 0;
struct tlv_parsed tv;
int length;
uint8_t n201 = 23; //FIXME
+ uint8_t ta = 0, tx_power = 0;
/* check if the layer3 message length exceeds N201 */
rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh));
+ if (TLVP_PRESENT(&tv, RSL_IE_TIMING_ADVANCE)) {
+ ta = *TLVP_VAL(&tv, RSL_IE_TIMING_ADVANCE);
+ }
+ if (TLVP_PRESENT(&tv, RSL_IE_MS_POWER)) {
+ tx_power = *TLVP_VAL(&tv, RSL_IE_MS_POWER);
+ }
+ if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) {
+ LOGP(DLAPDM, LOGL_ERROR, "unit data request without message "
+ "error\n");
+ msgb_free(msg);
+ return -EINVAL;
+ }
length = TLVP_LEN(&tv, RSL_IE_L3_INFO);
/* check if the layer3 message length exceeds N201 */
- if (length + 3 > 18) { /* FIXME: do we know the channel N201? */
+ if (length + 5 > 23) { /* FIXME: do we know the channel N201? */
LOGP(DLAPDM, LOGL_ERROR, "frame too large: %d > N201(%d) "
- "(discarding)\n", length + 3, 18);
+ "(discarding)\n", length + 5, 23);
msgb_free(msg);
return -EIO;
}
- LOGP(DLAPDM, LOGL_INFO, "sending unit data\n");
+ LOGP(DLAPDM, LOGL_INFO, "sending unit data (tx_power=%d, ta=%d)\n",
+ tx_power, ta);
/* Remove RLL header from msgb */
msgb_pull_l2h(msg);
- /* Push LAPDm header on msgb */
- msg->l2h = msgb_push(msg, 3);
- msg->l2h[0] = LAPDm_ADDR(LAPDm_LPD_NORMAL, sapi, CR_MS2BS_CMD);
- msg->l2h[1] = LAPDm_CTRL_U(LAPDm_U_UI, 0);
- msg->l2h[2] = LAPDm_LEN(length);
+ /* Push L1 + LAPDm header on msgb */
+ msg->l2h = msgb_push(msg, 2 + 3);
+ msg->l2h[0] = tx_power;
+ msg->l2h[1] = ta;
+ msg->l2h[2] = LAPDm_ADDR(LAPDm_LPD_NORMAL, sapi, CR_MS2BS_CMD);
+ msg->l2h[3] = LAPDm_CTRL_U(LAPDm_U_UI, 0);
+ msg->l2h[4] = LAPDm_LEN(length);
// FIXME: short L2 header support
/* Tramsmit */
rsl_tlv_parse(&tv, rllh->data, msgb_l2len(msg)-sizeof(*rllh));
if (!TLVP_PRESENT(&tv, RSL_IE_L3_INFO)) {
- LOGP(DLAPDM, LOGL_ERROR, "data request without message error\n");
+ LOGP(DLAPDM, LOGL_ERROR, "data request without message "
+ "error\n");
msgb_free(msg);
return -EINVAL;
}
msgb_enqueue(&dl->send_queue, msg);
/* Send message, if possible */
- rslms_send_i(&dl->mctx);
+ rslms_send_i(&dl->mctx, __LINE__);
return 0;
}
/* Send next I frame from queued/buffered data */
-static int rslms_send_i(struct lapdm_msg_ctx *mctx)
+static int rslms_send_i(struct lapdm_msg_ctx *mctx, int line)
{
struct lapdm_datalink *dl = mctx->dl;
uint8_t chan_nr = mctx->chan_nr;
int length, left;
int rc = -1; /* we sent nothing */
+ LOGP(DLAPDM, LOGL_INFO, "%s() called from line %d\n", __func__, line);
+
next_frame:
if (dl->peer_busy) {
length = left;
if (length > mctx->n201 - 3)
length = mctx->n201 - 3;
-printf("msg-len %d sent %d left %d N201 %d length %d first byte %02x\n", msgb_l3len(dl->send_buffer), dl->send_out, left, mctx->n201, length, dl->send_buffer->l3h[0]);
+ LOGP(DLAPDM, LOGL_INFO, "msg-len %d sent %d left %d N201 %d "
+ "length %d first byte %02x\n",
+ msgb_l3len(dl->send_buffer), dl->send_out, left,
+ mctx->n201, length, dl->send_buffer->l3h[0]);
/* If message in send-buffer is completely sent */
if (left == 0) {
msgb_free(dl->send_buffer);
/* put back the send-buffer to the send-queue (first position) */
if (dl->send_buffer) {
+ LOGP(DLAPDM, LOGL_INFO, "put frame in sendbuffer back to "
+ "queue\n");
llist_add(&dl->send_buffer->list, &dl->send_queue);
dl->send_buffer = NULL;
- }
+ } else
+ LOGP(DLAPDM, LOGL_INFO, "no frame in sendbuffer\n");
- /* Clear transmit and send buffer, if any */
+ /* Clear transmit buffer, but keep send buffer */
lapdm_dl_flush_tx(dl);
- lapdm_dl_flush_send(dl);
msgb_free(msg);
}
length = TLVP_LEN(&tv, RSL_IE_L3_INFO);
- LOGP(DLAPDM, LOGL_INFO, "perform re-establishment (SAMB)\n");
+ LOGP(DLAPDM, LOGL_INFO, "perform re-establishment (SABM) length=%d\n",
+ length);
/* Replace message in the send-buffer (reconnect) */
if (dl->send_buffer)
msgb_free(dl->send_buffer);
- dl->send_buffer = msg;
+ dl->send_out = 0;
+ if (length) {
+ /* Remove the RSL/RLL header */
+ msgb_pull_l2h(msg);
+ /* Write data into the send buffer, to be sent first */
+ dl->send_buffer = msg;
+ }
/* Discard partly received L3 message */
if (dl->rcv_buffer) {
/* Transmit-buffer carries exactly one segment */
memcpy(dl->tx_hist[0], msg->l2h, 3);
dl->tx_length[0] = 3;
+ /* set Vs to 0, because it is used as index when resending SABM */
+ dl->V_send = 0;
/* Set states */
dl->own_busy = dl->peer_busy = 0;
bsc_del_timer(&dl->t200);
/* enter idle state */
lapdm_dl_newstate(dl, LAPDm_STATE_IDLE);
+ /* flush buffers */
+ lapdm_dl_flush_tx(dl);
+ lapdm_dl_flush_send(dl);
/* send notification to L3 */
return send_rll_simple(RSL_MT_REL_CONF, &dl->mctx);
}
}
/* TA = 0 - delay */
- rc = l1ctl_tx_ph_param_req(ms, 0 - cch->data[5], cch->data[7]);
+ rc = l1ctl_tx_param_req(ms, 0 - cch->data[5], cch->data[7]);
- rc = tx_ph_rach_req(ms, cch->data[1], cch->data[2], cch->data[3]);
+ rc = l1ctl_tx_rach_req(ms, cch->data[1], cch->data[2], cch->data[3]);
msgb_free(msg);
RSL_MT_RES_REQ, rslms_rx_rll_res_req},
/* create and send SABM command (reconnect) */
- {SBIT(LAPDm_STATE_MF_EST) |
+ {SBIT(LAPDm_STATE_IDLE) |
+ SBIT(LAPDm_STATE_MF_EST) |
SBIT(LAPDm_STATE_TIMER_RECOV),
RSL_MT_RECON_REQ, rslms_rx_rll_res_req},