libosmo-abis/include/osmocom/abis/e1_input.h

408 lines
12 KiB
C

#ifndef _E1_INPUT_H
#define _E1_INPUT_H
#include <stdlib.h>
#include <netinet/in.h>
#include <osmocom/core/linuxlist.h>
#include <osmocom/core/use_count.h>
#include <osmocom/core/timer.h>
#include <osmocom/core/msgb.h>
#include <osmocom/core/select.h>
#include <osmocom/gsm/i460_mux.h>
#include <osmocom/abis/subchan_demux.h>
#include <osmocom/abis/lapd.h>
#define NUM_E1_TS 32
#define E1INP_USE_DEFAULT (-1)
#define LOGPITS(e1ts, ss, level, fmt, args ...) \
LOGP(ss, level, "E1TS(%u:%u) " fmt, (e1ts)->line->num, (e1ts)->num, ## args)
#define LOGPIL(e1l, ss, level, fmt, args ...) \
LOGP(ss, level, "E1L(%u) " fmt, (e1l)->num, ## args)
enum e1inp_sign_type {
E1INP_SIGN_NONE,
E1INP_SIGN_OML,
E1INP_SIGN_RSL,
E1INP_SIGN_OSMO, /* IPA CCM OSMO sub-type */
};
const char *e1inp_signtype_name(enum e1inp_sign_type tp);
extern const struct value_string e1inp_sign_type_names[5];
enum e1inp_ctr {
E1I_CTR_HDLC_ABORT,
E1I_CTR_HDLC_BADFCS,
E1I_CTR_HDLC_OVERR,
E1I_CTR_ALARM,
E1I_CTR_REMOVED,
};
struct e1inp_ts;
struct vty;
struct e1inp_sign_link {
/* list of signalling links */
struct llist_head list;
/* to which timeslot do we belong? */
struct e1inp_ts *ts;
enum e1inp_sign_type type;
/* trx for msg->trx of received msgs */
struct gsm_bts_trx *trx;
/* msgb queue of to-be-transmitted msgs */
struct llist_head tx_list;
/* SAPI and TEI on the E1 TS */
uint8_t sapi;
uint8_t tei;
union {
struct {
uint8_t channel;
} misdn;
} driver;
};
enum e1inp_ts_type {
E1INP_TS_TYPE_NONE,
E1INP_TS_TYPE_SIGN,
E1INP_TS_TYPE_TRAU,
E1INP_TS_TYPE_RAW,
E1INP_TS_TYPE_HDLC,
E1INP_TS_TYPE_I460,
};
const char *e1inp_tstype_name(enum e1inp_ts_type tp);
extern const struct value_string e1inp_ts_type_names[];
/* A timeslot in the E1 interface */
struct e1inp_ts {
enum e1inp_ts_type type;
int num;
/* to which line do we belong ? */
struct e1inp_line *line;
/* LAPD instance, if any */
struct lapd_instance *lapd;
union {
struct {
/* list of all signalling links on this TS */
struct llist_head sign_links;
/* delay for the queue */
int delay;
/* timer when to dequeue next frame */
struct osmo_timer_list tx_timer;
} sign;
struct {
/* subchannel demuxer for frames from E1 */
struct subch_demux demux;
/* subchannel muxer for frames to E1 */
struct subch_mux mux;
} trau;
struct {
/* call-back for every received frame */
void (*recv_cb)(struct e1inp_ts *ts, struct msgb *msg);
/* queue of pending to-be-transmitted msgbs */
struct llist_head tx_queue;
} raw;
struct {
/* call-back for every received frame */
void (*recv_cb)(struct e1inp_ts *ts, struct msgb *msg);
/* queue of pending to-be-transmitted msgbs */
struct llist_head tx_queue;
} hdlc;
struct {
struct osmo_i460_timeslot i460_ts;
} i460;
};
union {
struct {
/* mISDN driver has one fd for each ts */
struct osmo_fd fd;
} misdn;
struct {
/* ip.access driver has one fd for each ts */
struct osmo_fd fd;
/* ipa keep-alive */
struct osmo_fsm_inst* ka_fsm;
} ipaccess;
struct {
/* DAHDI driver has one fd for each ts */
struct osmo_fd fd;
} dahdi;
struct {
/* osmo-e1d driver has one fd for each ts */
struct osmo_fd fd;
} e1d;
struct {
struct osmo_fd fd;
} rs232;
} driver;
struct msgb *pending_msg;
};
#define E1_SUBSLOT_FULL 0xff
struct gsm_e1_subslot {
/* Number of E1 link */
uint8_t e1_nr;
/* Number of E1 TS inside E1 link */
uint8_t e1_ts;
/* Sub-slot within the E1 TS, 0xff (E1_SUBSLOT_FULL) if full TS */
uint8_t e1_ts_ss;
};
enum e1inp_line_role {
E1INP_LINE_R_NONE,
E1INP_LINE_R_BSC,
E1INP_LINE_R_BTS,
E1INP_LINE_R_MAX
};
/* Notes on setting/getting Sa bits (TABLE 5A and 5B of ITU-T G.704)
* The sa_bits byte contains the Sa bits in TS 0, if multi frame is used:
* bit 7 = Sa8, bit 6 = Sa7, bit 5 = Sa5, bit 4 = Sa4, bit 3 = Sa64, bit 2 = Sa63, bit 1 = Sa62, bit 0 = Sa61.
* The sa_bits byte contains the Sa bits in TS 0, if double frame is used:
* bit 7 = Sa8, bit 6 = Sa7, bit 5 = Sa5, bit 4 = Sa4, bit 0 = Sa6.
* The received Sa bits are reported whenever they change (and are stable for some frames, depending on the
* implementation). Before any report, all Sa bits are assumed to be set to 1.
* Setting sa_bits byte will change the transmitted Sa bits on TS0.
* Before setting them, all Sa bits are transmitted as 1.
*/
struct e1inp_driver {
struct llist_head list;
const char *name;
int (*want_write)(struct e1inp_ts *ts);
int (*line_update)(struct e1inp_line *line);
void (*close)(struct e1inp_sign_link *link);
void (*vty_show)(struct vty *vty, struct e1inp_line *line);
int default_delay;
int has_keepalive;
const char *bind_addr;
/* Set Sa bits to transmit in TS0 (MSB to LSB): Sa8 Sa7 Sa5 Sa4 Sa64 Sa63 Sa62 Sa61/Sa6 */
int (*set_sa_bits)(struct e1inp_line *line, uint8_t sa_bits);
};
struct e1inp_line_ops {
union {
struct {
enum e1inp_line_role role; /* BSC or BTS mode. */
const char *addr; /* IP address .*/
void *dev; /* device parameters. */
} ipa;
struct {
const char *port; /* e.g. /dev/ttyUSB0 */
unsigned int delay;
} rs232;
} cfg;
struct e1inp_sign_link * (*sign_link_up)(void *unit_info, struct e1inp_line *line, enum e1inp_sign_type type);
void (*sign_link_down)(struct e1inp_line *line);
/* Called when a new message arrives. -EBADF must be returned if the osmo_fd in link (msg->dst) is destroyed. */
int (*sign_link)(struct msgb *msg);
};
struct e1inp_line {
struct llist_head list;
int refcnt; /* unusued, kept for ABI compat, use_count is used instead */
unsigned int num;
const char *name;
unsigned int port_nr;
char *sock_path;
struct rate_ctr_group *rate_ctr;
/* tcp keepalive configuration */
int keepalive_num_probes; /* 0: disable, num, or E1INP_USE_DEFAULT */
int keepalive_idle_timeout; /* secs, or E1INP_USE_DEFAULT */
int keepalive_probe_interval; /* secs or E1INP_USE_DEFAULT */
/* ipa ping/pong keepalive params */
struct ipa_keepalive_params *ipa_kap;
/* array of timestlots */
struct e1inp_ts ts[NUM_E1_TS];
unsigned int num_ts;
const struct e1inp_line_ops *ops;
struct e1inp_driver *driver;
void *driver_data;
struct osmo_use_count use_count;
/* file name and file descriptor of pcap for this line */
char *pcap_file;
int pcap_fd;
unsigned int connect_timeout;
};
#define e1inp_line_ipa_oml_ts(line) (&line->ts[0])
#define e1inp_line_ipa_rsl_ts(line, trx_id) (((1 + (trx_id)) < NUM_E1_TS) ? (&line->ts[1 + (trx_id)]) : NULL)
/* SS_L_INPUT signals */
enum e1inp_signal_input {
S_L_INP_NONE,
S_L_INP_TEI_UP,
S_L_INP_TEI_DN,
S_L_INP_TEI_UNKNOWN,
S_L_INP_LINE_INIT,
S_L_INP_LINE_ALARM,
S_L_INP_LINE_NOALARM,
S_L_INP_LINE_LOS,
S_L_INP_LINE_NOLOS,
S_L_INP_LINE_AIS,
S_L_INP_LINE_NOAIS,
S_L_INP_LINE_RAI,
S_L_INP_LINE_NORAI,
S_L_INP_LINE_SLIP_RX,
S_L_INP_LINE_SLIP_TX,
S_L_INP_LINE_SA_BITS,
};
extern const struct value_string e1inp_signal_names[];
/* register a driver with the E1 core */
int e1inp_driver_register(struct e1inp_driver *drv);
/* fine a previously registered driver */
struct e1inp_driver *e1inp_driver_find(const char *name);
/* get a line by its ID */
struct e1inp_line *e1inp_line_find(uint8_t e1_nr);
/* create a line in the E1 input core */
struct e1inp_line *e1inp_line_create(uint8_t e1_nr, const char *driver_name);
/* clone one existing E1 input line */
struct e1inp_line *e1inp_line_clone(void *ctx, struct e1inp_line *line, const char *use);
/* increment refcount use of E1 input line */
void e1inp_line_get(struct e1inp_line *line) OSMO_DEPRECATED("Use e1inp_line_get2() instead");
/* decrement refcount use of E1 input line, release if unused */
void e1inp_line_put(struct e1inp_line *line) OSMO_DEPRECATED("Use e1inp_line_put2() instead");
/* Convenience macros for struct foo instances. These are strict about use count errors. */
#define e1inp_line_get2(line, USE) OSMO_ASSERT( osmo_use_count_get_put(&(line)->use_count, USE, 1) == 0 );
#define e1inp_line_put2(line, USE) OSMO_ASSERT( osmo_use_count_get_put(&(line)->use_count, USE, -1) == 0 );
/* bind operations to one E1 input line */
void e1inp_line_bind_ops(struct e1inp_line *line, const struct e1inp_line_ops *ops);
/* find a sign_link for given TEI and SAPI in a TS */
struct e1inp_sign_link *
e1inp_lookup_sign_link(struct e1inp_ts *ts, uint8_t tei,
uint8_t sapi);
/* create a new signalling link in a E1 timeslot */
struct e1inp_sign_link *
e1inp_sign_link_create(struct e1inp_ts *ts, enum e1inp_sign_type type,
struct gsm_bts_trx *trx, uint8_t tei,
uint8_t sapi);
/* configure and initialize one signalling e1inp_ts */
int e1inp_ts_config_sign(struct e1inp_ts *ts, struct e1inp_line *line);
/* configure and initialize one timeslot dedicated to TRAU frames. */
int e1inp_ts_config_trau(struct e1inp_ts *ts, struct e1inp_line *line,
int (*trau_rcv_cb)(struct subch_demux *dmx, int ch,
const ubit_t *data, int len, void *_priv));
/* configure and initialize one timeslot dedicated to RAW frames */
int e1inp_ts_config_raw(struct e1inp_ts *ts, struct e1inp_line *line,
void (*raw_recv_cb)(struct e1inp_ts *ts,
struct msgb *msg));
/* configure and initialize one timeslot dedicated to HDLC frames */
int e1inp_ts_config_hdlc(struct e1inp_ts *ts, struct e1inp_line *line,
void (*hdlc_recv_cb)(struct e1inp_ts *ts,
struct msgb *msg));
/* configure and initialize one timeslot dedicated to nothing */
int e1inp_ts_config_none(struct e1inp_ts *ts, struct e1inp_line *line);
/*
* configure Sa bits on TS0, if supported by driver (TABLE 5A and 5B of ITU-T G.704)
* sa_bits (MSB to LSB): Sa8 Sa7 Sa5 Sa4 Sa64 Sa63 Sa62 Sa61/Sa6
*/
int e1inp_ts_set_sa_bits(struct e1inp_line *line, uint8_t sa_bits);
/* obtain a string identifier/name for the given timeslot */
void e1inp_ts_name(char *out, size_t out_len, const struct e1inp_ts *ts);
/* Receive a packet from the E1 driver */
int e1inp_rx_ts(struct e1inp_ts *ts, struct msgb *msg,
uint8_t tei, uint8_t sapi);
int e1inp_rx_ts_lapd(struct e1inp_ts *e1i_ts, struct msgb *msg);
/* called by driver if it wants to transmit on a given TS */
struct msgb *e1inp_tx_ts(struct e1inp_ts *e1i_ts,
struct e1inp_sign_link **sign_link);
/* called by driver in case some kind of link state event */
int e1inp_event(struct e1inp_ts *ts, int evt, uint8_t tei, uint8_t sapi);
/* L2->L3 */
void e1inp_dlsap_up(struct osmo_dlsap_prim *odp, uint8_t tei, uint8_t sapi,
void *rx_cbdata);
/* Write LAPD frames to the fd. */
OSMO_DEPRECATED("Use e1_set_pcap_fd2() instead")
int e1_set_pcap_fd(int fd);
int e1_set_pcap_fd2(struct e1inp_line *line, int fd);
/* called by TRAU muxer to obtain the destination mux entity */
struct subch_mux *e1inp_get_mux(uint8_t e1_nr, uint8_t ts_nr);
/* on an IPA BTS, the BTS needs to establish the RSL connection much
* later than the OML connection. */
int e1inp_ipa_bts_rsl_connect(struct e1inp_line *line,
const char *rem_addr, uint16_t rem_port);
int e1inp_ipa_bts_rsl_connect_n(struct e1inp_line *line,
const char *rem_addr, uint16_t rem_port,
uint8_t trx_nr);
int e1inp_ipa_bts_rsl_close_n(struct e1inp_line *line, uint8_t trx_nr);
void e1inp_sign_link_destroy(struct e1inp_sign_link *link);
int e1inp_line_update(struct e1inp_line *line);
int e1inp_vty_init(void);
/* activate superchannel or deactive to use timeslots. only valid for unixsocket driver */
void e1inp_ericsson_set_altc(struct e1inp_line *unixlinue, int superchannel);
extern struct llist_head e1inp_driver_list;
extern struct llist_head e1inp_line_list;
/* XXX */
struct input_signal_data {
enum e1inp_sign_type link_type;
uint8_t tei;
uint8_t sapi;
uint8_t ts_nr;
/* received Sa bits in TS0 (MSB to LSB): Sa8 Sa7 Sa5 Sa4 Sa64 Sa63 Sa62 Sa61/Sa6 */
uint8_t sa_bits;
struct gsm_bts_trx *trx;
struct e1inp_line *line;
};
int abis_sendmsg(struct msgb *msg);
int abis_rsl_sendmsg(struct msgb *msg);
int e1inp_ts_send_raw(struct e1inp_ts *ts, struct msgb *msg);
int e1inp_ts_send_hdlc(struct e1inp_ts *ts, struct msgb *msg);
#endif /* _E1_INPUT_H */