diff --git a/include/openbsc/gsm_data.h b/include/openbsc/gsm_data.h index 0e3a380d7..071b1c6ec 100644 --- a/include/openbsc/gsm_data.h +++ b/include/openbsc/gsm_data.h @@ -138,8 +138,10 @@ struct gsm_lchan { struct gsm_bts_trx_ts *ts; /* The logical subslot number in the TS */ u_int8_t nr; - /* The lotical channel type */ + /* The logical channel type */ enum gsm_chan_t type; + /* If TCH, traffic channel mode */ + enum gsm_chan_t tch_mode; /* Power levels for MS and BTS */ u_int8_t bs_power; u_int8_t ms_power; diff --git a/include/openbsc/trau_mux.h b/include/openbsc/trau_mux.h index f3d519fb1..90535add4 100644 --- a/include/openbsc/trau_mux.h +++ b/include/openbsc/trau_mux.h @@ -36,8 +36,14 @@ int trau_mux_map_lchan(const struct gsm_lchan *src, const struct gsm_lchan *dst); /* unmap a TRAU mux map entry */ -int trau_mux_unmap(const struct gsm_e1_subslot *ss); +int trau_mux_unmap(const struct gsm_e1_subslot *ss, u_int32_t callref); /* we get called by subchan_demux */ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, const u_int8_t *trau_bits, int num_bits); + +/* add a trau receiver */ +int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref); + +/* send trau from application */ +int trau_send_lchan(struct gsm_lchan *lchan, struct decoded_trau_frame *tf); diff --git a/src/abis_rsl.c b/src/abis_rsl.c index 753a66609..d9a39b8b4 100644 --- a/src/abis_rsl.c +++ b/src/abis_rsl.c @@ -476,10 +476,21 @@ int rsl_chan_mode_modify_req(struct gsm_lchan *lchan) /* FIXME: what to do with data calls ? */ cm.dtx_dtu = 0x00; switch (lchan->type) { + /* todo more modes */ case GSM_LCHAN_TCH_F: cm.spd_ind = RSL_CMOD_SPD_SPEECH; cm.chan_rt = RSL_CMOD_CRT_TCH_Bm; - cm.chan_rate = RSL_CMOD_SP_GSM2; + switch(lchan->tch_mode) { + case GSM48_CMODE_SPEECH_V1: + cm.chan_rate = RSL_CMOD_SP_GSM1; + break; + case GSM48_CMODE_SPEECH_EFR: + cm.chan_rate = RSL_CMOD_SP_GSM2; + break; + default: + DEBUGP(DRSL, "Unimplemented channel modification\n"); + return -1; + } break; default: DEBUGP(DRSL, "Unimplemented channel modification\n"); diff --git a/src/e1_config.c b/src/e1_config.c index ffc7e46cc..fc23b55e1 100644 --- a/src/e1_config.c +++ b/src/e1_config.c @@ -5,6 +5,7 @@ #include #include +#include #include #include diff --git a/src/e1_input.c b/src/e1_input.c index 7fbf1797a..c3c7c7597 100644 --- a/src/e1_input.c +++ b/src/e1_input.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #define NUM_E1_TS 32 diff --git a/src/gsm_04_08.c b/src/gsm_04_08.c index 849ef4888..07e7a4683 100644 --- a/src/gsm_04_08.c +++ b/src/gsm_04_08.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #define GSM48_ALLOC_SIZE 1024 @@ -635,6 +636,7 @@ int gsm48_tx_chan_mode_modify(struct gsm_lchan *lchan, u_int8_t mode) DEBUGP(DRR, "-> CHANNEL MODE MODIFY mode=0x%02x\n", mode); + lchan->tch_mode = mode; msg->lchan = lchan; gh->proto_discr = GSM48_PDISC_RR; gh->msg_type = GSM48_MT_RR_CHAN_MODE_MODIF; diff --git a/src/trau_mux.c b/src/trau_mux.c index 2616785c0..96f858992 100644 --- a/src/trau_mux.c +++ b/src/trau_mux.c @@ -36,7 +36,15 @@ struct map_entry { struct gsm_e1_subslot src, dst; }; +struct upqueue_entry { + struct llist_head list; + struct gsm_network *net; + struct gsm_e1_subslot src; + u_int32_t callref; +}; + static LLIST_HEAD(ss_map); +static LLIST_HEAD(ss_upqueue); /* map one particular subslot to another subslot */ int trau_mux_map(const struct gsm_e1_subslot *src, @@ -52,8 +60,8 @@ int trau_mux_map(const struct gsm_e1_subslot *src, dst->e1_nr, dst->e1_ts, dst->e1_ts_ss); /* make sure to get rid of any stale old mappings */ - trau_mux_unmap(src); - trau_mux_unmap(dst); + trau_mux_unmap(src, 0); + trau_mux_unmap(dst, 0); memcpy(&me->src, src, sizeof(me->src)); memcpy(&me->dst, dst, sizeof(me->dst)); @@ -75,14 +83,26 @@ int trau_mux_map_lchan(const struct gsm_lchan *src, /* unmap one particular subslot from another subslot */ -int trau_mux_unmap(const struct gsm_e1_subslot *ss) +int trau_mux_unmap(const struct gsm_e1_subslot *ss, u_int32_t callref) { struct map_entry *me, *me2; + struct upqueue_entry *ue, *ue2; - llist_for_each_entry_safe(me, me2, &ss_map, list) { - if (!memcmp(&me->src, ss, sizeof(*ss)) || - !memcmp(&me->dst, ss, sizeof(*ss))) { - llist_del(&me->list); + if (ss) + llist_for_each_entry_safe(me, me2, &ss_map, list) { + if (!memcmp(&me->src, ss, sizeof(*ss)) || + !memcmp(&me->dst, ss, sizeof(*ss))) { + llist_del(&me->list); + return 0; + } + } + llist_for_each_entry_safe(ue, ue2, &ss_upqueue, list) { + if (ue->callref == callref) { + llist_del(&ue->list); + return 0; + } + if (ss && !memcmp(&ue->src, ss, sizeof(*ss))) { + llist_del(&ue->list); return 0; } } @@ -104,6 +124,19 @@ lookup_trau_mux_map(const struct gsm_e1_subslot *src) return NULL; } +/* look-up an enty in the TRAU upqueue */ +struct upqueue_entry * +lookup_trau_upqueue(const struct gsm_e1_subslot *src) +{ + struct upqueue_entry *ue; + + llist_for_each_entry(ue, &ss_upqueue, list) { + if (!memcmp(&ue->src, src, sizeof(*src))) + return ue; + } + return NULL; +} + /* we get called by subchan_demux */ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, const u_int8_t *trau_bits, int num_bits) @@ -114,6 +147,11 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, struct subch_mux *mx; int rc; + /* decode TRAU, change it to downlink, re-encode */ + rc = decode_trau_frame(&tf, trau_bits); + if (rc) + return rc; + if (!dst_e1_ss) return -EINVAL; @@ -121,11 +159,6 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, if (!mx) return -EINVAL; - /* decode TRAU, change it to downlink, re-encode */ - rc = decode_trau_frame(&tf, trau_bits); - if (rc) - return rc; - trau_frame_up2down(&tf); encode_trau_frame(trau_bits_out, &tf); @@ -133,3 +166,47 @@ int trau_mux_input(struct gsm_e1_subslot *src_e1_ss, return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out, TRAU_FRAME_BITS); } + +/* add receiver instance for lchan and callref */ +int trau_recv_lchan(struct gsm_lchan *lchan, u_int32_t callref) +{ + struct gsm_e1_subslot *src_ss; + struct upqueue_entry *ue = malloc(sizeof(*ue)); + + if (!ue) + return -ENOMEM; + + src_ss = &lchan->ts->e1_link; + + DEBUGP(DCC, "Setting up TRAU receiver (e1=%u,ts=%u,ss=%u) " + "and (callref 0x%x)\n", + src_ss->e1_nr, src_ss->e1_ts, src_ss->e1_ts_ss, + callref); + + /* make sure to get rid of any stale old mappings */ + trau_mux_unmap(src_ss, callref); + + memcpy(&ue->src, src_ss, sizeof(ue->src)); + ue->net = lchan->ts->trx->bts->network; + ue->callref = callref; + llist_add(&ue->list, &ss_upqueue); + + return 0; +} + +int trau_send_lchan(struct gsm_lchan *lchan, struct decoded_trau_frame *tf) +{ + u_int8_t trau_bits_out[TRAU_FRAME_BITS]; + struct gsm_e1_subslot *dst_e1_ss = &lchan->ts->e1_link; + struct subch_mux *mx; + + mx = e1inp_get_mux(dst_e1_ss->e1_nr, dst_e1_ss->e1_ts); + if (!mx) + return -EINVAL; + + encode_trau_frame(trau_bits_out, tf); + + /* and send it to the muxer */ + return subchan_mux_enqueue(mx, dst_e1_ss->e1_ts_ss, trau_bits_out, + TRAU_FRAME_BITS); +}