diff options
Diffstat (limited to 'include/osmocom/bsc/gsm_data.h')
-rw-r--r-- | include/osmocom/bsc/gsm_data.h | 357 |
1 files changed, 266 insertions, 91 deletions
diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h index 272b192ce..ce563ef17 100644 --- a/include/osmocom/bsc/gsm_data.h +++ b/include/osmocom/bsc/gsm_data.h @@ -14,13 +14,13 @@ #include <osmocom/core/stat_item.h> #include <osmocom/gsm/bts_features.h> #include <osmocom/gsm/protocol/gsm_08_08.h> +#include <osmocom/gsm/gsm0808.h> #include <osmocom/gsm/gsm48.h> #include <osmocom/core/fsm.h> #include <osmocom/crypt/auth.h> #include <osmocom/bsc/rest_octets.h> -#include <osmocom/bsc/handover.h> #include <osmocom/core/bitvec.h> #include <osmocom/gsm/gsm_utils.h> @@ -31,6 +31,8 @@ #include <osmocom/bsc/meas_rep.h> #include <osmocom/bsc/bsc_msg_filter.h> #include <osmocom/bsc/acc_ramp.h> +#include <osmocom/bsc/gsm_timers.h> +#include <osmocom/bsc/neighbor_ident.h> #define GSM_T3122_DEFAULT 10 @@ -38,6 +40,7 @@ struct mgcp_client_conf; struct mgcp_client; struct mgcp_ctx; struct gsm0808_cell_id; +struct mgw_endpoint; /** annotations for msgb ownership */ #define __uses @@ -46,6 +49,7 @@ struct gsm0808_cell_id; struct bsc_subscr; struct gprs_ra_id; +struct handover; #define OBSC_LINKID_CB(__msgb) (__msgb)->cb[3] @@ -95,6 +99,96 @@ enum subscr_sccp_state { SUBSCR_SCCP_ST_CONNECTED }; +struct assignment_request { + bool aoip; + + uint16_t msc_assigned_cic; + + char msc_rtp_addr[INET_ADDRSTRLEN]; + uint16_t msc_rtp_port; + + enum gsm48_chan_mode chan_mode; + bool full_rate; +}; + +struct assignment_fsm_data { + struct assignment_request req; + bool requires_voice_stream; + + struct osmo_fsm_inst *fi; + struct gsm_lchan *new_lchan; + + /* Whether this assignment triggered creation of the MGW endpoint: if the assignment + * fails, we will release that again as soon as possible. (If false, the endpoint already + * existed before or isn't needed at all.)*/ + struct mgwep_ci *created_ci_for_msc; + + enum gsm0808_cause failure_cause; + enum gsm48_rr_cause rr_cause; + + bool result_rate_ctr_done; +}; + +enum hodec_id { + HODEC_NONE, + HODEC1 = 1, + HODEC2 = 2, + HODEC_USER, + HODEC_REMOTE, +}; + +/* For example, to count specific kinds of ongoing handovers, it is useful to be able to OR-combine + * scopes. */ +enum handover_scope { + HO_NO_HANDOVER = 0, + HO_INTRA_CELL = 0x1, + HO_INTRA_BSC = 0x2, + HO_INTER_BSC_OUT = 0x4, + HO_INTER_BSC_IN = 0x8, + HO_SCOPE_ALL = 0xffff, +}; + +extern const struct value_string handover_scope_names[]; +inline static const char *handover_scope_name(enum handover_scope val) +{ return get_value_string(handover_scope_names, val); } + +struct handover_out_req { + enum hodec_id from_hodec_id; + struct gsm_lchan *old_lchan; + struct neighbor_ident_key target_nik; + enum gsm_chan_t new_lchan_type; /*< leave GSM_LCHAN_NONE to use same as old_lchan */ +}; + +struct handover_in_req { + struct gsm0808_channel_type ct; + struct gsm0808_speech_codec_list scl; + struct gsm0808_encrypt_info ei; + struct gsm_classmark classmark; + struct gsm0808_cell_id cell_id_serving; + char cell_id_serving_name[64]; + struct gsm0808_cell_id cell_id_target; + char cell_id_target_name[64]; + uint16_t msc_assigned_cic; + char msc_assigned_rtp_addr[INET_ADDRSTRLEN]; + uint16_t msc_assigned_rtp_port; +}; + +struct handover { + struct osmo_fsm_inst *fi; + + enum hodec_id from_hodec_id; + enum handover_scope scope; + enum gsm_chan_t new_lchan_type; + struct neighbor_ident_key target_cell; + + uint8_t ho_ref; + struct gsm_bts *new_bts; + struct gsm_lchan *new_lchan; + bool async; + struct handover_in_req inter_bsc_in; + struct mgwep_ci *created_ci_for_msc; +}; + /* active radio connection of a mobile subscriber */ struct gsm_subscriber_connection { /* global linked list of subscriber_connections */ @@ -112,11 +206,10 @@ struct gsm_subscriber_connection { /* the primary / currently active lchan to the BTS/subscriber */ struct gsm_lchan *lchan; - /* handover information, if a handover is pending for this conn. */ - struct bsc_handover *ho; + struct assignment_fsm_data assignment; - /* the future allocated but not yet used lchan during ASSIGNMENT */ - struct gsm_lchan *secondary_lchan; + /* handover information, if a handover is pending for this conn. */ + struct handover ho; /* buffer/cache for classmark of the ME of the subscriber */ struct gsm_classmark classmark; @@ -137,7 +230,6 @@ struct gsm_subscriber_connection { * i.e. by heeding the "Codec list (MSC Preferred)", we inherently heed the MS bearer * capabilities, which the MSC is required to translate into the codec list. */ struct gsm0808_speech_codec_list codec_list; - bool codec_list_present; /* flag to prevent multiple simultaneous ciphering commands */ int ciphering_handled; @@ -163,29 +255,24 @@ struct gsm_subscriber_connection { /* for audio handling */ struct { - uint16_t cic; - uint32_t rtp_ip; - int rtp_port; - /* RTP address of the remote end (assigned by MSC through assignment request) */ - struct sockaddr_storage aoip_rtp_addr_remote; - - /* Local RTP address (reported back to the MSC by us with the - * assignment complete message) */ - struct sockaddr_storage aoip_rtp_addr_local; + uint16_t msc_assigned_cic; - /* FSM instance to control the BTS sided RTP connection */ - struct osmo_fsm_inst *fi_bts; + /* RTP address where the MSC expects us to send the RTP stream coming from the BTS. */ + char msc_assigned_rtp_addr[INET_ADDRSTRLEN]; + uint16_t msc_assigned_rtp_port; - /* FSM instance to control the MSC sided RTP connection */ - struct osmo_fsm_inst *fi_msc; + /* The endpoint at the MGW used to join both BTS and MSC side connections, e.g. + * "rtpbridge/23@mgw". */ + struct mgw_endpoint *mgw_endpoint; - /* Endpoint identifier of the MGCP endpoint the connection uses */ - char *mgw_endpoint; + /* The connection identifier of the mgw_endpoint used to transceive RTP towards the MSC. + * (The BTS side CI is handled by struct gsm_lchan and the lchan_fsm.) */ + struct mgwep_ci *mgw_endpoint_ci_msc; - /* Channel rate flag, FR=1, HR=0, Invalid=-1 */ + /* Channel rate flag requested by the MSC, FR=1, HR=0, Invalid=-1 */ int full_rate; - /* Channel mode flag (signaling or voice channel) */ + /* Channel mode requested by the MSC (signalling or voice channel) */ enum gsm48_chan_mode chan_mode; } user_plane; @@ -298,18 +385,6 @@ struct om2k_mo { #define LCHAN_SAPI_UNUSED 0 #define LCHAN_SAPI_MS 1 #define LCHAN_SAPI_NET 2 -#define LCHAN_SAPI_REL 3 - -/* state of a logical channel */ -enum gsm_lchan_state { - LCHAN_S_NONE, /* channel is not active */ - LCHAN_S_ACT_REQ, /* channel activation requested */ - LCHAN_S_ACTIVE, /* channel is active and operational */ - LCHAN_S_REL_REQ, /* channel release has been requested */ - LCHAN_S_REL_ERR, /* channel is in an error state */ - LCHAN_S_BROKEN, /* channel is somehow unusable */ - LCHAN_S_INACTIVE, /* channel is set inactive */ -}; /* BTS ONLY */ #define MAX_NUM_UL_MEAS 104 @@ -386,11 +461,68 @@ struct gsm_encr { bsc_subscr_name(lchan && lchan->conn ? lchan->conn->bsub : NULL), \ ## args) +/* usage: + * struct gsm_lchan *lchan; + * struct gsm_bts_trx_ts *ts = get_some_timeslot(); + * ts_for_each_lchan(lchan, ts) { + * LOGPLCHAN(DMAIN, LOGL_DEBUG, "hello world\n"); + * } + * Iterate only those lchans that have an FSM allocated. */ +#define ts_for_each_lchan(lchan, ts) ts_as_pchan_for_each_lchan(lchan, ts, (ts)->pchan_is) + +/* Same as ts_for_each_lchan() but with an explicit pchan kind (GSM_PCHAN_* constant). + * Iterate only those lchans that have an FSM allocated. */ +#define ts_as_pchan_for_each_lchan(lchan, ts, as_pchan) \ + for (lchan = (ts)->lchan; \ + ((lchan - (ts)->lchan) < ARRAY_SIZE((ts)->lchan)) \ + && lchan->fi \ + && lchan->nr < pchan_subslots(as_pchan); \ + lchan++) + +enum lchan_activate_mode { + FOR_NONE, + FOR_MS_CHANNEL_REQUEST, + FOR_ASSIGNMENT, + FOR_HANDOVER, + FOR_VTY, +}; + +extern const struct value_string lchan_activate_mode_names[]; +static inline const char *lchan_activate_mode_name(enum lchan_activate_mode activ_for) +{ return get_value_string(lchan_activate_mode_names, activ_for); } + struct gsm_lchan { /* The TS that we're part of */ struct gsm_bts_trx_ts *ts; /* The logical subslot number in the TS */ uint8_t nr; + char *name; + + struct osmo_fsm_inst *fi; + struct mgwep_ci *mgw_endpoint_ci_bts; + + struct { + enum lchan_activate_mode activ_for; + bool concluded; /*< true as soon as LCHAN_ST_ESTABLISHED is reached */ + bool requires_voice_stream; + bool mgw_endpoint_available; + uint16_t msc_assigned_cic; + enum gsm0808_cause gsm0808_error_cause; + struct gsm_lchan *re_use_mgw_endpoint_from_lchan; + } activate; + + /* If an event to release the lchan comes in while still waiting for responses, just mark this + * flag, so that the lchan will gracefully release at the next sensible junction. */ + bool release_requested; + bool deact_sacch; + + char *last_error; + + /* There is an RSL error cause of value 0, so we need a separate flag. */ + bool release_in_error; + /* RSL error code, RSL_ERR_* */ + uint8_t rsl_error_cause; + /* The logical channel type */ enum gsm_chan_t type; /* RSL channel mode */ @@ -398,9 +530,6 @@ struct gsm_lchan { /* If TCH, traffic channel mode */ enum gsm48_chan_mode tch_mode; enum lchan_csd_mode csd_mode; - /* State */ - enum gsm_lchan_state state; - const char *broken_reason; /* Power levels for MS and BTS */ uint8_t bs_power; uint8_t ms_power; @@ -415,15 +544,14 @@ struct gsm_lchan { uint8_t sapis[8]; struct { - uint32_t bound_ip; - uint32_t connect_ip; + uint32_t bound_ip; /*< where the BTS receives RTP */ uint16_t bound_port; + uint32_t connect_ip; /*< where the BTS sends RTP to (MGW) */ uint16_t connect_port; uint16_t conn_id; uint8_t rtp_payload; uint8_t rtp_payload2; uint8_t speech_mode; - struct rtp_socket *rtp_socket; /* info we need to postpone the AoIP * assignment completed message */ @@ -435,16 +563,6 @@ struct gsm_lchan { uint8_t rqd_ta; - char *name; - - struct osmo_timer_list T3101; - struct osmo_timer_list T3109; - struct osmo_timer_list T3111; - struct osmo_timer_list error_timer; - struct osmo_timer_list act_timer; - struct osmo_timer_list rel_work; - uint8_t error_cause; - /* table of neighbor cell measurements */ struct neigh_meas_proc neigh_meas[MAX_NEIGH_MEAS]; @@ -455,43 +573,38 @@ struct gsm_lchan { uint8_t meas_rep_last_seen_nr; /* GSM Random Access data */ + /* TODO: don't allocate this, rather keep an "is_present" flag */ struct gsm48_req_ref *rqd_ref; struct gsm_subscriber_connection *conn; - - struct { - /* channel activation type and handover ref */ - uint8_t act_type; - uint8_t ho_ref; - struct gsm48_req_ref *rqd_ref; - uint8_t rqd_ta; - } dyn; }; -enum { - TS_F_PDCH_ACTIVE = 0x1000, - TS_F_PDCH_ACT_PENDING = 0x2000, - TS_F_PDCH_DEACT_PENDING = 0x4000, - TS_F_PDCH_PENDING_MASK = (TS_F_PDCH_ACT_PENDING | TS_F_PDCH_DEACT_PENDING), -} gsm_bts_trx_ts_flags; - /* One Timeslot in a TRX */ struct gsm_bts_trx_ts { struct gsm_bts_trx *trx; - bool initialized; - /* number of this timeslot at the TRX */ uint8_t nr; - enum gsm_phys_chan_config pchan; - - struct { - enum gsm_phys_chan_config pchan_is; - enum gsm_phys_chan_config pchan_want; - struct msgb *pending_chan_activ; - } dyn; + struct osmo_fsm_inst *fi; + char *last_errmsg; + + /* vty phys_chan_config setting, not necessarily in effect in case it was changed in the telnet + * vty after OML activation. Gets written on vty 'write file'. */ + enum gsm_phys_chan_config pchan_from_config; + /* When the timeslot OML is established, pchan_from_config is copied here. This is the pchan + * currently in effect; for dynamic ts, this is the dyn kind (GSM_PCHAN_TCH_F_TCH_H_PDCH or + * GSM_PCHAN_TCH_F_PDCH) and does not show the pchan type currently active. */ + enum gsm_phys_chan_config pchan_on_init; + /* This is the *actual* pchan type currently active. For dynamic timeslots, this reflects either + * GSM_PCHAN_NONE or one of the standard GSM_PCHAN_TCH_F, GSM_PCHAN_TCH_H, GSM_PCHAN_PDCH. + * Callers can use this transparently without being aware of dyn ts. */ + enum gsm_phys_chan_config pchan_is; + + /* After a PDCH ACT NACK, we shall not infinitely loop to try and ACT again. + * Also marks a timeslot where PDCH was deactivated by VTY. This is cleared whenever a timeslot + * enters IN_USE state, i.e. after each TCH use we try to PDCH ACT once again. */ + bool pdch_act_allowed; - unsigned int flags; struct gsm_abis_mo mo; struct tlv_parsed nm_attr; uint8_t nm_chan_comb; @@ -1033,9 +1146,12 @@ enum gsm_bts_type_variant str2btsvariant(const char *arg); const char *btsvariant2str(enum gsm_bts_type_variant v); extern const struct value_string gsm_chreq_descs[]; -const struct value_string gsm_pchant_names[13]; -const struct value_string gsm_pchant_descs[13]; +extern const struct value_string gsm_pchant_names[]; +extern const struct value_string gsm_pchant_descs[]; +extern const struct value_string gsm_pchan_ids[]; const char *gsm_pchan_name(enum gsm_phys_chan_config c); +static inline const char *gsm_pchan_id(enum gsm_phys_chan_config c) +{ return get_value_string(gsm_pchan_ids, c); } enum gsm_phys_chan_config gsm_pchan_parse(const char *name); const char *gsm_lchant_name(enum gsm_chan_t c); const char *gsm_chreq_name(enum gsm_chreq_reason_t c); @@ -1043,7 +1159,6 @@ char *gsm_trx_name(const struct gsm_bts_trx *trx); char *gsm_ts_name(const struct gsm_bts_trx_ts *ts); char *gsm_ts_and_pchan_name(const struct gsm_bts_trx_ts *ts); char *gsm_lchan_name_compute(const struct gsm_lchan *lchan); -const char *gsm_lchans_name(enum gsm_lchan_state s); static inline char *gsm_lchan_name(const struct gsm_lchan *lchan) { @@ -1089,7 +1204,7 @@ struct gsm_lchan *rsl_lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr, int *rc); enum gsm_phys_chan_config ts_pchan(struct gsm_bts_trx_ts *ts); -uint8_t ts_subslots(struct gsm_bts_trx_ts *ts); +uint8_t pchan_subslots(enum gsm_phys_chan_config pchan); bool ts_is_tch(struct gsm_bts_trx_ts *ts); @@ -1159,11 +1274,32 @@ enum { }; enum { + BSC_CTR_ASSIGNMENT_ATTEMPTED, + BSC_CTR_ASSIGNMENT_COMPLETED, + BSC_CTR_ASSIGNMENT_STOPPED, + BSC_CTR_ASSIGNMENT_NO_CHANNEL, + BSC_CTR_ASSIGNMENT_TIMEOUT, + BSC_CTR_ASSIGNMENT_FAILED, + BSC_CTR_ASSIGNMENT_ERROR, BSC_CTR_HANDOVER_ATTEMPTED, + BSC_CTR_HANDOVER_COMPLETED, + BSC_CTR_HANDOVER_STOPPED, BSC_CTR_HANDOVER_NO_CHANNEL, BSC_CTR_HANDOVER_TIMEOUT, - BSC_CTR_HANDOVER_COMPLETED, BSC_CTR_HANDOVER_FAILED, + BSC_CTR_HANDOVER_ERROR, + BSC_CTR_INTER_BSC_HO_OUT_ATTEMPTED, + BSC_CTR_INTER_BSC_HO_OUT_COMPLETED, + BSC_CTR_INTER_BSC_HO_OUT_STOPPED, + BSC_CTR_INTER_BSC_HO_OUT_TIMEOUT, + BSC_CTR_INTER_BSC_HO_OUT_ERROR, + BSC_CTR_INTER_BSC_HO_IN_ATTEMPTED, + BSC_CTR_INTER_BSC_HO_IN_COMPLETED, + BSC_CTR_INTER_BSC_HO_IN_STOPPED, + BSC_CTR_INTER_BSC_HO_IN_NO_CHANNEL, + BSC_CTR_INTER_BSC_HO_IN_FAILED, + BSC_CTR_INTER_BSC_HO_IN_TIMEOUT, + BSC_CTR_INTER_BSC_HO_IN_ERROR, BSC_CTR_PAGING_ATTEMPTED, BSC_CTR_PAGING_DETACHED, BSC_CTR_PAGING_RESPONDED, @@ -1171,11 +1307,42 @@ enum { }; static const struct rate_ctr_desc bsc_ctr_description[] = { - [BSC_CTR_HANDOVER_ATTEMPTED] = {"handover:attempted", "Received handover attempts."}, - [BSC_CTR_HANDOVER_NO_CHANNEL] = {"handover:no_channel", "Sent no channel available responses."}, - [BSC_CTR_HANDOVER_TIMEOUT] = {"handover:timeout", "Timeouts of timer T3103."}, - [BSC_CTR_HANDOVER_COMPLETED] = {"handover:completed", "Received handover completed."}, - [BSC_CTR_HANDOVER_FAILED] = {"handover:failed", "Received HO FAIL messages."}, + [BSC_CTR_ASSIGNMENT_ATTEMPTED] = {"assignment:attempted", "Intra-cell re-assignment attempts."}, + [BSC_CTR_ASSIGNMENT_COMPLETED] = {"assignment:completed", "Intra-cell re-assignment completed."}, + [BSC_CTR_ASSIGNMENT_STOPPED] = {"assignment:stopped", "Connection ended during re-assignment."}, + [BSC_CTR_ASSIGNMENT_NO_CHANNEL] = {"assignment:no_channel", "Failure to allocate lchan for re-assignment."}, + [BSC_CTR_ASSIGNMENT_TIMEOUT] = {"assignment:timeout", "Re-assignment timed out."}, + [BSC_CTR_ASSIGNMENT_FAILED] = {"assignment:failed", "Received FAIL message."}, + [BSC_CTR_ASSIGNMENT_ERROR] = {"assignment:error", "Re-assigment failed for other reason."}, + + [BSC_CTR_HANDOVER_ATTEMPTED] = {"handover:attempted", "Intra-BSC handover attempts."}, + [BSC_CTR_HANDOVER_COMPLETED] = {"handover:completed", "Intra-BSC handover completed."}, + [BSC_CTR_HANDOVER_STOPPED] = {"handover:stopped", "Connection ended during HO."}, + [BSC_CTR_HANDOVER_NO_CHANNEL] = {"handover:no_channel", "Failure to allocate lchan for HO."}, + [BSC_CTR_HANDOVER_TIMEOUT] = {"handover:timeout", "Handover timed out."}, + [BSC_CTR_HANDOVER_FAILED] = {"handover:failed", "Received Handover Fail messages."}, + [BSC_CTR_HANDOVER_ERROR] = {"handover:error", "Re-assigment failed for other reason."}, + + [BSC_CTR_INTER_BSC_HO_OUT_ATTEMPTED] = {"interbsc_ho_out:attempted", + "Attempts to handover to remote BSS."}, + [BSC_CTR_INTER_BSC_HO_OUT_COMPLETED] = {"interbsc_ho_out:completed", + "Handover to remote BSS completed."}, + [BSC_CTR_INTER_BSC_HO_OUT_STOPPED] = {"interbsc_ho_out:stopped", "Connection ended during HO."}, + [BSC_CTR_INTER_BSC_HO_OUT_TIMEOUT] = {"interbsc_ho_out:timeout", "Handover timed out."}, + [BSC_CTR_INTER_BSC_HO_OUT_ERROR] = {"interbsc_ho_out:error", + "Handover to remote BSS failed for other reason."}, + + [BSC_CTR_INTER_BSC_HO_IN_ATTEMPTED] = {"interbsc_ho_in:attempted", + "Attempts to handover from remote BSS."}, + [BSC_CTR_INTER_BSC_HO_IN_COMPLETED] = {"interbsc_ho_in:completed", + "Handover from remote BSS completed."}, + [BSC_CTR_INTER_BSC_HO_IN_STOPPED] = {"interbsc_ho_in:stopped", "Connection ended during HO."}, + [BSC_CTR_INTER_BSC_HO_IN_NO_CHANNEL] = {"interbsc_ho_in:no_channel", + "Failure to allocate lchan for HO."}, + [BSC_CTR_INTER_BSC_HO_IN_TIMEOUT] = {"interbsc_ho_in:timeout", "Handover from remote BSS timed out."}, + [BSC_CTR_INTER_BSC_HO_IN_FAILED] = {"interbsc_ho_in:failed", "Received Handover Fail message."}, + [BSC_CTR_INTER_BSC_HO_IN_ERROR] = {"interbsc_ho_in:error", + "Handover from remote BSS failed for other reason."}, [BSC_CTR_PAGING_ATTEMPTED] = {"paging:attempted", "Paging attempts for a subscriber."}, [BSC_CTR_PAGING_DETACHED] = {"paging:detached", "Paging request send failures because no responsible BTS was found."}, @@ -1272,6 +1439,11 @@ struct gsm_network { struct neighbor_ident_list *neighbor_bss_cells; }; +struct gsm_audio_support { + uint8_t hr : 1, + ver : 7; +}; + static inline const struct osmo_location_area_id *bts_lai(struct gsm_bts *bts) { static struct osmo_location_area_id lai; @@ -1407,12 +1579,15 @@ void gsm_bts_set_radio_link_timeout(struct gsm_bts *bts, int value); bool classmark_is_r99(struct gsm_classmark *cm); -void gsm_ts_check_init(struct gsm_bts_trx_ts *ts); -void gsm_trx_mark_all_ts_uninitialized(struct gsm_bts_trx *trx); -void gsm_bts_mark_all_ts_uninitialized(struct gsm_bts *bts); - bool trx_is_usable(const struct gsm_bts_trx *trx); +bool ts_is_usable(const struct gsm_bts_trx_ts *ts); + +int gsm_lchan_type_by_pchan(enum gsm_phys_chan_config pchan); +enum gsm_phys_chan_config gsm_pchan_by_lchan_type(enum gsm_chan_t type); + +void gsm_bts_all_ts_dispatch(struct gsm_bts *bts, uint32_t ts_ev, void *data); +void gsm_trx_all_ts_dispatch(struct gsm_bts_trx *trx, uint32_t ts_ev, void *data); -bool on_gsm_ts_init(struct gsm_bts_trx_ts *ts); +int bts_count_free_ts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan); #endif /* _GSM_DATA_H */ |