#ifndef _E1_INPUT_H #define _E1_INPUT_H #include #include #include #include #include #include #include #include #include #include #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 */