[lapdm] Added flow control between L1 and L2, so DM mode does not crash.

In dedicated mode a frame is sent to layer 1. Subsequent frames are queued
inside lapdm.c until a confirm from layer 1 is received. Since not all
pending frames are sent rapidly at once, the layer 1 does not crash anymore.

Also included in this commit: handling of reset confirm (maybe required
in the future after dedicated mode)
This commit is contained in:
Andreas.Eversberg 2010-06-26 11:12:25 +00:00
parent 4e03d6f822
commit 7b84cf805b
7 changed files with 79 additions and 21 deletions

View File

@ -32,6 +32,9 @@ int l1ctl_tx_ccch_mode_req(struct osmocom_ms *ms, uint8_t ccch_mode);
int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len);
/* Transmit L1CTL_RESET_REQ */
int l1ctl_tx_reset_req(struct osmocom_ms *ms, uint8_t type);
/* Transmit L1CTL_PM_REQ */
int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
uint16_t arfcm_to);

View File

@ -78,6 +78,7 @@ void lapdm_exit(struct lapdm_entity *le);
/* input into layer2 (from layer 1) */
int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le, struct l1ctl_info_dl *l1i);
int l2_ph_data_conf(struct msgb *msg, struct lapdm_entity *le);
/* input into layer2 (from layer 3) */
int rslms_recvmsg(struct msgb *msg, struct osmocom_ms *ms);

View File

