/* get next frame from the tx queue. because the ms has multiple datalinks, * each datalink's queue is read round-robin. */ static int l2_ph_data_conf(struct msgb *msg, struct lapdm_entity *le) { struct osmo_phsap_prim pp; /* we may send again */ le->tx_pending = 0; /* free confirm message */ if (msg) msgb_free(msg); if (lapdm_phsap_dequeue_prim(le, &pp) < 0) { /* no message in all queues */ /* If user didn't request PH-EMPTY_FRAME.req, abort */ if (!(le->flags & LAPDM_ENT_F_EMPTY_FRAME)) return 0; /* otherwise, send PH-EMPTY_FRAME.req */ osmo_prim_init(&pp.oph, SAP_GSM_PH, PRIM_PH_EMPTY_FRAME, PRIM_OP_REQUEST, NULL); } else { le->tx_pending = 1; } return le->l1_prim_cb(&pp.oph, le->l1_ctx); }
static void test_lapdm_polling() { printf("I do some very simple LAPDm test.\n"); int rc; struct lapdm_polling_state test_state; struct osmo_phsap_prim pp; /* Configure LAPDm on both sides */ struct lapdm_channel bts_to_ms_channel; struct lapdm_channel ms_to_bts_channel; memset(&bts_to_ms_channel, 0, sizeof(bts_to_ms_channel)); memset(&ms_to_bts_channel, 0, sizeof(ms_to_bts_channel)); memset(&test_state, 0, sizeof(test_state)); test_state.bts = &bts_to_ms_channel; test_state.ms = &ms_to_bts_channel; /* BTS to MS in polling mode */ lapdm_channel_init(&bts_to_ms_channel, LAPDM_MODE_BTS); lapdm_channel_set_flags(&bts_to_ms_channel, LAPDM_ENT_F_POLLING_ONLY); lapdm_channel_set_l1(&bts_to_ms_channel, NULL, &test_state); lapdm_channel_set_l3(&bts_to_ms_channel, bts_to_ms_tx_cb, &test_state); /* MS to BTS in direct mode */ lapdm_channel_init(&ms_to_bts_channel, LAPDM_MODE_MS); lapdm_channel_set_l1(&ms_to_bts_channel, ms_to_bts_l1_cb, &test_state); lapdm_channel_set_l3(&ms_to_bts_channel, ms_to_bts_tx_cb, &test_state); /* * We try to send messages from the MS to the BTS to the MS.. */ /* 1. Start with MS -> BTS, BTS should have a pending message */ printf("Establishing link.\n"); lapdm_rslms_recvmsg(create_cm_serv_req(), &ms_to_bts_channel); /* 2. Poll on the BTS for sending out a confirmation */ printf("\nConfirming\n"); ASSERT(test_state.bts_read == 1) rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp); CHECK_RC(rc); ASSERT(pp.oph.msg->data == pp.oph.msg->l2h); send(pp.oph.msg, &ms_to_bts_channel); msgb_free(pp.oph.msg); ASSERT(test_state.ms_read == 1); /* 3. Send some data to the MS */ printf("\nSending back to MS\n"); lapdm_rslms_recvmsg(create_mm_id_req(), &bts_to_ms_channel); rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp); CHECK_RC(rc); send(pp.oph.msg, &ms_to_bts_channel); msgb_free(pp.oph.msg); ASSERT(test_state.ms_read == 2); /* verify that there is nothing more to poll */ rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp); ASSERT(rc < 0); /* 3. And back to the BTS */ printf("\nSending back to BTS\n"); ASSERT(test_state.ms_read == 2); lapdm_rslms_recvmsg(create_dummy_data_req(), &ms_to_bts_channel); /* 4. And back to the MS, but let's move data/l2h apart */ ASSERT(test_state.bts_read == 2) ASSERT(test_state.ms_read == 2); rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp); CHECK_RC(rc); send(pp.oph.msg, &ms_to_bts_channel); ASSERT(test_state.ms_read == 2); msgb_free(pp.oph.msg); /* verify that there is nothing more to poll */ rc = lapdm_phsap_dequeue_prim(&bts_to_ms_channel.lapdm_dcch, &pp); ASSERT(rc < 0); /* check sending an empty L3 message fails */ rc = lapdm_rslms_recvmsg(create_empty_msg(), &bts_to_ms_channel); ASSERT(rc == -1); ASSERT(test_state.ms_read == 2); /* clean up */ lapdm_channel_exit(&bts_to_ms_channel); lapdm_channel_exit(&ms_to_bts_channel); }