1 /* GSMTAP layer1 is transmits gsmtap messages over a virtual layer 1.*/
3 /* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
4 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <osmocom/core/gsmtap.h>
24 #include <osmocom/core/gsmtap_util.h>
25 #include <osmocom/core/utils.h>
26 #include <osmocom/gsm/rsl.h>
27 #include <osmocom/gsm/gsm_utils.h>
28 #include <osmocom/gsm/protocol/gsm_08_58.h>
29 #include <osmocom/gsm/protocol/gsm_04_08.h>
30 #include <osmocom/core/msgb.h>
35 #include <l1ctl_proto.h>
36 #include <virtphy/virtual_um.h>
37 #include <virtphy/l1ctl_sock.h>
38 #include <virtphy/virt_l1_model.h>
39 #include <virtphy/l1ctl_sap.h>
40 #include <virtphy/gsmtapl1_if.h>
41 #include <virtphy/logging.h>
42 #include <virtphy/virt_l1_sched.h>
44 static char *pseudo_lchan_name(uint16_t arfcn
, uint8_t ts
, uint8_t ss
, uint8_t sub_type
)
46 static char lname
[64];
47 snprintf(lname
, sizeof(lname
), "(arfcn=%u,ts=%u,ss=%u,type=%s)",
48 arfcn
, ts
, ss
, get_value_string(gsmtap_gsm_channel_names
, sub_type
));
52 /* Return gsmtap_um_voice_type or -1 on error */
53 static int get_um_voice_type(enum gsm48_chan_mode tch_mode
, uint8_t rsl_chantype
)
56 case GSM48_CMODE_SPEECH_V1
:
57 switch (rsl_chantype
) {
58 case RSL_CHAN_Bm_ACCHs
:
59 return GSMTAP_UM_VOICE_FR
;
60 case RSL_CHAN_Lm_ACCHs
:
61 return GSMTAP_UM_VOICE_HR
;
66 case GSM48_CMODE_SPEECH_EFR
:
67 return GSMTAP_UM_VOICE_EFR
;
68 case GSM48_CMODE_SPEECH_AMR
:
69 return GSMTAP_UM_VOICE_AMR
;
76 * Replace l11 header of given msgb by a gsmtap header and send it over the virt um.
78 void gsmtapl1_tx_to_virt_um_inst(struct l1_model_ms
*ms
, uint32_t fn
, uint8_t tn
, struct msgb
*msg
)
80 struct l1ctl_hdr
*l1h
= (struct l1ctl_hdr
*)msg
->data
;
81 struct l1ctl_info_ul
*ul
;
82 struct gsmtap_hdr
*gh
;
83 struct msgb
*outmsg
; /* msg to send with gsmtap header prepended */
84 uint16_t arfcn
= ms
->state
.serving_cell
.arfcn
; /* arfcn of the cell we currently camp on */
85 uint8_t signal_dbm
= 63; /* signal strength */
86 uint8_t snr
= 63; /* signal noise ratio, 63 is best */
87 uint8_t *data
= msgb_l2(msg
); /* data to transmit (whole message without l1 header) */
88 uint8_t data_len
= msgb_l2len(msg
); /* length of data */
90 uint8_t rsl_chantype
; /* rsl chan type (8.58, 9.3.1) */
91 uint8_t subslot
; /* multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51) */
92 uint8_t timeslot
; /* tdma timeslot to send in (0-7) */
93 uint8_t gsmtap_chan
; /* the gsmtap channel */
95 switch (l1h
->msg_type
) {
96 case L1CTL_DATA_TBF_REQ
:
98 rsl_chantype
= RSL_CHAN_OSMO_PDCH
;
101 gsmtap_chan
= chantype_rsl2gsmtap2(rsl_chantype
, 0, false);
103 case L1CTL_TRAFFIC_REQ
:
104 ul
= (struct l1ctl_info_ul
*)l1h
->data
;
105 rsl_dec_chan_nr(ul
->chan_nr
, &rsl_chantype
, &subslot
, ×lot
);
106 gsmtap_chan
= chantype_rsl2gsmtap2(rsl_chantype
, 0, true);
107 /* the first byte indicates the type of voice codec (gsmtap_um_voice_type);
108 * let's first strip any data in front of the l2 header, then push this extra
109 * byte to the front and finally adjust the l2h pointer */
110 msgb_pull_to_l2(msg
);
111 msgb_push_u8(msg
, get_um_voice_type(ms
->state
.tch_mode
, rsl_chantype
));
112 msg
->l2h
= msg
->data
;
114 data_len
= msgb_l2len(msg
);
117 ul
= (struct l1ctl_info_ul
*)l1h
->data
;
118 rsl_dec_chan_nr(ul
->chan_nr
, &rsl_chantype
, &subslot
, ×lot
);
119 gsmtap_chan
= chantype_rsl2gsmtap2(rsl_chantype
, ul
->link_id
, false);
123 /* arfcn needs to be flagged to be able to distinguish between uplink and downlink */
124 outmsg
= gsmtap_makemsg(arfcn
| GSMTAP_ARFCN_F_UPLINK
, timeslot
,
125 gsmtap_chan
, subslot
, fn
, signal_dbm
, snr
, data
,
128 outmsg
->l1h
= msgb_data(outmsg
);
129 gh
= msgb_l1(outmsg
);
130 if (virt_um_write_msg(ms
->vui
, outmsg
) == -1) {
131 LOGPMS(DVIRPHY
, LOGL_ERROR
, ms
, "%s Tx go GSMTAP failed: %s\n",
132 pseudo_lchan_name(gh
->arfcn
, gh
->timeslot
, gh
->sub_slot
, gh
->sub_type
),
135 DEBUGPMS(DVIRPHY
, ms
, "%s: Tx to GSMTAP: %s\n",
136 pseudo_lchan_name(gh
->arfcn
, gh
->timeslot
, gh
->sub_slot
, gh
->sub_type
),
137 osmo_hexdump(data
, data_len
));
140 LOGPMS(DVIRPHY
, LOGL_ERROR
, ms
, "GSMTAP msg could not be created!\n");
147 * @see virt_prim_fbsb.c
149 extern void prim_fbsb_sync(struct l1_model_ms
*ms
, struct msgb
*msg
);
152 * @see virt_prim_pm.c
154 extern uint16_t prim_pm_set_sig_strength(struct l1_model_ms
*ms
, uint16_t arfcn
, int16_t sig_lev
);
156 /* determine if a received Downlink RLC/MAC block matches the current MS configuration */
157 static bool gprs_dl_block_matches_ms(struct l1_model_ms
*ms
, struct msgb
*msg
, uint8_t timeslot
)
159 uint8_t payload_type
;
162 if (msgb_length(msg
) < 1)
165 /* FIXME: Ensure this will also work for EGPRS! */
166 payload_type
= msg
->data
[0] >> 6;
167 switch (payload_type
) {
168 case 0: /* RLC Data Block */
169 /* forward all RLD Data Blocks destined for TFI of MS */
170 tfi
= (msg
->data
[1] >> 1) & 0x1f;
171 if (ms
->state
.state
== MS_STATE_TBF
&& ms
->state
.tbf
.dl
.tfi
[timeslot
] == tfi
)
174 case 1: /* RLC/MAC Control without optional octets */
175 /* forward all RLC/MAC control blocks without optional octets, i.e. not addressed
176 * to a specific TFI */
178 case 2: /* RLC/MAC with optional control octets */
179 /* forward all RLD Control Blocks destined for TFI of MS */
180 tfi
= (msg
->data
[2] >> 1) & 0x1f;
181 if (ms
->state
.state
== MS_STATE_TBF
&& ms
->state
.tbf
.dl
.tfi
[timeslot
] == tfi
)
190 /* determine if given USF at given timeslot is relevant to given MS or not */
191 static bool usf_matches_ms(struct l1_model_ms
*ms
, uint8_t usf
, uint8_t timeslot
)
193 if (ms
->state
.state
== MS_STATE_TBF
&& ms
->state
.tbf
.ul
.usf
[timeslot
] == usf
)
199 /* extract USF from (E)GPRS RLC/MAC block */
200 static uint8_t get_usf_from_block(struct msgb
*msg
)
202 /* FIXME: Ensure this will also work for EGPRS! */
203 return msg
->data
[0] & 0x7;
206 /* MS is authorized to transmit a block in uplink for given USF on timeslot+arfcn at FN */
207 static void ms_ul_tbf_may_transmit(struct l1_model_ms
*ms
, uint16_t arfcn
, uint8_t timeslot
,
208 uint32_t fn
, uint8_t usf
)
212 /* If USF is not for us, bail out */
213 if (!usf_matches_ms(ms
, usf
, timeslot
))
216 /* attempt to de-queue pending msgb for this UL TBF and transmit it */
217 msg
= msgb_dequeue(&ms
->state
.tbf
.ul
.tx_queue
);
219 printf("FN=%u, TN=%u, USF=%u: empty tx_queue, not transmitting\n", fn
, timeslot
, usf
);
220 /* FIXME: send some dummy control frame? */
222 printf("FN=%u, TN=%u, USF=%u: transmitting queued msg\n", fn
, timeslot
, usf
);
223 gsmtapl1_tx_to_virt_um_inst(ms
, fn
, timeslot
, msg
);
227 static void l1ctl_from_virt_um(struct l1ctl_sock_client
*lsc
, struct msgb
*msg
, uint32_t fn
,
228 uint16_t arfcn
, uint8_t timeslot
, uint8_t subslot
,
229 uint8_t gsmtap_chantype
, uint8_t chan_nr
, uint8_t link_id
,
232 struct l1_model_ms
*ms
= lsc
->priv
;
233 uint8_t signal_dbm
= dbm2rxlev(prim_pm_set_sig_strength(ms
, arfcn
& GSMTAP_ARFCN_MASK
, MAX_SIG_LEV_DBM
)); /* Power measurement with each received massage */
236 gsm_fn2gsmtime(&ms
->state
.downlink_time
, fn
);
238 /* we do not forward messages to l23 if we are in network search state */
239 if (ms
->state
.state
== MS_STATE_IDLE_SEARCHING
)
242 /* forward downlink msg to fbsb sync routine if we are in sync state */
243 if (ms
->state
.state
== MS_STATE_IDLE_SYNCING
) {
244 prim_fbsb_sync(ms
, msg
);
247 /* generally ignore all messages coming from another arfcn than the camped one */
248 if (ms
->state
.serving_cell
.arfcn
!= arfcn
) {
252 virt_l1_sched_sync_time(ms
, ms
->state
.downlink_time
, 0);
253 virt_l1_sched_execute(ms
, fn
);
255 /* switch case with removed ACCH flag */
256 switch (gsmtap_chantype
& ~GSMTAP_CHANNEL_ACCH
& 0xff) {
257 case GSMTAP_CHANNEL_TCH_H
:
258 case GSMTAP_CHANNEL_TCH_F
:
259 /* This is TCH signalling, for voice frames see GSMTAP_CHANNEL_VOICE */
260 case GSMTAP_CHANNEL_SDCCH4
:
261 case GSMTAP_CHANNEL_SDCCH8
:
262 /* only forward messages on dedicated channels to l2, if
263 * the timeslot and subslot is fitting */
264 if (ms
->state
.dedicated
.tn
== timeslot
265 && ms
->state
.dedicated
.subslot
== subslot
) {
266 l1ctl_tx_data_ind(ms
, msg
, arfcn
, link_id
, chan_nr
, fn
, snr_db
, signal_dbm
, 0, 0);
269 case GSMTAP_CHANNEL_VOICE_F
:
270 case GSMTAP_CHANNEL_VOICE_H
:
271 /* only forward messages on dedicated channels to l2, if
272 * the timeslot and subslot is fitting */
273 if (ms
->state
.dedicated
.tn
== timeslot
274 && ms
->state
.dedicated
.subslot
== subslot
) {
275 l1ctl_tx_traffic_ind(ms
, msg
, arfcn
, link_id
, chan_nr
, fn
,
276 snr_db
, signal_dbm
, 0, 0);
279 case GSMTAP_CHANNEL_CBCH51
:
280 /* only pass CBCH data if the user application actually indicated that a CBCH
282 if (ms
->state
.serving_cell
.ccch_mode
!= CCCH_MODE_COMBINED_CBCH
)
284 case GSMTAP_CHANNEL_AGCH
:
285 case GSMTAP_CHANNEL_PCH
:
286 case GSMTAP_CHANNEL_BCCH
:
287 case GSMTAP_CHANNEL_CBCH52
:
288 /* save to just forward here, as upper layer ignores messages that
289 * do not fit the current state (e.g. gsm48_rr.c:2159) */
290 l1ctl_tx_data_ind(ms
, msg
, arfcn
, link_id
, chan_nr
, fn
, snr_db
, signal_dbm
, 0, 0);
292 case GSMTAP_CHANNEL_RACH
:
293 LOGPMS(DVIRPHY
, LOGL_NOTICE
, ms
, "Ignoring unexpected RACH in downlink ?!?\n");
295 case GSMTAP_CHANNEL_PACCH
:
296 case GSMTAP_CHANNEL_PDCH
:
297 if (gprs_dl_block_matches_ms(ms
, msg
, timeslot
))
298 l1ctl_tx_data_ind(ms
, msg
, arfcn
, link_id
, chan_nr
, fn
, snr_db
, signal_dbm
, 0, 0);
299 usf
= get_usf_from_block(msg
);
300 ms_ul_tbf_may_transmit(ms
, arfcn
, timeslot
, fn
, usf
);
302 case GSMTAP_CHANNEL_SDCCH
:
303 case GSMTAP_CHANNEL_CCCH
:
304 case GSMTAP_CHANNEL_PTCCH
:
305 LOGPMS(DVIRPHY
, LOGL_NOTICE
, ms
, "Ignoring unsupported channel type %s\n",
306 get_value_string(gsmtap_gsm_channel_names
, gsmtap_chantype
));
309 LOGPMS(DVIRPHY
, LOGL_NOTICE
, ms
, "Ignoring unknown channel type %s\n",
310 get_value_string(gsmtap_gsm_channel_names
, gsmtap_chantype
));
316 * Receive a gsmtap message from the virt um.
318 * As we do not have a downlink scheduler, but not all dl messages must be processed and thus forwarded to l2, this function also implements some message filtering.
319 * E.g. we do not forward:
321 * - messages with a wrong arfcn
322 * - if in MS_STATE_IDLE_SEARCHING
324 void gsmtapl1_rx_from_virt_um_inst_cb(struct virt_um_inst
*vui
,
327 struct l1ctl_sock_inst
*lsi
= vui
->priv
;
328 struct l1ctl_sock_client
*lsc
;
333 struct gsmtap_hdr
*gh
= msgb_l1(msg
);
334 uint32_t fn
= ntohl(gh
->frame_number
); /* frame number of the rcv msg */
335 uint16_t arfcn
= ntohs(gh
->arfcn
); /* arfcn of the received msg */
336 uint8_t gsmtap_chantype
= gh
->sub_type
; /* gsmtap channel type */
337 uint8_t snr
= gh
->snr_db
; /* signal noise ratio */
338 uint8_t subslot
= gh
->sub_slot
; /* multiframe subslot to send msg in (tch -> 0-26, bcch/ccch -> 0-51) */
339 uint8_t timeslot
= gh
->timeslot
; /* tdma timeslot to send in (0-7) */
340 uint8_t rsl_chantype
; /* rsl chan type (8.58, 9.3.1) */
341 uint8_t link_id
; /* rsl link id tells if this is an ssociated or dedicated link */
342 uint8_t chan_nr
; /* encoded rsl channel type, timeslot and mf subslot */
343 struct gsm_time gtime
;
345 msg
->l2h
= msgb_pull(msg
, sizeof(*gh
));
346 chantype_gsmtap2rsl(gsmtap_chantype
, &rsl_chantype
, &link_id
);
347 /* see TS 08.58 -> 9.3.1 for channel number encoding */
348 chan_nr
= rsl_enc_chan_nr(rsl_chantype
, subslot
, timeslot
);
350 gsm_fn2gsmtime(>ime
, fn
);
352 DEBUGP(DVIRPHY
, "%s Rx from VirtUM: FN=%s chan_nr=0x%02x link_id=0x%02x\n",
353 pseudo_lchan_name(arfcn
, timeslot
, subslot
, gsmtap_chantype
),
354 osmo_dump_gsmtime(>ime
), chan_nr
, link_id
);
356 /* generally ignore all uplink messages received */
357 if (arfcn
& GSMTAP_ARFCN_F_UPLINK
) {
358 LOGP(DVIRPHY
, LOGL_NOTICE
, "Ignoring unexpected uplink message in downlink!\n");
362 /* dispatch the incoming DL message from GSMTAP to each of the registered L1CTL instances */
363 llist_for_each_entry(lsc
, &lsi
->clients
, list
) {
364 l1ctl_from_virt_um(lsc
, msg
, fn
, arfcn
, timeslot
, subslot
, gsmtap_chantype
,
365 chan_nr
, link_id
, snr
);