@ -80,11 +80,8 @@ static int signal_cb(unsigned int subsys, unsigned int signal,
switch (signal) {
case S_L1CTL_RESET:
if (started) {
printf("L1_RESET, TODO: resend last radio request "
"(CCCH / dedicated / power scan)\n");
if (started)
break;
}
started = 1;
ms = signal_data;
/* insert test card, if enabled */

View File

@ -221,6 +221,7 @@ int gsm322_cs_sendmsg(struct osmocom_ms *ms, struct msgb *msg)
static int gsm322_sync_to_cell(struct osmocom_ms *ms, struct gsm322_cellsel *cs)
{
// l1ctl_tx_reset_req(ms, L1CTL_RES_T_FULL);
return l1ctl_tx_fbsb_req(ms, cs->arfcn,
L1CTL_FBSB_F_FB01SB, 100, 0,
CCCH_MODE_COMBINED);
@ -2404,6 +2405,9 @@ static int gsm322_l1_signal(unsigned int subsys, unsigned int signal,
ms = rc->ms;
gsm48_rr_rach_conf(ms, rc->fn);
break;
case S_L1CTL_RESET:
LOGP(DCS, LOGL_INFO, "Reset\n");
break;
}
return 0;

View File

@ -215,7 +215,8 @@ static void new_rr_state(struct gsm48_rrlayer *rr, int state)
struct msgb *msg, *nmsg;
/* release dedicated mode, if any */
tx_ph_dm_rel_req(rr->ms);
// tx_ph_dm_rel_req(rr->ms);
l1ctl_tx_reset_req(rr->ms, L1CTL_RES_T_FULL);
/* free establish message, if any */
rr->rr_est_req = 0;
if (rr->rr_est_msg) {

View File

@ -208,6 +208,26 @@ static int rx_ph_data_ind(struct osmocom_ms *ms, struct msgb *msg)
return 0;
}
/* Receive L1CTL_DATA_CONF (Data Confirm from L1) */
static int rx_ph_data_conf(struct osmocom_ms *ms, struct msgb *msg)
{
struct l1ctl_info_dl *dl;
struct lapdm_entity *le;
dl = (struct l1ctl_info_dl *) msg->l1h;
/* determine LAPDm entity based on SACCH or not */
if (dl->link_id & 0x40)
le = &ms->l2_entity.lapdm_acch;
else
le = &ms->l2_entity.lapdm_dcch;
/* send it up into LAPDm */
l2_ph_data_conf(msg, le);
return 0;
}
/* Transmit L1CTL_DATA_REQ */
int tx_ph_data_req(struct osmocom_ms *ms, struct msgb *msg,
uint8_t chan_nr, uint8_t link_id)
@ -397,6 +417,23 @@ int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
return osmo_send_l1(ms, msg);
}
/* Transmit L1CTL_RESET_REQ */
int l1ctl_tx_reset_req(struct osmocom_ms *ms, uint8_t type)
{
struct msgb *msg;
struct l1ctl_reset *res;
msg = osmo_l1_alloc(L1CTL_RESET_REQ);
if (!msg)
return -1;
printf("Tx Reset Req (%u)\n", type);
res = (struct l1ctl_reset *) msgb_put(msg, sizeof(*res));
res->type = type;
return osmo_send_l1(ms, msg);
}
/* Receive L1CTL_RESET_IND */
static int rx_l1_reset(struct osmocom_ms *ms)
{
@ -452,7 +489,11 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
case L1CTL_DATA_IND:
rc = rx_ph_data_ind(ms, msg);
break;
case L1CTL_DATA_CONF:
rc = rx_ph_data_conf(ms, msg);
break;
case L1CTL_RESET_IND:
case L1CTL_RESET_CONF:
rc = rx_l1_reset(ms);
msgb_free(msg);
break;
@ -462,19 +503,10 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
if (l1h->flags & L1CTL_F_DONE)
dispatch_signal(SS_L1CTL, S_L1CTL_PM_DONE, ms);
break;
case L1CTL_RESET_CONF:
LOGP(DL1C, LOGL_NOTICE, "L1CTL_RESET_CONF\n");
msgb_free(msg);
break;
case L1CTL_RACH_CONF:
LOGP(DL1C, LOGL_NOTICE, "L1CTL_RACH_CONF\n");
rc = rx_l1_rach_conf(ms, msg);
msgb_free(msg);
break;
case L1CTL_DATA_CONF:
LOGP(DL1C, LOGL_NOTICE, "L1CTL_DATA_CONF\n");
msgb_free(msg);
break;
default:
fprintf(stderr, "Unknown MSG: %u\n", l1h->msg_type);
msgb_free(msg);

View File

@ -297,14 +297,13 @@ static int tx_ph_data_enqueue(struct lapdm_datalink *dl, struct msgb *msg,
/* send the frame now */
le->tx_pending = 1;
#warning HACK: no confirm yet! (queue is always empty now)
le->tx_pending = 0;
#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");
//usleep(100000);
#endif
lapdm_pad_msgb(msg, n201);
return tx_ph_data_req(ms, msg, chan_nr, link_id);
}
@ -312,15 +311,23 @@ printf("\n");
/* get next frame from the tx queue. because the ms has multiple datalinks,
* each datalink's queue is read round-robin.
*/
static int tx_ph_data_dequeue(struct lapdm_entity *le)
int l2_ph_data_conf(struct msgb *msg, struct lapdm_entity *le)
{
struct osmocom_ms *ms = le->ms;
struct lapdm_datalink *dl;
int last = le->last_tx_dequeue;
int i = last, n = ARRAY_SIZE(le->datalink);
struct msgb *msg;
uint8_t chan_nr, link_id, n201;
/* we may send again */
le->tx_pending = 0;
#if 0
printf("-> tx confirm\n");
#endif
/* free confirm message */
msgb_free(msg);
/* round-robin dequeue */
do {
/* next */
@ -331,7 +338,7 @@ static int tx_ph_data_dequeue(struct lapdm_entity *le)
} while (i != last);
/* no message in all queues */
if (msg)
if (!msg)
return 0;
/* Pull chan_nr and link_id */
@ -347,6 +354,12 @@ static int tx_ph_data_dequeue(struct lapdm_entity *le)
/* 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);
}
@ -1419,6 +1432,13 @@ static int lapdm_ph_data_ind(struct msgb *msg, struct lapdm_msg_ctx *mctx)
{
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");
@ -1959,7 +1979,7 @@ const char *lapdm_state_names[] = {
"LAPDm_STATE_SABM_SENT",
"LAPDm_STATE_MF_EST",
"LAPDm_STATE_TIMER_RECOV",
"LAPDm_STATE_OWN_RCVR_BUSY"
"LAPDm_STATE_DISC_SENT",
};
/* statefull handling for RSLms RLL messages from L3 */