diff options
39 files changed, 2 insertions, 10806 deletions
diff --git a/configure.ac b/configure.ac index ccfce19b0..bcf890cee 100644 --- a/configure.ac +++ b/configure.ac @@ -49,10 +49,6 @@ PKG_CHECK_MODULES(LIBOSMOSIGTRAN, libosmo-sigtran >= 0.9.0) PKG_CHECK_MODULES(LIBOSMOSCCP, libosmo-sccp >= 0.9.0) PKG_CHECK_MODULES(LIBOSMOMGCPCLIENT, libosmo-mgcp-client >= 1.3.0) -#NOTE: osmo-bsc does not depend on libosmo-legacy-mgcp anymore, but we still -# need the dependancy for osmo-bsc-nat, which still uses the old API. -PKG_CHECK_MODULES(LIBOSMOLEGACYMGCP, libosmo-legacy-mgcp >= 1.3.0) - dnl checks for header files AC_HEADER_STDC @@ -182,8 +178,6 @@ AC_OUTPUT( tests/gsm0408/Makefile tests/channel/Makefile tests/bsc/Makefile - tests/bsc-nat/Makefile - tests/bsc-nat-trie/Makefile tests/abis/Makefile tests/subscr/Makefile tests/nanobts_omlattr/Makefile diff --git a/debian/control b/debian/control index c2627a1c6..03e5a14e2 100644 --- a/debian/control +++ b/debian/control @@ -16,7 +16,6 @@ Build-Depends: debhelper (>=9), libosmo-sigtran-dev (>= 0.8.0), libosmo-abis-dev (>= 0.3.2), libosmo-netif-dev (>= 0.1.0), - libosmo-legacy-mgcp-dev (>= 1.0.0), libosmo-mgcp-client-dev (>= 1.2.0) Standards-Version: 3.9.8 Vcs-Git: git://git.osmocom.org/osmo-bsc.git diff --git a/doc/examples/osmo-bsc_nat/black-list.cfg b/doc/examples/osmo-bsc_nat/black-list.cfg deleted file mode 100644 index d36179d37..000000000 --- a/doc/examples/osmo-bsc_nat/black-list.cfg +++ /dev/null @@ -1 +0,0 @@ -678012512671923:6:6: diff --git a/doc/examples/osmo-bsc_nat/bscs.cfg b/doc/examples/osmo-bsc_nat/bscs.cfg deleted file mode 100644 index 176debe42..000000000 --- a/doc/examples/osmo-bsc_nat/bscs.cfg +++ /dev/null @@ -1,13 +0,0 @@ -nat - bsc 0 - token lol - location_area_code 1234 - description bsc - max-endpoints 32 - paging forbidden 0 - bsc 1 - token wat - location_area_code 5678 - description bsc - max-endpoints 32 - paging forbidden 0 diff --git a/doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg b/doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg deleted file mode 100644 index e835e068a..000000000 --- a/doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg +++ /dev/null @@ -1,66 +0,0 @@ -! -! OsmoBSCNAT (0.12.0.266-2daa9) configuration saved from vty -!! -! -log stderr - logging filter all 1 - logging color 1 - logging timestamp 0 - logging level all debug - logging level rll notice - logging level cc notice - logging level mm notice - logging level rr notice - logging level rsl notice - logging level nm info - logging level mncc notice - logging level pag notice - logging level meas notice - logging level sccp notice - logging level msc notice - logging level mgcp notice - logging level ho notice - logging level db notice - logging level ref notice - logging level gprs debug - logging level ns info - logging level bssgp debug - logging level llc debug - logging level sndcp debug - logging level nat notice - logging level ctrl notice - logging level smpp debug - logging level lglobal notice - logging level llapd notice - logging level linp notice - logging level lmux notice - logging level lmi notice - logging level lmib notice - logging level lsms notice -! -line vty - no login -! -mgcp - bind ip 0.0.0.0 - bind port 2427 - rtp bts-base 4000 - rtp net-base 16000 - rtp ip-dscp 0 - no rtcp-omit - sdp audio-payload number 126 - sdp audio-payload name AMR/8000 - loop 0 - number endpoints 1 - call-agent ip 127.0.0.1 - rtp transcoder-base 0 - transcoder-remote-base 4000 -nat - msc ip 127.0.0.1 - msc port 5000 - timeout auth 2 - timeout ping 20 - timeout pong 5 - ip-dscp 0 - bscs-config-file bscs.cfg - access-list bla imsi-allow ^11$ diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am index b25dfd833..80f9b01ea 100644 --- a/include/osmocom/bsc/Makefile.am +++ b/include/osmocom/bsc/Makefile.am @@ -7,9 +7,6 @@ noinst_HEADERS = \ arfcn_range_encode.h \ bsc_msc.h \ bsc_msg_filter.h \ - bsc_nat.h \ - bsc_nat_callstats.h \ - bsc_nat_sccp.h \ bsc_rll.h \ bsc_subscriber.h \ bsc_subscr_conn_fsm.h \ @@ -32,7 +29,6 @@ noinst_HEADERS = \ meas_feed.h \ meas_rep.h \ misdn.h \ - nat_rewrite_trie.h \ network_listen.h \ openbscdefines.h \ osmo_bsc.h \ diff --git a/include/osmocom/bsc/bsc_nat.h b/include/osmocom/bsc/bsc_nat.h deleted file mode 100644 index bd78b9d43..000000000 --- a/include/osmocom/bsc/bsc_nat.h +++ /dev/null @@ -1,469 +0,0 @@ -/* - * (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010-2012 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#ifndef BSC_NAT_H -#define BSC_NAT_H - -#include <osmocom/legacy_mgcp/mgcp.h> - -#include "bsc_msg_filter.h" - -#include <osmocom/core/select.h> -#include <osmocom/core/msgb.h> -#include <osmocom/core/msgfile.h> -#include <osmocom/core/timer.h> -#include <osmocom/core/write_queue.h> -#include <osmocom/core/rate_ctr.h> -#include <osmocom/core/statistics.h> -#include <osmocom/gsm/protocol/gsm_04_08.h> - -#include <regex.h> -#include <stdbool.h> - -#define DIR_BSC 1 -#define DIR_MSC 2 - -#define PAGIN_GROUP_UNASSIGNED -1 - -struct sccp_source_reference; -struct nat_sccp_connection; -struct bsc_nat_parsed; -struct bsc_nat; -struct bsc_nat_ussd_con; -struct nat_rewrite_rule; - -/* - * Is this terminated to the MSC, to the local machine (release - * handling for IMSI filtering) or to a USSD provider? - */ -enum { - NAT_CON_END_MSC, - NAT_CON_END_LOCAL, - NAT_CON_END_USSD, -}; - -/* - * Pending command entry - */ -struct bsc_cmd_list { - struct llist_head list_entry; - - struct osmo_timer_list timeout; - - /* The NATed ID used on the bsc_con*/ - int nat_id; - - /* The command from the control connection */ - struct ctrl_cmd *cmd; -}; - -/* - * Per BSC data structure - */ -struct bsc_connection { - struct llist_head list_entry; - - /* do we know anything about this BSC? */ - int authenticated; - uint8_t last_rand[16]; - - /* the fd we use to communicate */ - struct osmo_wqueue write_queue; - - /* incoming message buffer */ - struct msgb *pending_msg; - - /* the BSS associated */ - struct bsc_config *cfg; - - /* a timeout node */ - struct osmo_timer_list id_timeout; - - /* pong timeout */ - struct osmo_timer_list ping_timeout; - struct osmo_timer_list pong_timeout; - - /* mgcp related code */ - char *_endpoint_status; - int number_multiplexes; - int max_endpoints; - int last_endpoint; - int next_transaction; - uint32_t pending_dlcx_count; - struct llist_head pending_dlcx; - - /* track the pending commands for this BSC */ - struct llist_head cmd_pending; - int last_id; - - /* a back pointer */ - struct bsc_nat *nat; -}; - -/** - * Stats per BSC - */ -struct bsc_config_stats { - struct rate_ctr_group *ctrg; -}; - -enum bsc_cfg_ctr { - BCFG_CTR_SCCP_CONN, - BCFG_CTR_SCCP_CALLS, - BCFG_CTR_NET_RECONN, - BCFG_CTR_DROPPED_SCCP, - BCFG_CTR_DROPPED_CALLS, - BCFG_CTR_REJECTED_CR, - BCFG_CTR_REJECTED_MSG, - BCFG_CTR_ILL_PACKET, - BCFG_CTR_CON_TYPE_LU, - BCFG_CTR_CON_CMSERV_RQ, - BCFG_CTR_CON_PAG_RESP, - BCFG_CTR_CON_SSA, - BCFG_CTR_CON_OTHER, -}; - -/** - * One BSC entry in the config - */ -struct bsc_config { - struct llist_head entry; - - uint8_t key[16]; - uint8_t key_present; - char *token; - int nr; - - char *description; - - /* imsi white and blacklist */ - char *acc_lst_name; - - int forbid_paging; - int paging_group; - - /* audio handling */ - int max_endpoints; - - /* used internally for reload handling */ - bool remove; - bool token_updated; - - /* backpointer */ - struct bsc_nat *nat; - - struct bsc_config_stats stats; - - struct llist_head lac_list; - - /* Osmux is enabled/disabled per BSC */ - int osmux; - - /* Use a jitterbuffer on the bts-side receiver */ - bool bts_use_jibuf; - /* Minimum and maximum buffer size for the jitter buffer, in ms */ - uint32_t bts_jitter_delay_min; - uint32_t bts_jitter_delay_max; - /* Enabled if explicitly configured through VTY: */ - bool bts_use_jibuf_override; - bool bts_jitter_delay_min_override; - bool bts_jitter_delay_max_override; -}; - -struct bsc_lac_entry { - struct llist_head entry; - uint16_t lac; -}; - -struct bsc_nat_paging_group { - struct llist_head entry; - - /* list of lac entries */ - struct llist_head lists; - int nr; -}; - -/** - * BSCs point of view of endpoints - */ -struct bsc_endpoint { - /* the operation that is carried out */ - int transaction_state; - /* the pending transaction id */ - char *transaction_id; - /* the bsc we are talking to */ - struct bsc_connection *bsc; -}; - -/** - * Statistic for the nat. - */ -struct bsc_nat_statistics { - struct { - struct osmo_counter *conn; - struct osmo_counter *calls; - } sccp; - - struct { - struct osmo_counter *reconn; - struct osmo_counter *auth_fail; - } bsc; - - struct { - struct osmo_counter *reconn; - } msc; - - struct { - struct osmo_counter *reconn; - } ussd; -}; - -/** - * the structure of the "nat" network - */ -struct bsc_nat { - /* active SCCP connections that need patching */ - struct llist_head sccp_connections; - - /* active BSC connections that need patching */ - struct llist_head bsc_connections; - - /* access lists */ - struct llist_head access_lists; - - /* paging groups */ - struct llist_head paging_groups; - - /* known BSC's */ - struct llist_head bsc_configs; - int num_bsc; - int bsc_ip_dscp; - - /* MGCP config */ - struct mgcp_config *mgcp_cfg; - uint8_t mgcp_msg[4096]; - int mgcp_length; - int mgcp_ipa; - int sdp_ensure_amr_mode_set; - - /* msc things */ - struct llist_head dests; - struct bsc_msc_dest *main_dest; - struct bsc_msc_connection *msc_con; - char *token; - - /* timeouts */ - int auth_timeout; - int ping_timeout; - int pong_timeout; - - struct bsc_endpoint *bsc_endpoints; - - /* path to file with BSC config */ - char *include_file; - char *include_base; - char *resolved_path; - - /* filter */ - char *acc_lst_name; - - /* Barring of subscribers with a rb tree */ - struct rb_root imsi_black_list; - char *imsi_black_list_fn; - - /* number rewriting */ - char *num_rewr_name; - struct llist_head num_rewr; - char *num_rewr_post_name; - struct llist_head num_rewr_post; - - char *smsc_rewr_name; - struct llist_head smsc_rewr; - char *tpdest_match_name; - struct llist_head tpdest_match; - char *sms_clear_tp_srr_name; - struct llist_head sms_clear_tp_srr; - char *sms_num_rewr_name; - struct llist_head sms_num_rewr; - - /* more rewriting */ - char *num_rewr_trie_name; - struct nat_rewrite *num_rewr_trie; - - /* USSD messages we want to match */ - char *ussd_lst_name; - char *ussd_query; - regex_t ussd_query_re; - char *ussd_token; - char *ussd_local; - struct osmo_fd ussd_listen; - struct bsc_nat_ussd_con *ussd_con; - - /* for maintainenance */ - int blocked; - - /* statistics */ - struct bsc_nat_statistics stats; - - /* control interface */ - struct ctrl_handle *ctrl; -}; - -struct bsc_nat_ussd_con { - struct osmo_wqueue queue; - struct bsc_nat *nat; - int authorized; - - struct msgb *pending_msg; - - struct osmo_timer_list auth_timeout; -}; - -/* create and init the structures */ -struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, - unsigned int number); -struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num); -struct bsc_config *bsc_config_by_token(struct bsc_nat *nat, const char *token, int len); -void bsc_config_free(struct bsc_config *); -void bsc_config_add_lac(struct bsc_config *cfg, int lac); -void bsc_config_del_lac(struct bsc_config *cfg, int lac); -int bsc_config_handles_lac(struct bsc_config *cfg, int lac); - -struct bsc_nat *bsc_nat_alloc(void); -struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat); -void bsc_nat_set_msc_ip(struct bsc_nat *bsc, const char *ip); - -void sccp_connection_destroy(struct nat_sccp_connection *); -void bsc_close_connection(struct bsc_connection *); - -const char *bsc_con_type_to_string(int type); - -/** - * parse the given message into the above structure - */ -struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg); - -/** - * filter based on IP Access header in both directions - */ -int bsc_nat_filter_ipa(int direction, struct msgb *msg, struct bsc_nat_parsed *parsed); -int bsc_nat_vty_init(struct bsc_nat *nat); -int bsc_nat_find_paging(struct msgb *msg, const uint8_t **,int *len); - -/** - * SCCP patching and handling - */ -struct nat_sccp_connection *create_sccp_src_ref(struct bsc_connection *bsc, struct bsc_nat_parsed *parsed); -int update_sccp_src_ref(struct nat_sccp_connection *sccp, struct bsc_nat_parsed *parsed); -void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed); -struct nat_sccp_connection *patch_sccp_src_ref_to_bsc(struct msgb *, struct bsc_nat_parsed *, struct bsc_nat *); -struct nat_sccp_connection *patch_sccp_src_ref_to_msc(struct msgb *, struct bsc_nat_parsed *, struct bsc_connection *); -struct nat_sccp_connection *bsc_nat_find_con_by_bsc(struct bsc_nat *, struct sccp_source_reference *); - -/** - * MGCP/Audio handling - */ -int bsc_mgcp_nr_multiplexes(int max_endpoints); -int bsc_write_mgcp(struct bsc_connection *bsc, const uint8_t *data, unsigned int length); -int bsc_mgcp_assign_patch(struct nat_sccp_connection *, struct msgb *msg); -void bsc_mgcp_init(struct nat_sccp_connection *); -void bsc_mgcp_dlcx(struct nat_sccp_connection *); -void bsc_mgcp_free_endpoints(struct bsc_nat *nat); -int bsc_mgcp_nat_init(struct bsc_nat *nat); - -struct nat_sccp_connection *bsc_mgcp_find_con(struct bsc_nat *, int endpoint_number); -struct msgb *bsc_mgcp_rewrite(char *input, int length, int endp, const char *ip, - int port, int osmux, int *first_payload_type, int mode_set); -void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg); - -void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc); -int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]); -uint32_t bsc_mgcp_extract_ci(const char *resp); - - -int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int id); -int bsc_do_write(struct osmo_wqueue *queue, struct msgb *msg, int id); -int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg); -int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg); - -int bsc_nat_msc_is_connected(struct bsc_nat *nat); - -int bsc_conn_type_to_ctr(struct nat_sccp_connection *conn); - -struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed, struct msgb *msg, uint32_t *len); - -/** USSD filtering */ -int bsc_ussd_init(struct bsc_nat *nat); -int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, struct msgb *msg); -int bsc_ussd_close_connections(struct bsc_nat *nat); - -struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct bsc_nat_parsed *, const char *imsi); - -/** paging group handling */ -struct bsc_nat_paging_group *bsc_nat_paging_group_num(struct bsc_nat *nat, int group); -struct bsc_nat_paging_group *bsc_nat_paging_group_create(struct bsc_nat *nat, int group); -void bsc_nat_paging_group_delete(struct bsc_nat_paging_group *); -void bsc_nat_paging_group_add_lac(struct bsc_nat_paging_group *grp, int lac); -void bsc_nat_paging_group_del_lac(struct bsc_nat_paging_group *grp, int lac); - -/** - * Number rewriting support below - */ -struct bsc_nat_num_rewr_entry { - struct llist_head list; - - regex_t msisdn_reg; - regex_t num_reg; - - char *replace; - uint8_t is_prefix_lookup; -}; - -void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, const struct osmo_config_list *); - -void bsc_nat_send_mgcp_to_msc(struct bsc_nat *bsc_nat, struct msgb *msg); -void bsc_nat_handle_mgcp(struct bsc_nat *bsc, struct msgb *msg); - -struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, - const char *bind_addr, int port); -void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending); -int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg); - -int bsc_nat_extract_lac(struct bsc_connection *bsc, struct nat_sccp_connection *con, - struct bsc_nat_parsed *parsed, struct msgb *msg); - -int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, - struct bsc_nat_parsed *, int *con_type, char **imsi, - struct bsc_filter_reject_cause *cause); -int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg, - struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, - struct bsc_filter_reject_cause *cause); - -/** - * CTRL interface helper - */ -void bsc_nat_inform_reject(struct bsc_connection *bsc, const char *imsi); - -/* - * Use for testing - */ -void bsc_nat_free(struct bsc_nat *nat); - -#endif diff --git a/include/osmocom/bsc/bsc_nat_callstats.h b/include/osmocom/bsc/bsc_nat_callstats.h deleted file mode 100644 index 64f9bfc0a..000000000 --- a/include/osmocom/bsc/bsc_nat_callstats.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010-2012 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#ifndef BSC_NAT_CALLSTATS_H -#define BSC_NAT_CALLSTATS_H - -#include <osmocom/core/linuxlist.h> - -#include <osmocom/sccp/sccp_types.h> - -struct bsc_nat_call_stats { - struct llist_head entry; - - struct sccp_source_reference remote_ref; - struct sccp_source_reference src_ref; /* as seen by the MSC */ - - /* mgcp options */ - uint32_t ci; - int bts_rtp_port; - int net_rtp_port; - struct in_addr bts_addr; - struct in_addr net_addr; - - - /* as witnessed by the NAT */ - uint32_t net_ps; - uint32_t net_os; - uint32_t bts_pr; - uint32_t bts_or; - uint32_t bts_expected; - uint32_t bts_jitter; - int bts_loss; - - uint32_t trans_id; - int msc_endpoint; -}; - -#endif diff --git a/include/osmocom/bsc/bsc_nat_sccp.h b/include/osmocom/bsc/bsc_nat_sccp.h deleted file mode 100644 index 082466408..000000000 --- a/include/osmocom/bsc/bsc_nat_sccp.h +++ /dev/null @@ -1,105 +0,0 @@ -/* NAT utilities using SCCP types */ -/* - * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#ifndef BSC_NAT_SCCP_H -#define BSC_NAT_SCCP_H - -#include "bsc_msg_filter.h" - -#include <osmocom/sccp/sccp_types.h> - -/* - * For the NAT we will need to analyze and later patch - * the received message. This would require us to parse - * the IPA and SCCP header twice. Instead of doing this - * we will have one analyze structure and have the patching - * and filter operate on the same structure. - */ -struct bsc_nat_parsed { - /* ip access prototype */ - int ipa_proto; - - /* source local reference */ - struct sccp_source_reference *src_local_ref; - - /* destination local reference */ - struct sccp_source_reference *dest_local_ref; - - /* original value */ - struct sccp_source_reference original_dest_ref; - - /* called ssn number */ - int called_ssn; - - /* calling ssn number */ - int calling_ssn; - - /* sccp message type */ - int sccp_type; - - /* bssap type, e.g. 0 for BSS Management */ - int bssap; - - /* the gsm0808 message type */ - int gsm_type; -}; - -/* - * Per SCCP source local reference patch table. It needs to - * be updated on new SCCP connections, connection confirm and reject, - * and on the loss of the BSC connection. - */ -struct nat_sccp_connection { - struct llist_head list_entry; - - struct bsc_connection *bsc; - struct bsc_msc_connection *msc_con; - - struct sccp_source_reference real_ref; - struct sccp_source_reference patched_ref; - struct sccp_source_reference remote_ref; - int has_remote_ref; - - /* status */ - int con_local; - int authorized; - - struct bsc_filter_state filter_state; - - uint16_t lac; - uint16_t ci; - - /* remember which Transactions we run over the bypass */ - char ussd_ti[8]; - - /* - * audio handling. Remember if we have ever send a CRCX, - * remember the endpoint used by the MSC and BSC. - */ - int msc_endp; - int bsc_endp; - - /* timeout handling */ - struct timespec creation_time; -}; - - -#endif diff --git a/include/osmocom/bsc/nat_rewrite_trie.h b/include/osmocom/bsc/nat_rewrite_trie.h deleted file mode 100644 index 0571099c6..000000000 --- a/include/osmocom/bsc/nat_rewrite_trie.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * (C) 2013 by On-Waves - * (C) 2013 by Holger Hans Peter Freyther <zecke@selfish.org> - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ -#ifndef NAT_REWRITE_FILE_H -#define NAT_REWRITE_FILE_H - -#include <osmocom/core/linuxrbtree.h> - -struct vty; - -struct nat_rewrite_rule { - /* For digits 0-9 and + */ - struct nat_rewrite_rule *rules[11]; - - char empty; - char prefix[14]; - char rewrite[6]; -}; - -struct nat_rewrite { - struct nat_rewrite_rule rule; - size_t prefixes; -}; - - -struct nat_rewrite *nat_rewrite_parse(void *ctx, const char *filename); -struct nat_rewrite_rule *nat_rewrite_lookup(struct nat_rewrite *, const char *prefix); -void nat_rewrite_dump(struct nat_rewrite *rewr); -void nat_rewrite_dump_vty(struct vty *vty, struct nat_rewrite *rewr); - -#endif diff --git a/src/libfilter/bsc_msg_acc.c b/src/libfilter/bsc_msg_acc.c index d7b737bc7..6b048874f 100644 --- a/src/libfilter/bsc_msg_acc.c +++ b/src/libfilter/bsc_msg_acc.c @@ -19,9 +19,10 @@ */ #include <osmocom/bsc/bsc_msg_filter.h> -#include <osmocom/bsc/bsc_nat.h> #include <osmocom/bsc/debug.h> +#include <osmocom/gsm/protocol/gsm_04_08.h> + #include <osmocom/core/rate_ctr.h> #include <osmocom/core/stats.h> diff --git a/src/libfilter/bsc_msg_filter.c b/src/libfilter/bsc_msg_filter.c index 56ddf670d..120169bf9 100644 --- a/src/libfilter/bsc_msg_filter.c +++ b/src/libfilter/bsc_msg_filter.c @@ -23,7 +23,6 @@ #include <osmocom/bsc/bsc_msg_filter.h> -#include <osmocom/bsc/bsc_nat.h> #include <osmocom/bsc/bsc_msc.h> #include <osmocom/bsc/gsm_data.h> #include <osmocom/bsc/debug.h> diff --git a/src/osmo-bsc/osmo_bsc_msc.c b/src/osmo-bsc/osmo_bsc_msc.c index 612a00bb3..10f602a09 100644 --- a/src/osmo-bsc/osmo_bsc_msc.c +++ b/src/osmo-bsc/osmo_bsc_msc.c @@ -20,7 +20,6 @@ * */ -#include <osmocom/bsc/bsc_nat.h> #include <osmocom/ctrl/control_cmd.h> #include <osmocom/ctrl/control_if.h> #include <osmocom/crypt/auth.h> diff --git a/src/osmo-bsc_nat/Makefile.am b/src/osmo-bsc_nat/Makefile.am deleted file mode 100644 index 267565147..000000000 --- a/src/osmo-bsc_nat/Makefile.am +++ /dev/null @@ -1,51 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - -I$(top_builddir) \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOVTY_CFLAGS) \ - $(LIBOSMOCTRL_CFLAGS) \ - $(LIBOSMOSCCP_CFLAGS) \ - $(LIBOSMOLEGACYMGCP_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -bin_PROGRAMS = \ - osmo-bsc_nat \ - $(NULL) - -osmo_bsc_nat_SOURCES = \ - bsc_filter.c \ - bsc_mgcp_utils.c \ - bsc_nat.c \ - bsc_nat_utils.c \ - bsc_nat_vty.c \ - bsc_sccp.c \ - bsc_ussd.c \ - bsc_nat_ctrl.c \ - bsc_nat_rewrite.c \ - bsc_nat_rewrite_trie.c \ - bsc_nat_filter.c \ - $(NULL) - -osmo_bsc_nat_LDADD = \ - $(top_builddir)/src/libfilter/libfilter.a \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(LIBOSMOSCCP_LIBS) \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOVTY_LIBS) \ - $(LIBOSMOCTRL_LIBS) \ - $(LIBOSMOSIGTRAN_LIBS) \ - $(LIBRARY_GSM) \ - -lrt \ - $(NULL) diff --git a/src/osmo-bsc_nat/bsc_filter.c b/src/osmo-bsc_nat/bsc_filter.c deleted file mode 100644 index 77ef5833f..000000000 --- a/src/osmo-bsc_nat/bsc_filter.c +++ /dev/null @@ -1,220 +0,0 @@ -/* BSC Multiplexer/NAT */ - -/* - * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <string.h> - -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_nat_sccp.h> -#include <osmocom/bsc/ipaccess.h> -#include <osmocom/bsc/debug.h> - -#include <osmocom/core/talloc.h> -#include <osmocom/gsm/protocol/gsm_08_08.h> - -#include <osmocom/sccp/sccp.h> - -/* - * The idea is to have a simple struct describing a IPA packet with - * SCCP SSN and the GSM 08.08 payload and decide. We will both have - * a white and a blacklist of packets we want to handle. - * - * TODO: Implement a "NOT" in the filter language. - */ - -#define ALLOW_ANY -1 - -#define FILTER_TO_BSC 1 -#define FILTER_TO_MSC 2 -#define FILTER_TO_BOTH 3 - - -struct bsc_pkt_filter { - int ipa_proto; - int dest_ssn; - int bssap; - int gsm; - int filter_dir; -}; - -static struct bsc_pkt_filter black_list[] = { - /* filter reset messages to the MSC */ - { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET, FILTER_TO_MSC }, - - /* filter reset ack messages to the BSC */ - { IPAC_PROTO_SCCP, SCCP_SSN_BSSAP, 0, BSS_MAP_MSG_RESET_ACKNOWLEDGE, FILTER_TO_BSC }, - - /* filter ip access */ - { IPAC_PROTO_IPACCESS, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_MSC }, -}; - -static struct bsc_pkt_filter white_list[] = { - /* allow IPAC_PROTO_SCCP messages to both sides */ - { IPAC_PROTO_SCCP, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH }, - - /* allow MGCP messages to both sides */ - { IPAC_PROTO_MGCP_OLD, ALLOW_ANY, ALLOW_ANY, ALLOW_ANY, FILTER_TO_BOTH }, -}; - -struct bsc_nat_parsed *bsc_nat_parse(struct msgb *msg) -{ - struct sccp_parse_result result; - struct bsc_nat_parsed *parsed; - struct ipaccess_head *hh; - - /* quick fail */ - if (msg->len < 4) - return NULL; - - parsed = talloc_zero(msg, struct bsc_nat_parsed); - if (!parsed) - return NULL; - - /* more init */ - parsed->ipa_proto = parsed->called_ssn = parsed->calling_ssn = -1; - parsed->sccp_type = parsed->bssap = parsed->gsm_type = -1; - - /* start parsing */ - hh = (struct ipaccess_head *) msg->data; - parsed->ipa_proto = hh->proto; - - msg->l2h = &hh->data[0]; - - /* do a size check on the input */ - if (ntohs(hh->len) != msgb_l2len(msg)) { - LOGP(DLINP, LOGL_ERROR, "Wrong input length?\n"); - talloc_free(parsed); - return NULL; - } - - /* analyze sccp down here */ - if (parsed->ipa_proto == IPAC_PROTO_SCCP) { - memset(&result, 0, sizeof(result)); - if (sccp_parse_header(msg, &result) != 0) { - talloc_free(parsed); - return 0; - } - - if (msg->l3h && msgb_l3len(msg) < 3) { - LOGP(DNAT, LOGL_ERROR, "Not enough space or GSM payload\n"); - talloc_free(parsed); - return 0; - } - - parsed->sccp_type = sccp_determine_msg_type(msg); - parsed->src_local_ref = result.source_local_reference; - parsed->dest_local_ref = result.destination_local_reference; - if (parsed->dest_local_ref) - parsed->original_dest_ref = *parsed->dest_local_ref; - parsed->called_ssn = result.called.ssn; - parsed->calling_ssn = result.calling.ssn; - - /* in case of connection confirm we have no payload */ - if (msg->l3h) { - parsed->bssap = msg->l3h[0]; - parsed->gsm_type = msg->l3h[2]; - } - } - - return parsed; -} - -int bsc_nat_filter_ipa(int dir, struct msgb *msg, struct bsc_nat_parsed *parsed) -{ - int i; - - /* go through the blacklist now */ - for (i = 0; i < ARRAY_SIZE(black_list); ++i) { - /* ignore the rule? */ - if (black_list[i].filter_dir != FILTER_TO_BOTH - && black_list[i].filter_dir != dir) - continue; - - /* the proto is not blacklisted */ - if (black_list[i].ipa_proto != ALLOW_ANY - && black_list[i].ipa_proto != parsed->ipa_proto) - continue; - - if (parsed->ipa_proto == IPAC_PROTO_SCCP) { - /* the SSN is not blacklisted */ - if (black_list[i].dest_ssn != ALLOW_ANY - && black_list[i].dest_ssn != parsed->called_ssn) - continue; - - /* bssap */ - if (black_list[i].bssap != ALLOW_ANY - && black_list[i].bssap != parsed->bssap) - continue; - - /* gsm */ - if (black_list[i].gsm != ALLOW_ANY - && black_list[i].gsm != parsed->gsm_type) - continue; - - /* blacklisted */ - LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i); - return 1; - } else { - /* blacklisted, we have no content sniffing yet */ - LOGP(DNAT, LOGL_INFO, "Blacklisted with rule %d\n", i); - return 1; - } - } - - /* go through the whitelust now */ - for (i = 0; i < ARRAY_SIZE(white_list); ++i) { - /* ignore the rule? */ - if (white_list[i].filter_dir != FILTER_TO_BOTH - && white_list[i].filter_dir != dir) - continue; - - /* the proto is not whitelisted */ - if (white_list[i].ipa_proto != ALLOW_ANY - && white_list[i].ipa_proto != parsed->ipa_proto) - continue; - - if (parsed->ipa_proto == IPAC_PROTO_SCCP) { - /* the SSN is not whitelisted */ - if (white_list[i].dest_ssn != ALLOW_ANY - && white_list[i].dest_ssn != parsed->called_ssn) - continue; - - /* bssap */ - if (white_list[i].bssap != ALLOW_ANY - && white_list[i].bssap != parsed->bssap) - continue; - - /* gsm */ - if (white_list[i].gsm != ALLOW_ANY - && white_list[i].gsm != parsed->gsm_type) - continue; - - /* whitelisted */ - LOGP(DNAT, LOGL_INFO, "Whitelisted with rule %d\n", i); - return 0; - } else { - /* whitelisted */ - return 0; - } - } - - return 1; -} diff --git a/src/osmo-bsc_nat/bsc_mgcp_utils.c b/src/osmo-bsc_nat/bsc_mgcp_utils.c deleted file mode 100644 index ab06a5ee3..000000000 --- a/src/osmo-bsc_nat/bsc_mgcp_utils.c +++ /dev/null @@ -1,1162 +0,0 @@ -/** - * This file contains helper routines for MGCP Gateway handling. - * - * The first thing to remember is that each BSC has its own namespace/range - * of endpoints. Whenever a BSSMAP ASSIGNMENT REQUEST is received this code - * will be called to select an endpoint on the BSC. The mapping from original - * multiplex/timeslot to BSC multiplex'/timeslot' will be stored. - * - * The second part is to take messages on the public MGCP GW interface - * and forward them to the right BSC. This requires the MSC to first - * assign the timeslot. This assumption has been true so far. We are using - * the policy_cb of the MGCP protocol code to decide if the request should - * be immediately answered or delayed. An extension "Z: noanswer" is used - * to request the BSC to not respond. This is saving some bytes of bandwidth - * and as we are using TCP to forward the message we know it will arrive. - * The mgcp_do_read method reads these messages and hands them to the protocol - * parsing code which will call the mentioned policy_cb. The bsc_mgcp_forward - * method is used on the way back from the BSC to the network. - * - * The third part is to patch messages forwarded to the BSC. This includes - * the endpoint number, the ports to be used inside the SDP file and maybe - * some other bits. - * - */ -/* - * (C) 2010-2012 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010-2012 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_nat_callstats.h> -#include <osmocom/bsc/bsc_nat_sccp.h> -#include <osmocom/bsc/gsm_data.h> -#include <osmocom/bsc/debug.h> -#include <osmocom/bsc/ipaccess.h> -#include <osmocom/legacy_mgcp/mgcp.h> -#include <osmocom/legacy_mgcp/mgcp_internal.h> -#include <osmocom/bsc/osmux.h> - -#include <osmocom/ctrl/control_cmd.h> - -#include <osmocom/sccp/sccp.h> - -#include <osmocom/core/talloc.h> -#include <osmocom/gsm/gsm0808.h> -#include <osmocom/gsm/protocol/gsm_08_08.h> - -#include <netinet/in.h> -#include <arpa/inet.h> - -#include <errno.h> -#include <unistd.h> - -static void send_direct(struct bsc_nat *nat, struct msgb *output) -{ - if (osmo_wqueue_enqueue(&nat->mgcp_cfg->gw_fd, output) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to queue MGCP msg.\n"); - msgb_free(output); - } -} - -static void mgcp_queue_for_call_agent(struct bsc_nat *nat, struct msgb *output) -{ - if (nat->mgcp_ipa) - bsc_nat_send_mgcp_to_msc(nat, output); - else - send_direct(nat, output); -} - -int bsc_mgcp_nr_multiplexes(int max_endpoints) -{ - int div = max_endpoints / 32; - - if ((max_endpoints % 32) != 0) - div += 1; - - return div; -} - -static int bsc_init_endps_if_needed(struct bsc_connection *con) -{ - int multiplexes; - - /* we have done that */ - if (con->_endpoint_status) - return 0; - - /* we have no config... */ - if (!con->cfg) - return -1; - - multiplexes = bsc_mgcp_nr_multiplexes(con->cfg->max_endpoints); - con->number_multiplexes = multiplexes; - con->max_endpoints = con->cfg->max_endpoints; - con->_endpoint_status = talloc_zero_array(con, char, 32 * multiplexes + 1); - return con->_endpoint_status == NULL; -} - -static int bsc_assign_endpoint(struct bsc_connection *bsc, struct nat_sccp_connection *con) -{ - int multiplex; - int timeslot; - const int number_endpoints = bsc->max_endpoints; - int i; - - mgcp_endpoint_to_timeslot(bsc->last_endpoint, &multiplex, ×lot); - timeslot += 1; - - for (i = 0; i < number_endpoints; ++i) { - int endpoint; - - /* Wrap around timeslots */ - if (timeslot == 0) - timeslot = 1; - - if (timeslot == 0x1f) { - timeslot = 1; - multiplex += 1; - } - - /* Wrap around the multiplex */ - if (multiplex >= bsc->number_multiplexes) - multiplex = 0; - - endpoint = mgcp_timeslot_to_endpoint(multiplex, timeslot); - - /* Now check if we are allowed to assign this one */ - if (endpoint >= bsc->max_endpoints) { - multiplex = 0; - timeslot = 1; - endpoint = mgcp_timeslot_to_endpoint(multiplex, timeslot); - } - - - if (bsc->_endpoint_status[endpoint] == 0) { - bsc->_endpoint_status[endpoint] = 1; - con->bsc_endp = endpoint; - bsc->last_endpoint = endpoint; - return 0; - } - - timeslot += 1; - } - - return -1; -} - -static uint16_t create_cic(int endpoint) -{ - int timeslot, multiplex; - - mgcp_endpoint_to_timeslot(endpoint, &multiplex, ×lot); - return (multiplex << 5) | (timeslot & 0x1f); -} - -int bsc_mgcp_assign_patch(struct nat_sccp_connection *con, struct msgb *msg) -{ - struct nat_sccp_connection *mcon; - struct tlv_parsed tp; - uint16_t cic; - uint8_t timeslot; - uint8_t multiplex; - unsigned int endp; - - if (!msg->l3h) { - LOGP(DNAT, LOGL_ERROR, "Assignment message should have l3h pointer.\n"); - return -1; - } - - if (msgb_l3len(msg) < 3) { - LOGP(DNAT, LOGL_ERROR, "Assignment message has not enough space for GSM0808.\n"); - return -1; - } - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0); - if (!TLVP_PRESENT(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)) { - LOGP(DNAT, LOGL_ERROR, "Circuit identity code not found in assignment message.\n"); - return -1; - } - - cic = ntohs(tlvp_val16_unal(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE)); - timeslot = cic & 0x1f; - multiplex = (cic & ~0x1f) >> 5; - - - endp = mgcp_timeslot_to_endpoint(multiplex, timeslot); - - if (endp >= con->bsc->nat->mgcp_cfg->trunk.number_endpoints) { - LOGP(DNAT, LOGL_ERROR, - "MSC attempted to assign bad endpoint 0x%x\n", - endp); - return -1; - } - - /* find stale connections using that endpoint */ - llist_for_each_entry(mcon, &con->bsc->nat->sccp_connections, list_entry) { - if (mcon->msc_endp == endp) { - LOGP(DNAT, LOGL_ERROR, - "Endpoint %d was assigned to 0x%x and now 0x%x\n", - endp, - sccp_src_ref_to_int(&mcon->patched_ref), - sccp_src_ref_to_int(&con->patched_ref)); - bsc_mgcp_dlcx(mcon); - } - } - - con->msc_endp = endp; - if (bsc_init_endps_if_needed(con->bsc) != 0) - return -1; - if (bsc_assign_endpoint(con->bsc, con) != 0) - return -1; - - /* - * now patch the message for the new CIC... - * still assumed to be one multiplex only - */ - cic = htons(create_cic(con->bsc_endp)); - memcpy((uint8_t *) TLVP_VAL(&tp, GSM0808_IE_CIRCUIT_IDENTITY_CODE), - &cic, sizeof(cic)); - - return 0; -} - -static void bsc_mgcp_free_endpoint(struct bsc_nat *nat, int i) -{ - if (nat->bsc_endpoints[i].transaction_id) { - talloc_free(nat->bsc_endpoints[i].transaction_id); - nat->bsc_endpoints[i].transaction_id = NULL; - } - - nat->bsc_endpoints[i].transaction_state = 0; - nat->bsc_endpoints[i].bsc = NULL; -} - -void bsc_mgcp_free_endpoints(struct bsc_nat *nat) -{ - int i; - - for (i = 1; i < nat->mgcp_cfg->trunk.number_endpoints; ++i){ - bsc_mgcp_free_endpoint(nat, i); - mgcp_release_endp(&nat->mgcp_cfg->trunk.endpoints[i]); - } -} - -/* send a MDCX where we do not want a response */ -static void bsc_mgcp_send_mdcx(struct bsc_connection *bsc, int port, struct mgcp_endpoint *endp) -{ - char buf[2096]; - int len; - - len = snprintf(buf, sizeof(buf), - "MDCX 23 %x@mgw MGCP 1.0\r\n" - "Z: noanswer\r\n" - "\r\n" - "c=IN IP4 %s\r\n" - "m=audio %d RTP/AVP 255\r\n", - port, mgcp_bts_src_addr(endp), - endp->bts_end.local_port); - if (len < 0) { - LOGP(DMGCP, LOGL_ERROR, "snprintf for MDCX failed.\n"); - return; - } - - bsc_write_mgcp(bsc, (uint8_t *) buf, len); -} - -static void bsc_mgcp_send_dlcx(struct bsc_connection *bsc, int endpoint, int trans) -{ - char buf[2096]; - int len; - - /* - * The following is a bit of a spec violation. According to the - * MGCP grammar the transaction id is are upto 9 digits but we - * prefix it with an alpha numeric value so we can easily recognize - * it as a response. - */ - len = snprintf(buf, sizeof(buf), - "DLCX nat-%u %x@mgw MGCP 1.0\r\n", - trans, endpoint); - if (len < 0) { - LOGP(DMGCP, LOGL_ERROR, "snprintf for DLCX failed.\n"); - return; - } - - bsc_write_mgcp(bsc, (uint8_t *) buf, len); -} - -void bsc_mgcp_init(struct nat_sccp_connection *con) -{ - con->msc_endp = -1; - con->bsc_endp = -1; -} - -/** - * This code will remember the network side of the audio statistics and - * once the internal DLCX response arrives this can be combined with the - * the BSC side and forwarded as a trap. - */ -static void remember_pending_dlcx(struct nat_sccp_connection *con, uint32_t transaction) -{ - struct bsc_nat_call_stats *stats; - struct bsc_connection *bsc = con->bsc; - struct mgcp_endpoint *endp; - - stats = talloc_zero(bsc, struct bsc_nat_call_stats); - if (!stats) { - LOGP(DNAT, LOGL_NOTICE, - "Failed to allocate statistics for endpoint 0x%x\n", - con->msc_endp); - return; - } - - /* take the endpoint here */ - endp = &bsc->nat->mgcp_cfg->trunk.endpoints[con->msc_endp]; - - stats->remote_ref = con->remote_ref; - stats->src_ref = con->patched_ref; - - stats->ci = endp->ci; - stats->bts_rtp_port = endp->bts_end.rtp_port; - stats->bts_addr = endp->bts_end.addr; - stats->net_rtp_port = endp->net_end.rtp_port; - stats->net_addr = endp->net_end.addr; - - stats->net_ps = endp->net_end.packets; - stats->net_os = endp->net_end.octets; - stats->bts_pr = endp->bts_end.packets; - stats->bts_or = endp->bts_end.octets; - mgcp_state_calc_loss(&endp->bts_state, &endp->bts_end, - &stats->bts_expected, &stats->bts_loss); - stats->bts_jitter = mgcp_state_calc_jitter(&endp->bts_state); - - stats->trans_id = transaction; - stats->msc_endpoint = con->msc_endp; - - /* - * Too many pending requests.. let's remove the first two items. - */ - if (!llist_empty(&bsc->pending_dlcx) && - bsc->pending_dlcx_count >= bsc->cfg->max_endpoints * 3) { - struct bsc_nat_call_stats *tmp; - LOGP(DNAT, LOGL_ERROR, - "Too many(%d) pending DLCX responses on BSC: %d\n", - bsc->pending_dlcx_count, bsc->cfg->nr); - bsc->pending_dlcx_count -= 1; - tmp = (struct bsc_nat_call_stats *) bsc->pending_dlcx.next; - llist_del(&tmp->entry); - talloc_free(tmp); - } - - bsc->pending_dlcx_count += 1; - llist_add_tail(&stats->entry, &bsc->pending_dlcx); -} - -void bsc_mgcp_dlcx(struct nat_sccp_connection *con) -{ - /* send a DLCX down the stream */ - if (con->bsc_endp != -1 && con->bsc->_endpoint_status) { - LOGP(DNAT, LOGL_NOTICE, - "Endpoint 0x%x was allocated for bsc: %d. Freeing it.\n", - con->bsc_endp, con->bsc->cfg->nr); - if (con->bsc->_endpoint_status[con->bsc_endp] != 1) - LOGP(DNAT, LOGL_ERROR, "Endpoint 0x%x was not in use\n", con->bsc_endp); - remember_pending_dlcx(con, con->bsc->next_transaction); - con->bsc->_endpoint_status[con->bsc_endp] = 0; - bsc_mgcp_send_dlcx(con->bsc, con->bsc_endp, con->bsc->next_transaction++); - bsc_mgcp_free_endpoint(con->bsc->nat, con->msc_endp); - } - - bsc_mgcp_init(con); - -} - -/* - * Search for the pending request - */ -static void handle_dlcx_response(struct bsc_connection *bsc, struct msgb *msg, - int code, const char *transaction) -{ - uint32_t trans_id = UINT32_MAX; - uint32_t b_ps, b_os, n_pr, n_or, jitter; - int loss; - struct bsc_nat_call_stats *tmp, *stat = NULL; - struct ctrl_cmd *cmd; - - /* parse the transaction identifier */ - int rc = sscanf(transaction, "nat-%u", &trans_id); - if (rc != 1) { - LOGP(DNAT, LOGL_ERROR, "Can not parse transaction id: '%s'\n", - transaction); - return; - } - - /* find the answer for the request we made */ - llist_for_each_entry(tmp, &bsc->pending_dlcx, entry) { - if (trans_id != tmp->trans_id) - continue; - - stat = tmp; - break; - } - - if (!stat) { - LOGP(DNAT, LOGL_ERROR, - "Can not find transaction for: %u\n", trans_id); - return; - } - - /* attempt to parse the data now */ - rc = mgcp_parse_stats(msg, &b_ps, &b_os, &n_pr, &n_or, &loss, &jitter); - if (rc != 0) - LOGP(DNAT, LOGL_ERROR, - "Can not parse connection statistics: %d\n", rc); - - /* send a trap now */ - cmd = ctrl_cmd_create(bsc, CTRL_TYPE_TRAP); - if (!cmd) { - LOGP(DNAT, LOGL_ERROR, - "Creating a ctrl cmd failed.\n"); - goto free_stat; - } - - cmd->id = "0"; - cmd->variable = talloc_asprintf(cmd, "net.0.bsc.%d.call_stats.v2", - bsc->cfg->nr); - cmd->reply = talloc_asprintf(cmd, - "mg_ip_addr=%s,mg_port=%d,", - inet_ntoa(stat->net_addr), - stat->net_rtp_port); - cmd->reply = talloc_asprintf_append(cmd->reply, - "endpoint_ip_addr=%s,endpoint_port=%d,", - inet_ntoa(stat->bts_addr), - stat->bts_rtp_port); - cmd->reply = talloc_asprintf_append(cmd->reply, - "nat_pkt_in=%u,nat_pkt_out=%u," - "nat_bytes_in=%u,nat_bytes_out=%u," - "nat_jitter=%u,nat_pkt_lost=%d,", - stat->bts_pr, stat->net_ps, - stat->bts_or, stat->net_os, - stat->bts_jitter, stat->bts_loss); - cmd->reply = talloc_asprintf_append(cmd->reply, - "bsc_pkt_in=%u,bsc_pkt_out=%u," - "bsc_bytes_in=%u,bsc_bytes_out=%u," - "bsc_jitter=%u,bsc_pkt_lost=%d,", - n_pr, b_ps, - n_or, b_os, - jitter, loss); - cmd->reply = talloc_asprintf_append(cmd->reply, - "sccp_src_ref=%u,sccp_dst_ref=%u", - sccp_src_ref_to_int(&stat->src_ref), - sccp_src_ref_to_int(&stat->remote_ref)); - - /* send it and be done */ - ctrl_cmd_send_to_all(bsc->nat->ctrl, cmd); - talloc_free(cmd); - -free_stat: - bsc->pending_dlcx_count -= 1; - llist_del(&stat->entry); - talloc_free(stat); -} - - -struct nat_sccp_connection *bsc_mgcp_find_con(struct bsc_nat *nat, int endpoint) -{ - struct nat_sccp_connection *con = NULL; - struct nat_sccp_connection *sccp; - - llist_for_each_entry(sccp, &nat->sccp_connections, list_entry) { - if (sccp->msc_endp == -1) - continue; - if (sccp->msc_endp != endpoint) - continue; - - con = sccp; - } - - if (con) - return con; - - LOGP(DMGCP, LOGL_ERROR, - "Failed to find the connection for endpoint: 0x%x\n", endpoint); - return NULL; -} - -static int nat_osmux_only(struct mgcp_config *mgcp_cfg, struct bsc_config *bsc_cfg) -{ - if (mgcp_cfg->osmux == OSMUX_USAGE_ONLY) - return 1; - if (bsc_cfg->osmux == OSMUX_USAGE_ONLY) - return 1; - return 0; -} - -static int bsc_mgcp_policy_cb(struct mgcp_trunk_config *tcfg, int endpoint, int state, const char *transaction_id) -{ - struct bsc_nat *nat; - struct bsc_endpoint *bsc_endp; - struct nat_sccp_connection *sccp; - struct mgcp_endpoint *mgcp_endp; - struct msgb *bsc_msg; - - nat = tcfg->cfg->data; - bsc_endp = &nat->bsc_endpoints[endpoint]; - mgcp_endp = &nat->mgcp_cfg->trunk.endpoints[endpoint]; - - if (bsc_endp->transaction_id) { - LOGP(DMGCP, LOGL_ERROR, "Endpoint 0x%x had pending transaction: '%s'\n", - endpoint, bsc_endp->transaction_id); - talloc_free(bsc_endp->transaction_id); - bsc_endp->transaction_id = NULL; - bsc_endp->transaction_state = 0; - } - bsc_endp->bsc = NULL; - - sccp = bsc_mgcp_find_con(nat, endpoint); - - if (!sccp) { - LOGP(DMGCP, LOGL_ERROR, "Did not find BSC for change on endpoint: 0x%x state: %d\n", endpoint, state); - - switch (state) { - case MGCP_ENDP_CRCX: - return MGCP_POLICY_REJECT; - break; - case MGCP_ENDP_DLCX: - return MGCP_POLICY_CONT; - break; - case MGCP_ENDP_MDCX: - return MGCP_POLICY_CONT; - break; - default: - LOGP(DMGCP, LOGL_FATAL, "Unhandled state: %d\n", state); - return MGCP_POLICY_CONT; - break; - } - } - - /* Allocate a Osmux circuit ID */ - if (state == MGCP_ENDP_CRCX) { - if (nat->mgcp_cfg->osmux && sccp->bsc->cfg->osmux) { - osmux_allocate_cid(mgcp_endp); - if (mgcp_endp->osmux.allocated_cid < 0 && - nat_osmux_only(nat->mgcp_cfg, sccp->bsc->cfg)) { - LOGP(DMGCP, LOGL_ERROR, - "Rejecting usage of endpoint\n"); - return MGCP_POLICY_REJECT; - } - } - } - - /* we need to generate a new and patched message */ - bsc_msg = bsc_mgcp_rewrite((char *) nat->mgcp_msg, nat->mgcp_length, - sccp->bsc_endp, mgcp_bts_src_addr(mgcp_endp), - mgcp_endp->bts_end.local_port, - mgcp_endp->osmux.allocated_cid, - &mgcp_endp->net_end.codec.payload_type, - nat->sdp_ensure_amr_mode_set); - if (!bsc_msg) { - LOGP(DMGCP, LOGL_ERROR, "Failed to patch the msg.\n"); - return MGCP_POLICY_CONT; - } - - - bsc_endp->transaction_id = talloc_strdup(nat, transaction_id); - bsc_endp->transaction_state = state; - bsc_endp->bsc = sccp->bsc; - - /* we need to update some bits */ - if (state == MGCP_ENDP_CRCX) { - struct sockaddr_in sock; - - /* set up jitter buffer parameters */ - if (bsc_endp->bsc->cfg->bts_use_jibuf_override) - mgcp_endp->bts_use_jibuf = bsc_endp->bsc->cfg->bts_use_jibuf; - - if (bsc_endp->bsc->cfg->bts_jitter_delay_min_override) - mgcp_endp->bts_jitter_delay_min = bsc_endp->bsc->cfg->bts_jitter_delay_min; - - if (bsc_endp->bsc->cfg->bts_jitter_delay_max_override) - mgcp_endp->bts_jitter_delay_max = bsc_endp->bsc->cfg->bts_jitter_delay_max; - - - /* Annotate the allocated Osmux CID until the bsc confirms that - * it agrees to use Osmux for this voice flow. - */ - if (mgcp_endp->osmux.allocated_cid >= 0 && - mgcp_endp->osmux.state != OSMUX_STATE_ENABLED) { - mgcp_endp->osmux.state = OSMUX_STATE_NEGOTIATING; - mgcp_endp->osmux.cid = mgcp_endp->osmux.allocated_cid; - } - - socklen_t len = sizeof(sock); - if (getpeername(sccp->bsc->write_queue.bfd.fd, (struct sockaddr *) &sock, &len) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Can not get the peername...%d/%s\n", - errno, strerror(errno)); - } else { - mgcp_endp->bts_end.addr = sock.sin_addr; - } - - /* send the message and a fake MDCX to force sending of a dummy packet */ - bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP_OLD); - bsc_mgcp_send_mdcx(sccp->bsc, sccp->bsc_endp, mgcp_endp); - return MGCP_POLICY_DEFER; - } else if (state == MGCP_ENDP_DLCX) { - /* we will free the endpoint now and send a DLCX to the BSC */ - msgb_free(bsc_msg); - bsc_mgcp_dlcx(sccp); - - /* libmgcp clears the MGCP endpoint for us */ - if (mgcp_endp->osmux.state == OSMUX_STATE_ENABLED) - osmux_release_cid(mgcp_endp); - - return MGCP_POLICY_CONT; - } else { - bsc_write(sccp->bsc, bsc_msg, IPAC_PROTO_MGCP_OLD); - return MGCP_POLICY_DEFER; - } -} - -/* - * We do have a failure, free data downstream.. - */ -static void free_chan_downstream(struct mgcp_endpoint *endp, struct bsc_endpoint *bsc_endp, - struct bsc_connection *bsc) -{ - LOGP(DMGCP, LOGL_ERROR, "No CI, freeing endpoint 0x%x in state %d\n", - ENDPOINT_NUMBER(endp), bsc_endp->transaction_state); - - /* if a CRCX failed... send a DLCX down the stream */ - if (bsc_endp->transaction_state == MGCP_ENDP_CRCX) { - struct nat_sccp_connection *con; - con = bsc_mgcp_find_con(bsc->nat, ENDPOINT_NUMBER(endp)); - if (!con) { - LOGP(DMGCP, LOGL_ERROR, - "No SCCP connection for endp 0x%x\n", - ENDPOINT_NUMBER(endp)); - } else { - if (con->bsc == bsc) { - bsc_mgcp_send_dlcx(bsc, con->bsc_endp, con->bsc->next_transaction++); - } else { - LOGP(DMGCP, LOGL_ERROR, - "Endpoint belongs to a different BSC\n"); - } - } - } - - bsc_mgcp_free_endpoint(bsc->nat, ENDPOINT_NUMBER(endp)); - mgcp_release_endp(endp); -} - -static void bsc_mgcp_osmux_confirm(struct mgcp_endpoint *endp, const char *str) -{ - unsigned int osmux_cid; - char *res; - - res = strstr(str, "X-Osmux: "); - if (!res) { - LOGP(DMGCP, LOGL_INFO, - "BSC doesn't want to use Osmux, failing back to RTP\n"); - goto err; - } - - if (sscanf(res, "X-Osmux: %u", &osmux_cid) != 1) { - LOGP(DMGCP, LOGL_ERROR, "Failed to parse Osmux CID '%s'\n", - str); - goto err; - } - - if (endp->osmux.cid != osmux_cid) { - LOGP(DMGCP, LOGL_ERROR, - "BSC sent us wrong CID %u, we expected %u", - osmux_cid, endp->osmux.cid); - goto err; - } - - LOGP(DMGCP, LOGL_NOTICE, "bsc accepted to use Osmux (cid=%u)\n", - osmux_cid); - endp->osmux.state = OSMUX_STATE_ACTIVATING; - return; -err: - osmux_release_cid(endp); - endp->osmux.state = OSMUX_STATE_DISABLED; -} - -/* - * We have received a msg from the BSC. We will see if we know - * this transaction and if it belongs to the BSC. Then we will - * need to patch the content to point to the local network and we - * need to update the I: that was assigned by the BSS. - * - * Only responses to CRCX and DLCX should arrive here. The DLCX - * needs to be handled specially to combine the two statistics. - */ -void bsc_mgcp_forward(struct bsc_connection *bsc, struct msgb *msg) -{ - struct msgb *output; - struct bsc_endpoint *bsc_endp = NULL; - struct mgcp_endpoint *endp = NULL; - int i, code; - char transaction_id[60]; - - /* Some assumption that our buffer is big enough.. and null terminate */ - if (msgb_l2len(msg) > 2000) { - LOGP(DMGCP, LOGL_ERROR, "MGCP message too long.\n"); - return; - } - - msg->l2h[msgb_l2len(msg)] = '\0'; - - if (bsc_mgcp_parse_response((const char *) msg->l2h, &code, transaction_id) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to parse response code.\n"); - return; - } - - for (i = 1; i < bsc->nat->mgcp_cfg->trunk.number_endpoints; ++i) { - if (bsc->nat->bsc_endpoints[i].bsc != bsc) - continue; - /* no one listening? a bug? */ - if (!bsc->nat->bsc_endpoints[i].transaction_id) - continue; - if (strcmp(transaction_id, bsc->nat->bsc_endpoints[i].transaction_id) != 0) - continue; - - endp = &bsc->nat->mgcp_cfg->trunk.endpoints[i]; - bsc_endp = &bsc->nat->bsc_endpoints[i]; - break; - } - - if (!bsc_endp && strncmp("nat-", transaction_id, 4) == 0) { - handle_dlcx_response(bsc, msg, code, transaction_id); - return; - } - - if (!bsc_endp) { - LOGP(DMGCP, LOGL_ERROR, "Could not find active endpoint: %s for msg: '%s'\n", - transaction_id, (const char *) msg->l2h); - return; - } - - endp->ci = bsc_mgcp_extract_ci((const char *) msg->l2h); - if (endp->ci == CI_UNUSED) { - free_chan_downstream(endp, bsc_endp, bsc); - return; - } - - if (endp->osmux.state == OSMUX_STATE_NEGOTIATING) - bsc_mgcp_osmux_confirm(endp, (const char *) msg->l2h); - - /* If we require osmux and it is disabled.. fail */ - if (nat_osmux_only(bsc->nat->mgcp_cfg, bsc->cfg) && - endp->osmux.state == OSMUX_STATE_DISABLED) { - LOGP(DMGCP, LOGL_ERROR, - "Failed to activate osmux endpoint 0x%x\n", - ENDPOINT_NUMBER(endp)); - free_chan_downstream(endp, bsc_endp, bsc); - return; - } - - /* free some stuff */ - talloc_free(bsc_endp->transaction_id); - bsc_endp->transaction_id = NULL; - bsc_endp->transaction_state = 0; - - /* - * rewrite the information. In case the endpoint was deleted - * there should be nothing for us to rewrite so putting endp->rtp_port - * with the value of 0 should be no problem. - */ - output = bsc_mgcp_rewrite((char * ) msg->l2h, msgb_l2len(msg), -1, - mgcp_net_src_addr(endp), - endp->net_end.local_port, -1, - &endp->bts_end.codec.payload_type, - bsc->nat->sdp_ensure_amr_mode_set); - if (!output) { - LOGP(DMGCP, LOGL_ERROR, "Failed to rewrite MGCP msg.\n"); - return; - } - - mgcp_queue_for_call_agent(bsc->nat, output); -} - -int bsc_mgcp_parse_response(const char *str, int *code, char transaction[60]) -{ - int rc; - /* we want to parse two strings */ - rc = sscanf(str, "%3d %59s\n", code, transaction) != 2; - transaction[59] = '\0'; - return rc; -} - -uint32_t bsc_mgcp_extract_ci(const char *str) -{ - unsigned int ci; - char *res = strstr(str, "I: "); - if (!res) { - LOGP(DMGCP, LOGL_ERROR, "No CI in msg '%s'\n", str); - return CI_UNUSED; - } - - if (sscanf(res, "I: %u", &ci) != 1) { - LOGP(DMGCP, LOGL_ERROR, "Failed to parse CI in msg '%s'\n", str); - return CI_UNUSED; - } - - return ci; -} - -/** - * Create a new MGCPCommand based on the input and endpoint from a message - */ -static void patch_mgcp(struct msgb *output, const char *op, const char *tok, - int endp, int len, int cr, int osmux_cid) -{ - int slen; - int ret; - char buf[40]; - char osmux_extension[strlen("\nX-Osmux: 255") + 1]; - - buf[0] = buf[39] = '\0'; - ret = sscanf(tok, "%*s %s", buf); - if (ret != 1) { - LOGP(DMGCP, LOGL_ERROR, - "Failed to find Endpoint in: %s\n", tok); - return; - } - - if (osmux_cid >= 0) - sprintf(osmux_extension, "\nX-Osmux: %u", osmux_cid & 0xff); - else - osmux_extension[0] = '\0'; - - slen = sprintf((char *) output->l3h, "%s %s %x@mgw MGCP 1.0%s%s", - op, buf, endp, osmux_extension, cr ? "\r\n" : "\n"); - output->l3h = msgb_put(output, slen); -} - -/* we need to replace some strings... */ -struct msgb *bsc_mgcp_rewrite(char *input, int length, int endpoint, - const char *ip, int port, int osmux_cid, - int *first_payload_type, int ensure_mode_set) -{ - static const char crcx_str[] = "CRCX "; - static const char dlcx_str[] = "DLCX "; - static const char mdcx_str[] = "MDCX "; - - static const char ip_str[] = "c=IN IP4 "; - static const char aud_str[] = "m=audio "; - static const char fmt_str[] = "a=fmtp:"; - - char buf[128]; - char *running, *token; - struct msgb *output; - - /* keep state to add the a=fmtp line */ - int found_fmtp = 0; - int payload = -1; - int cr = 1; - - if (length > 4096 - 256) { - LOGP(DMGCP, LOGL_ERROR, "Input is too long.\n"); - return NULL; - } - - output = msgb_alloc_headroom(4096, 128, "MGCP rewritten"); - if (!output) { - LOGP(DMGCP, LOGL_ERROR, "Failed to allocate new MGCP msg.\n"); - return NULL; - } - - running = input; - output->l2h = output->data; - output->l3h = output->l2h; - for (token = strsep(&running, "\n"); running; token = strsep(&running, "\n")) { - int len = strlen(token); - cr = len > 0 && token[len - 1] == '\r'; - - if (strncmp(crcx_str, token, (sizeof crcx_str) - 1) == 0) { - patch_mgcp(output, "CRCX", token, endpoint, len, cr, osmux_cid); - } else if (strncmp(dlcx_str, token, (sizeof dlcx_str) - 1) == 0) { - patch_mgcp(output, "DLCX", token, endpoint, len, cr, -1); - } else if (strncmp(mdcx_str, token, (sizeof mdcx_str) - 1) == 0) { - patch_mgcp(output, "MDCX", token, endpoint, len, cr, -1); - } else if (strncmp(ip_str, token, (sizeof ip_str) - 1) == 0) { - output->l3h = msgb_put(output, strlen(ip_str)); - memcpy(output->l3h, ip_str, strlen(ip_str)); - output->l3h = msgb_put(output, strlen(ip)); - memcpy(output->l3h, ip, strlen(ip)); - - if (cr) { - output->l3h = msgb_put(output, 2); - output->l3h[0] = '\r'; - output->l3h[1] = '\n'; - } else { - output->l3h = msgb_put(output, 1); - output->l3h[0] = '\n'; - } - } else if (strncmp(aud_str, token, (sizeof aud_str) - 1) == 0) { - int offset; - if (sscanf(token, "m=audio %*d RTP/AVP %n%d", &offset, &payload) != 1) { - LOGP(DMGCP, LOGL_ERROR, "Could not parsed audio line.\n"); - msgb_free(output); - return NULL; - } - - snprintf(buf, sizeof(buf)-1, "m=audio %d RTP/AVP %s\n", - port, &token[offset]); - buf[sizeof(buf)-1] = '\0'; - - output->l3h = msgb_put(output, strlen(buf)); - memcpy(output->l3h, buf, strlen(buf)); - } else if (strncmp(fmt_str, token, (sizeof fmt_str) - 1) == 0) { - found_fmtp = 1; - goto copy; - } else { -copy: - output->l3h = msgb_put(output, len + 1); - memcpy(output->l3h, token, len); - output->l3h[len] = '\n'; - } - } - - /* - * the above code made sure that we have 128 bytes lefts. So we can - * safely append another line. - */ - if (ensure_mode_set && !found_fmtp && payload != -1) { - snprintf(buf, sizeof(buf) - 1, "a=fmtp:%d mode-set=2%s", - payload, cr ? "\r\n" : "\n"); - buf[sizeof(buf) - 1] = '\0'; - output->l3h = msgb_put(output, strlen(buf)); - memcpy(output->l3h, buf, strlen(buf)); - } - - if (payload != -1 && first_payload_type) - *first_payload_type = payload; - - return output; -} - -/* - * This comes from the MSC and we will now parse it. The caller needs - * to free the msgb. - */ -void bsc_nat_handle_mgcp(struct bsc_nat *nat, struct msgb *msg) -{ - struct msgb *resp; - - if (!nat->mgcp_ipa) { - LOGP(DMGCP, LOGL_ERROR, "MGCP message not allowed on IPA.\n"); - return; - } - - if (msgb_l2len(msg) > sizeof(nat->mgcp_msg) - 1) { - LOGP(DMGCP, LOGL_ERROR, "MGCP msg too big for handling.\n"); - return; - } - - memcpy(nat->mgcp_msg, msg->l2h, msgb_l2len(msg)); - nat->mgcp_length = msgb_l2len(msg); - nat->mgcp_msg[nat->mgcp_length] = '\0'; - - /* now handle the message */ - resp = mgcp_handle_message(nat->mgcp_cfg, msg); - - /* we do have a direct answer... e.g. AUEP */ - if (resp) - mgcp_queue_for_call_agent(nat, resp); - - return; -} - -static int mgcp_do_read(struct osmo_fd *fd) -{ - struct bsc_nat *nat; - struct msgb *msg, *resp; - int rc; - - nat = fd->data; - - rc = read(fd->fd, nat->mgcp_msg, sizeof(nat->mgcp_msg) - 1); - if (rc <= 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to read errno: %d\n", errno); - return -1; - } - - nat->mgcp_msg[rc] = '\0'; - nat->mgcp_length = rc; - - msg = msgb_alloc(sizeof(nat->mgcp_msg), "MGCP GW Read"); - if (!msg) { - LOGP(DMGCP, LOGL_ERROR, "Failed to create buffer.\n"); - return -1; - } - - msg->l2h = msgb_put(msg, rc); - memcpy(msg->l2h, nat->mgcp_msg, msgb_l2len(msg)); - resp = mgcp_handle_message(nat->mgcp_cfg, msg); - msgb_free(msg); - - /* we do have a direct answer... e.g. AUEP */ - if (resp) - mgcp_queue_for_call_agent(nat, resp); - - return 0; -} - -static int mgcp_do_write(struct osmo_fd *bfd, struct msgb *msg) -{ - int rc; - - rc = write(bfd->fd, msg->data, msg->len); - - if (rc != msg->len) { - LOGP(DMGCP, LOGL_ERROR, "Failed to write msg to MGCP CallAgent.\n"); - return -1; - } - - return rc; -} - -static int init_mgcp_socket(struct bsc_nat *nat, struct mgcp_config *cfg) -{ - struct sockaddr_in addr; - int on; - - cfg->gw_fd.bfd.fd = socket(AF_INET, SOCK_DGRAM, 0); - if (cfg->gw_fd.bfd.fd < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to create MGCP socket. errno: %d\n", errno); - return -1; - } - - on = 1; - setsockopt(cfg->gw_fd.bfd.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); - - memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_port = htons(cfg->source_port); - inet_aton(cfg->source_addr, &addr.sin_addr); - - if (bind(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to bind on %s:%d errno: %d\n", - cfg->source_addr, cfg->source_port, errno); - close(cfg->gw_fd.bfd.fd); - cfg->gw_fd.bfd.fd = -1; - return -1; - } - - addr.sin_port = htons(2727); - inet_aton(cfg->call_agent_addr, &addr.sin_addr); - if (connect(cfg->gw_fd.bfd.fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to connect to: '%s'. errno: %d\n", - cfg->call_agent_addr, errno); - close(cfg->gw_fd.bfd.fd); - cfg->gw_fd.bfd.fd = -1; - return -1; - } - - osmo_wqueue_init(&cfg->gw_fd, 10); - cfg->gw_fd.bfd.when = BSC_FD_READ; - cfg->gw_fd.bfd.data = nat; - cfg->gw_fd.read_cb = mgcp_do_read; - cfg->gw_fd.write_cb = mgcp_do_write; - - if (osmo_fd_register(&cfg->gw_fd.bfd) != 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to register MGCP fd.\n"); - close(cfg->gw_fd.bfd.fd); - cfg->gw_fd.bfd.fd = -1; - return -1; - } - - return 0; -} - -int bsc_mgcp_nat_init(struct bsc_nat *nat) -{ - struct mgcp_config *cfg = nat->mgcp_cfg; - - if (!cfg->call_agent_addr) { - LOGP(DMGCP, LOGL_ERROR, "The BSC nat requires the call agent ip to be set.\n"); - return -1; - } - - if (cfg->bts_ip) { - LOGP(DMGCP, LOGL_ERROR, "Do not set the BTS ip for the nat.\n"); - return -1; - } - - /* initialize the MGCP socket */ - if (!nat->mgcp_ipa) { - int rc = init_mgcp_socket(nat, cfg); - if (rc != 0) - return rc; - } - - - /* some more MGCP config handling */ - cfg->data = nat; - cfg->policy_cb = bsc_mgcp_policy_cb; - - if (cfg->bts_ip) - talloc_free(cfg->bts_ip); - cfg->bts_ip = ""; - - nat->bsc_endpoints = talloc_zero_array(nat, - struct bsc_endpoint, - cfg->trunk.number_endpoints + 1); - if (!nat->bsc_endpoints) { - LOGP(DMGCP, LOGL_ERROR, "Failed to allocate nat endpoints\n"); - close(cfg->gw_fd.bfd.fd); - cfg->gw_fd.bfd.fd = -1; - return -1; - } - - if (mgcp_reset_transcoder(cfg) < 0) { - LOGP(DMGCP, LOGL_ERROR, "Failed to send packet to the transcoder.\n"); - talloc_free(nat->bsc_endpoints); - nat->bsc_endpoints = NULL; - close(cfg->gw_fd.bfd.fd); - cfg->gw_fd.bfd.fd = -1; - return -1; - } - - return 0; -} - -void bsc_mgcp_clear_endpoints_for(struct bsc_connection *bsc) -{ - struct rate_ctr *ctr = NULL; - int i; - - if (bsc->cfg) - ctr = &bsc->cfg->stats.ctrg->ctr[BCFG_CTR_DROPPED_CALLS]; - - for (i = 1; i < bsc->nat->mgcp_cfg->trunk.number_endpoints; ++i) { - struct bsc_endpoint *bsc_endp = &bsc->nat->bsc_endpoints[i]; - - if (bsc_endp->bsc != bsc) - continue; - - if (ctr) - rate_ctr_inc(ctr); - - bsc_mgcp_free_endpoint(bsc->nat, i); - mgcp_release_endp(&bsc->nat->mgcp_cfg->trunk.endpoints[i]); - } -} diff --git a/src/osmo-bsc_nat/bsc_nat.c b/src/osmo-bsc_nat/bsc_nat.c deleted file mode 100644 index af97c5701..000000000 --- a/src/osmo-bsc_nat/bsc_nat.c +++ /dev/null @@ -1,1819 +0,0 @@ -/* BSC Multiplexer/NAT */ - -/* - * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010-2013 by On-Waves - * (C) 2009 by Harald Welte <laforge@gnumonks.org> - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ -#include <sys/socket.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <netinet/in.h> -#include <netinet/tcp.h> -#include <arpa/inet.h> - -#include <errno.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <time.h> -#include <unistd.h> -#include <fcntl.h> -#include <libgen.h> - -#define _GNU_SOURCE -#include <getopt.h> - -#include <osmocom/bsc/debug.h> -#include <osmocom/bsc/bsc_msc.h> -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_nat_sccp.h> -#include <osmocom/bsc/bsc_msg_filter.h> -#include <osmocom/bsc/ipaccess.h> -#include <osmocom/bsc/abis_nm.h> -#include <osmocom/bsc/vty.h> -#include <osmocom/bsc/gsm_04_08_utils.h> - -#include <osmocom/ctrl/control_cmd.h> -#include <osmocom/ctrl/control_if.h> -#include <osmocom/ctrl/ports.h> -#include <osmocom/ctrl/control_vty.h> - -#include <osmocom/crypt/auth.h> - -#include <osmocom/core/application.h> -#include <osmocom/core/talloc.h> -#include <osmocom/core/stats.h> -#include <osmocom/core/socket.h> - -#include <osmocom/gsm/tlv.h> -#include <osmocom/gsm/gsm0808.h> -#include <osmocom/gsm/protocol/gsm_08_08.h> - -#include <osmocom/vty/telnet_interface.h> -#include <osmocom/vty/vty.h> -#include <osmocom/vty/logging.h> -#include <osmocom/vty/stats.h> -#include <osmocom/vty/ports.h> - -#include <osmocom/sccp/sccp.h> - -#include <osmocom/abis/ipa.h> - -#include "../../bscconfig.h" - -#define SCCP_CLOSE_TIME 20 -#define SCCP_CLOSE_TIME_TIMEOUT 19 - -static const char *config_file = "bsc-nat.cfg"; -static const char *local_addr; -static struct osmo_fd bsc_listen; -static const char *msc_ip = NULL; -static struct osmo_timer_list sccp_close; -static int daemonize = 0; - -const char *openbsc_copyright = - "Copyright (C) 2010 Holger Hans Peter Freyther and On-Waves\r\n" - "License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n" - "This is free software: you are free to change and redistribute it.\r\n" - "There is NO WARRANTY, to the extent permitted by law.\r\n"; - -static struct bsc_nat *nat; -static void bsc_send_data(struct bsc_connection *bsc, const uint8_t *data, unsigned int length, int); -static void msc_send_reset(struct bsc_msc_connection *con); -static void bsc_stat_reject(int filter, struct bsc_connection *bsc, int normal); - -struct bsc_config *bsc_config_num(struct bsc_nat *nat, int num) -{ - struct bsc_config *conf; - - llist_for_each_entry(conf, &nat->bsc_configs, entry) - if (conf->nr == num) - return conf; - - return NULL; -} - -static void queue_for_msc(struct bsc_msc_connection *con, struct msgb *msg) -{ - if (!con) { - LOGP(DLINP, LOGL_ERROR, "No MSC Connection assigned. Check your code.\n"); - msgb_free(msg); - return; - } - - - if (osmo_wqueue_enqueue(&con->write_queue, msg) != 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to enqueue the write.\n"); - msgb_free(msg); - } -} - -static void send_reset_ack(struct bsc_connection *bsc) -{ - static const uint8_t gsm_reset_ack[] = { - 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, - 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03, - 0x00, 0x01, 0x31, - }; - - bsc_send_data(bsc, gsm_reset_ack, sizeof(gsm_reset_ack), IPAC_PROTO_SCCP); -} - -static void send_ping(struct bsc_connection *bsc) -{ - static const uint8_t id_ping[] = { - IPAC_MSGT_PING, - }; - - bsc_send_data(bsc, id_ping, sizeof(id_ping), IPAC_PROTO_IPACCESS); -} - -static void send_pong(struct bsc_connection *bsc) -{ - static const uint8_t id_pong[] = { - IPAC_MSGT_PONG, - }; - - bsc_send_data(bsc, id_pong, sizeof(id_pong), IPAC_PROTO_IPACCESS); -} - -static void bsc_pong_timeout(void *_bsc) -{ - struct bsc_connection *bsc = _bsc; - - LOGP(DNAT, LOGL_ERROR, "BSC Nr: %d PONG timeout.\n", bsc->cfg->nr); - bsc_close_connection(bsc); -} - -static void bsc_ping_timeout(void *_bsc) -{ - struct bsc_connection *bsc = _bsc; - - if (bsc->nat->ping_timeout < 0) - return; - - send_ping(bsc); - - /* send another ping in 20 seconds */ - osmo_timer_schedule(&bsc->ping_timeout, bsc->nat->ping_timeout, 0); - - /* also start a pong timer */ - osmo_timer_schedule(&bsc->pong_timeout, bsc->nat->pong_timeout, 0); -} - -static void start_ping_pong(struct bsc_connection *bsc) -{ - osmo_timer_setup(&bsc->pong_timeout, bsc_pong_timeout, bsc); - osmo_timer_setup(&bsc->ping_timeout, bsc_ping_timeout, bsc); - - bsc_ping_timeout(bsc); -} - -static void send_id_ack(struct bsc_connection *bsc) -{ - static const uint8_t id_ack[] = { - IPAC_MSGT_ID_ACK - }; - - bsc_send_data(bsc, id_ack, sizeof(id_ack), IPAC_PROTO_IPACCESS); -} - -static void send_id_req(struct bsc_nat *nat, struct bsc_connection *bsc) -{ - static const uint8_t s_id_req[] = { - IPAC_MSGT_ID_GET, - 0x01, IPAC_IDTAG_UNIT, - 0x01, IPAC_IDTAG_MACADDR, - 0x01, IPAC_IDTAG_LOCATION1, - 0x01, IPAC_IDTAG_LOCATION2, - 0x01, IPAC_IDTAG_EQUIPVERS, - 0x01, IPAC_IDTAG_SWVERSION, - 0x01, IPAC_IDTAG_UNITNAME, - 0x01, IPAC_IDTAG_SERNR, - }; - int rc; - uint8_t *mrand; - uint8_t id_req[sizeof(s_id_req) + (2+16)]; - uint8_t *buf = &id_req[sizeof(s_id_req)]; - - /* copy the static data */ - memcpy(id_req, s_id_req, sizeof(s_id_req)); - - /* put the RAND with length, tag, value */ - buf = v_put(buf, 0x11); - buf = v_put(buf, 0x23); - mrand = bsc->last_rand; - - rc = osmo_get_rand_id(mrand, 16); - if (rc < 0) { - /* the timeout will trigger and close this connection */ - LOGP(DNAT, LOGL_ERROR, "osmo_get_rand_id() failed: %s\n", strerror(-rc)); - return; - } - - memcpy(buf, mrand, 16); - buf += 16; - - bsc_send_data(bsc, id_req, sizeof(id_req), IPAC_PROTO_IPACCESS); -} - -static struct msgb *nat_create_rlsd(struct nat_sccp_connection *conn) -{ - struct sccp_connection_released *rel; - struct msgb *msg; - - msg = msgb_alloc_headroom(4096, 128, "rlsd"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate released.\n"); - return NULL; - } - - msg->l2h = msgb_put(msg, sizeof(*rel)); - rel = (struct sccp_connection_released *) msg->l2h; - rel->type = SCCP_MSG_TYPE_RLSD; - rel->release_cause = SCCP_RELEASE_CAUSE_SCCP_FAILURE; - rel->destination_local_reference = conn->remote_ref; - rel->source_local_reference = conn->patched_ref; - - return msg; -} - -static void nat_send_rlsd_ussd(struct bsc_nat *nat, struct nat_sccp_connection *conn) -{ - struct msgb *msg; - - if (!nat->ussd_con) - return; - - msg = nat_create_rlsd(conn); - if (!msg) - return; - - bsc_do_write(&nat->ussd_con->queue, msg, IPAC_PROTO_SCCP); -} - -static void nat_send_rlsd_msc(struct nat_sccp_connection *conn) -{ - struct msgb *msg; - - msg = nat_create_rlsd(conn); - if (!msg) - return; - - ipa_prepend_header(msg, IPAC_PROTO_SCCP); - queue_for_msc(conn->msc_con, msg); -} - -static void nat_send_rlsd_bsc(struct nat_sccp_connection *conn) -{ - struct msgb *msg; - struct sccp_connection_released *rel; - - msg = msgb_alloc_headroom(4096, 128, "rlsd"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n"); - return; - } - - msg->l2h = msgb_put(msg, sizeof(*rel)); - rel = (struct sccp_connection_released *) msg->l2h; - rel->type = SCCP_MSG_TYPE_RLSD; - rel->release_cause = SCCP_RELEASE_CAUSE_SCCP_FAILURE; - rel->destination_local_reference = conn->real_ref; - rel->source_local_reference = conn->remote_ref; - - bsc_write(conn->bsc, msg, IPAC_PROTO_SCCP); -} - -static struct msgb *nat_creat_clrc(struct nat_sccp_connection *conn, uint8_t cause) -{ - struct msgb *msg; - struct msgb *sccp; - - msg = gsm0808_create_clear_command(cause); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate clear command.\n"); - return NULL; - } - - sccp = sccp_create_dt1(&conn->real_ref, msg->data, msg->len); - if (!sccp) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate SCCP msg.\n"); - msgb_free(msg); - return NULL; - } - - msgb_free(msg); - return sccp; -} - -static int nat_send_clrc_bsc(struct nat_sccp_connection *conn) -{ - struct msgb *sccp; - - sccp = nat_creat_clrc(conn, 0x20); - if (!sccp) - return -1; - return bsc_write(conn->bsc, sccp, IPAC_PROTO_SCCP); -} - -static void nat_send_rlc(struct bsc_msc_connection *msc_con, - struct sccp_source_reference *src, - struct sccp_source_reference *dst) -{ - struct sccp_connection_release_complete *rlc; - struct msgb *msg; - - msg = msgb_alloc_headroom(4096, 128, "rlc"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to sccp rlc.\n"); - return; - } - - msg->l2h = msgb_put(msg, sizeof(*rlc)); - rlc = (struct sccp_connection_release_complete *) msg->l2h; - rlc->type = SCCP_MSG_TYPE_RLC; - rlc->destination_local_reference = *dst; - rlc->source_local_reference = *src; - - ipa_prepend_header(msg, IPAC_PROTO_SCCP); - - queue_for_msc(msc_con, msg); -} - -static void send_mgcp_reset(struct bsc_connection *bsc) -{ - static const uint8_t mgcp_reset[] = { - "RSIP 1 13@mgw MGCP 1.0\r\n" - }; - - bsc_write_mgcp(bsc, mgcp_reset, sizeof mgcp_reset - 1); -} - -void bsc_nat_send_mgcp_to_msc(struct bsc_nat *nat, struct msgb *msg) -{ - ipa_prepend_header(msg, IPAC_PROTO_MGCP_OLD); - queue_for_msc(nat->msc_con, msg); -} - -/* - * Below is the handling of messages coming - * from the MSC and need to be forwarded to - * a real BSC. - */ -static void initialize_msc_if_needed(struct bsc_msc_connection *msc_con) -{ - if (msc_con->first_contact) - return; - - msc_con->first_contact = 1; - msc_send_reset(msc_con); -} - -static void send_id_get_response(struct bsc_msc_connection *msc_con) -{ - struct msgb *msg = bsc_msc_id_get_resp(0, nat->token, NULL, 0); - if (!msg) - return; - - ipa_prepend_header(msg, IPAC_PROTO_IPACCESS); - queue_for_msc(msc_con, msg); -} - -/* - * Currently we are lacking refcounting so we need to copy each message. - */ -static void bsc_send_data(struct bsc_connection *bsc, const uint8_t *data, unsigned int length, int proto) -{ - struct msgb *msg; - - if (length > 4096 - 128) { - LOGP(DLINP, LOGL_ERROR, "Can not send message of that size.\n"); - return; - } - - msg = msgb_alloc_headroom(4096, 128, "to-bsc"); - if (!msg) { - LOGP(DLINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n"); - return; - } - - msg->l2h = msgb_put(msg, length); - memcpy(msg->data, data, length); - - bsc_write(bsc, msg, proto); -} - -/* - * Update the release statistics - */ -static void bsc_stat_reject(int filter, struct bsc_connection *bsc, int normal) -{ - if (!bsc->cfg) { - LOGP(DNAT, LOGL_ERROR, "BSC is not authenticated."); - return; - } - - if (filter >= 0) { - LOGP(DNAT, LOGL_ERROR, "Connection was not rejected"); - return; - } - - if (filter == -1) - rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_ILL_PACKET]); - else if (normal) - rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_REJECTED_MSG]); - else - rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_REJECTED_CR]); -} - -/* - * Release an established connection. We will have to release it to the BSC - * and to the network and we do it the following way. - * 1.) Give up on the MSC side - * 1.1) Send a RLSD message, it is a bit non standard but should work, we - * ignore the RLC... we might complain about it. Other options would - * be to send a Release Request, handle the Release Complete.. - * 1.2) Mark the data structure to be con_local and wait for 2nd - * - * 2.) Give up on the BSC side - * 2.1) Depending on the con type reject the service, or just close it - */ -static void bsc_send_con_release(struct bsc_connection *bsc, - struct nat_sccp_connection *con, - struct bsc_filter_reject_cause *cause) -{ - struct msgb *rlsd; - /* 1. release the network */ - rlsd = sccp_create_rlsd(&con->patched_ref, &con->remote_ref, - SCCP_RELEASE_CAUSE_END_USER_ORIGINATED); - if (!rlsd) - LOGP(DNAT, LOGL_ERROR, "Failed to create RLSD message.\n"); - else { - ipa_prepend_header(rlsd, IPAC_PROTO_SCCP); - queue_for_msc(con->msc_con, rlsd); - } - con->con_local = NAT_CON_END_LOCAL; - con->msc_con = NULL; - - /* 2. release the BSC side */ - if (con->filter_state.con_type == FLT_CON_TYPE_LU) { - struct msgb *payload, *udt; - payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause); - - if (payload) { - gsm0808_prepend_dtap_header(payload, 0); - udt = sccp_create_dt1(&con->real_ref, payload->data, payload->len); - if (udt) - bsc_write(bsc, udt, IPAC_PROTO_SCCP); - else - LOGP(DNAT, LOGL_ERROR, "Failed to create DT1\n"); - - msgb_free(payload); - } else { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate LU Reject.\n"); - } - } - - nat_send_clrc_bsc(con); - - rlsd = sccp_create_rlsd(&con->remote_ref, &con->real_ref, - SCCP_RELEASE_CAUSE_END_USER_ORIGINATED); - if (!rlsd) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate RLSD for the BSC.\n"); - sccp_connection_destroy(con); - return; - } - - con->filter_state.con_type = FLT_CON_TYPE_LOCAL_REJECT; - bsc_write(bsc, rlsd, IPAC_PROTO_SCCP); -} - -static void bsc_send_con_refuse(struct bsc_connection *bsc, - struct bsc_nat_parsed *parsed, int con_type, - struct bsc_filter_reject_cause *cause) -{ - struct msgb *payload; - struct msgb *refuse; - - if (con_type == FLT_CON_TYPE_LU) - payload = gsm48_create_loc_upd_rej(cause->lu_reject_cause); - else if (con_type == FLT_CON_TYPE_CM_SERV_REQ || con_type == FLT_CON_TYPE_SSA) - payload = gsm48_create_mm_serv_rej(cause->cm_reject_cause); - else { - LOGP(DNAT, LOGL_ERROR, "Unknown connection type: %d\n", con_type); - payload = NULL; - } - - /* - * Some BSCs do not handle the payload inside a SCCP CREF msg - * so we will need to: - * 1.) Allocate a local connection and mark it as local.. - * 2.) queue data for downstream.. and the RLC should delete everything - */ - if (payload) { - struct msgb *cc, *udt, *clear, *rlsd; - struct nat_sccp_connection *con; - con = create_sccp_src_ref(bsc, parsed); - if (!con) - goto send_refuse; - - /* declare it local and assign a unique remote_ref */ - con->filter_state.con_type = FLT_CON_TYPE_LOCAL_REJECT; - con->con_local = NAT_CON_END_LOCAL; - con->has_remote_ref = 1; - con->remote_ref = con->patched_ref; - - /* 1. create a confirmation */ - cc = sccp_create_cc(&con->remote_ref, &con->real_ref); - if (!cc) - goto send_refuse; - - /* 2. create the DT1 */ - gsm0808_prepend_dtap_header(payload, 0); - udt = sccp_create_dt1(&con->real_ref, payload->data, payload->len); - if (!udt) { - msgb_free(cc); - goto send_refuse; - } - - /* 3. send a Clear Command */ - clear = nat_creat_clrc(con, 0x20); - if (!clear) { - msgb_free(cc); - msgb_free(udt); - goto send_refuse; - } - - /* 4. send a RLSD */ - rlsd = sccp_create_rlsd(&con->remote_ref, &con->real_ref, - SCCP_RELEASE_CAUSE_END_USER_ORIGINATED); - if (!rlsd) { - msgb_free(cc); - msgb_free(udt); - msgb_free(clear); - goto send_refuse; - } - - bsc_write(bsc, cc, IPAC_PROTO_SCCP); - bsc_write(bsc, udt, IPAC_PROTO_SCCP); - bsc_write(bsc, clear, IPAC_PROTO_SCCP); - bsc_write(bsc, rlsd, IPAC_PROTO_SCCP); - msgb_free(payload); - return; - } - - -send_refuse: - if (payload) - msgb_free(payload); - - refuse = sccp_create_refuse(parsed->src_local_ref, - SCCP_REFUSAL_SCCP_FAILURE, NULL, 0); - if (!refuse) { - LOGP(DNAT, LOGL_ERROR, - "Creating refuse msg failed for SCCP 0x%x on BSC Nr: %d.\n", - sccp_src_ref_to_int(parsed->src_local_ref), bsc->cfg->nr); - return; - } - - bsc_write(bsc, refuse, IPAC_PROTO_SCCP); -} - -static void bsc_nat_send_paging(struct bsc_connection *bsc, struct msgb *msg) -{ - if (bsc->cfg->forbid_paging) { - LOGP(DNAT, LOGL_DEBUG, "Paging forbidden for BTS: %d\n", bsc->cfg->nr); - return; - } - - bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), IPAC_PROTO_SCCP); -} - -static void bsc_nat_handle_paging(struct bsc_nat *nat, struct msgb *msg) -{ - struct bsc_connection *bsc; - const uint8_t *paging_start; - int paging_length, i, ret; - - ret = bsc_nat_find_paging(msg, &paging_start, &paging_length); - if (ret != 0) { - LOGP(DNAT, LOGL_ERROR, "Could not parse paging message: %d\n", ret); - return; - } - - /* This is quite expensive now */ - for (i = 0; i < paging_length; i += 2) { - unsigned int _lac = ntohs(*(unsigned int *) &paging_start[i]); - unsigned int paged = 0; - llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) { - if (!bsc->cfg) - continue; - if (!bsc->authenticated) - continue; - if (!bsc_config_handles_lac(bsc->cfg, _lac)) - continue; - bsc_nat_send_paging(bsc, msg); - paged += 1; - } - - /* highlight a possible config issue */ - if (paged == 0) - LOGP(DNAT, LOGL_ERROR, "No BSC for LAC %d/0x%d\n", _lac, _lac); - - } -} - - -/* - * Update the auth status. This can be either a CIPHER MODE COMMAND or - * a CM Serivce Accept. Maybe also LU Accept or such in the future. - */ -static void update_con_authorize(struct nat_sccp_connection *con, - struct bsc_nat_parsed *parsed, - struct msgb *msg) -{ - if (!con) - return; - if (con->authorized) - return; - - if (parsed->bssap == BSSAP_MSG_BSS_MANAGEMENT && - parsed->gsm_type == BSS_MAP_MSG_CIPHER_MODE_CMD) { - con->authorized = 1; - } else if (parsed->bssap == BSSAP_MSG_DTAP) { - uint8_t msg_type, proto; - uint32_t len; - struct gsm48_hdr *hdr48; - hdr48 = bsc_unpack_dtap(parsed, msg, &len); - if (!hdr48) - return; - - proto = gsm48_hdr_pdisc(hdr48); - msg_type = gsm48_hdr_msg_type(hdr48); - if (proto == GSM48_PDISC_MM && - msg_type == GSM48_MT_MM_CM_SERV_ACC) - con->authorized = 1; - } -} - -static int forward_sccp_to_bts(struct bsc_msc_connection *msc_con, struct msgb *msg) -{ - struct nat_sccp_connection *con = NULL; - struct bsc_connection *bsc; - struct bsc_nat_parsed *parsed; - int proto; - - /* filter, drop, patch the message? */ - parsed = bsc_nat_parse(msg); - if (!parsed) { - LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n"); - return -1; - } - - if (bsc_nat_filter_ipa(DIR_BSC, msg, parsed)) - goto exit; - - proto = parsed->ipa_proto; - - /* Route and modify the SCCP packet */ - if (proto == IPAC_PROTO_SCCP) { - switch (parsed->sccp_type) { - case SCCP_MSG_TYPE_UDT: - /* forward UDT messages to every BSC */ - goto send_to_all; - break; - case SCCP_MSG_TYPE_RLSD: - case SCCP_MSG_TYPE_CREF: - case SCCP_MSG_TYPE_DT1: - case SCCP_MSG_TYPE_IT: - con = patch_sccp_src_ref_to_bsc(msg, parsed, nat); - if (parsed->gsm_type == BSS_MAP_MSG_ASSIGMENT_RQST) { - osmo_counter_inc(nat->stats.sccp.calls); - - if (con) { - struct rate_ctr_group *ctrg; - ctrg = con->bsc->cfg->stats.ctrg; - rate_ctr_inc(&ctrg->ctr[BCFG_CTR_SCCP_CALLS]); - if (bsc_mgcp_assign_patch(con, msg) != 0) - LOGP(DNAT, LOGL_ERROR, "Failed to assign...\n"); - } else - LOGP(DNAT, LOGL_ERROR, "Assignment command but no BSC.\n"); - } else if (con && con->con_local == NAT_CON_END_USSD && - parsed->gsm_type == BSS_MAP_MSG_CLEAR_CMD) { - LOGP(DNAT, LOGL_NOTICE, "Clear Command for USSD Connection. Ignoring.\n"); - con = NULL; - } - break; - case SCCP_MSG_TYPE_CC: - con = patch_sccp_src_ref_to_bsc(msg, parsed, nat); - if (!con || update_sccp_src_ref(con, parsed) != 0) - goto exit; - break; - case SCCP_MSG_TYPE_RLC: - LOGP(DNAT, LOGL_ERROR, "Unexpected release complete from MSC.\n"); - goto exit; - break; - case SCCP_MSG_TYPE_CR: - /* MSC never opens a SCCP connection, fall through */ - default: - goto exit; - } - - if (!con && parsed->sccp_type == SCCP_MSG_TYPE_RLSD) { - LOGP(DNAT, LOGL_NOTICE, "Sending fake RLC on RLSD message to network.\n"); - /* Exchange src/dest for the reply */ - nat_send_rlc(msc_con, &parsed->original_dest_ref, - parsed->src_local_ref); - } else if (!con) - LOGP(DNAT, LOGL_ERROR, "Unknown connection for msg type: 0x%x from the MSC.\n", parsed->sccp_type); - } - - if (!con) { - talloc_free(parsed); - return -1; - } - if (!con->bsc->authenticated) { - talloc_free(parsed); - LOGP(DNAT, LOGL_ERROR, "Selected BSC not authenticated.\n"); - return -1; - } - - update_con_authorize(con, parsed, msg); - talloc_free(parsed); - - bsc_send_data(con->bsc, msg->l2h, msgb_l2len(msg), proto); - return 0; - -send_to_all: - /* - * Filter Paging from the network. We do not want to send a PAGING - * Command to every BSC in our network. We will analys the PAGING - * message and then send it to the authenticated messages... - */ - if (parsed->ipa_proto == IPAC_PROTO_SCCP && parsed->gsm_type == BSS_MAP_MSG_PAGING) { - bsc_nat_handle_paging(nat, msg); - goto exit; - } - /* currently send this to every BSC connected */ - llist_for_each_entry(bsc, &nat->bsc_connections, list_entry) { - if (!bsc->authenticated) - continue; - - bsc_send_data(bsc, msg->l2h, msgb_l2len(msg), parsed->ipa_proto); - } - -exit: - talloc_free(parsed); - return 0; -} - -static void msc_connection_was_lost(struct bsc_msc_connection *con) -{ - struct bsc_connection *bsc, *tmp; - - LOGP(DMSC, LOGL_ERROR, "Closing all connections downstream.\n"); - llist_for_each_entry_safe(bsc, tmp, &nat->bsc_connections, list_entry) - bsc_close_connection(bsc); - - bsc_mgcp_free_endpoints(nat); - bsc_msc_schedule_connect(con); -} - -static void msc_connection_connected(struct bsc_msc_connection *con) -{ - osmo_counter_inc(nat->stats.msc.reconn); -} - -static void msc_send_reset(struct bsc_msc_connection *msc_con) -{ - static const uint8_t reset[] = { - 0x00, 0x12, 0xfd, - 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe, - 0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04, - 0x01, 0x20 - }; - - struct msgb *msg; - - msg = msgb_alloc_headroom(4096, 128, "08.08 reset"); - if (!msg) { - LOGP(DMSC, LOGL_ERROR, "Failed to allocate reset msg.\n"); - return; - } - - msg->l2h = msgb_put(msg, sizeof(reset)); - memcpy(msg->l2h, reset, msgb_l2len(msg)); - - queue_for_msc(msc_con, msg); - - LOGP(DMSC, LOGL_NOTICE, "Scheduled GSM0808 reset msg for the MSC.\n"); -} - -static int ipaccess_msc_read_cb(struct osmo_fd *bfd) -{ - struct bsc_msc_connection *msc_con; - struct msgb *msg = NULL; - struct ipaccess_head *hh; - int ret; - - msc_con = (struct bsc_msc_connection *) bfd->data; - - ret = ipa_msg_recv_buffered(bfd->fd, &msg, &msc_con->pending_msg); - if (ret <= 0) { - if (ret == -EAGAIN) - return 0; - if (ret == 0) - LOGP(DNAT, LOGL_FATAL, - "The connection the MSC(%s) was lost, exiting\n", - msc_con->name); - else - LOGP(DNAT, LOGL_ERROR, - "Failed to parse ip access message on %s: %d\n", - msc_con->name, ret); - - bsc_msc_lost(msc_con); - return -1; - } - - LOGP(DNAT, LOGL_DEBUG, - "MSG from MSC(%s): %s proto: %d\n", msc_con->name, - osmo_hexdump(msg->data, msg->len), msg->l2h[0]); - - /* handle base message handling */ - hh = (struct ipaccess_head *) msg->data; - - /* initialize the networking. This includes sending a GSM08.08 message */ - if (hh->proto == IPAC_PROTO_IPACCESS) { - ipa_ccm_rcvmsg_base(msg, bfd); - if (msg->l2h[0] == IPAC_MSGT_ID_ACK) - initialize_msc_if_needed(msc_con); - else if (msg->l2h[0] == IPAC_MSGT_ID_GET) - send_id_get_response(msc_con); - } else if (hh->proto == IPAC_PROTO_SCCP) { - forward_sccp_to_bts(msc_con, msg); - } else if (hh->proto == IPAC_PROTO_MGCP_OLD) { - bsc_nat_handle_mgcp(nat, msg); - } - - msgb_free(msg); - return 0; -} - -static int ipaccess_msc_write_cb(struct osmo_fd *bfd, struct msgb *msg) -{ - int rc; - rc = write(bfd->fd, msg->data, msg->len); - - if (rc != msg->len) { - LOGP(DNAT, LOGL_ERROR, "Failed to write MSG to MSC.\n"); - return -1; - } - - return rc; -} - -/* - * Below is the handling of messages coming - * from the BSC and need to be forwarded to - * a real BSC. - */ - -/* - * Remove the connection from the connections list, - * remove it from the patching of SCCP header lists - * as well. Maybe in the future even close connection.. - */ -void bsc_close_connection(struct bsc_connection *connection) -{ - struct nat_sccp_connection *sccp_patch, *tmp; - struct bsc_cmd_list *cmd_entry, *cmd_tmp; - struct rate_ctr *ctr = NULL; - - /* stop the timeout timer */ - osmo_timer_del(&connection->id_timeout); - osmo_timer_del(&connection->ping_timeout); - osmo_timer_del(&connection->pong_timeout); - - if (connection->cfg) - ctr = &connection->cfg->stats.ctrg->ctr[BCFG_CTR_DROPPED_SCCP]; - - /* remove all SCCP connections */ - llist_for_each_entry_safe(sccp_patch, tmp, &nat->sccp_connections, list_entry) { - if (sccp_patch->bsc != connection) - continue; - - if (ctr) - rate_ctr_inc(ctr); - if (sccp_patch->has_remote_ref) { - if (sccp_patch->con_local == NAT_CON_END_MSC) - nat_send_rlsd_msc(sccp_patch); - else if (sccp_patch->con_local == NAT_CON_END_USSD) - nat_send_rlsd_ussd(nat, sccp_patch); - } - - sccp_connection_destroy(sccp_patch); - } - - /* Reply to all outstanding commands */ - llist_for_each_entry_safe(cmd_entry, cmd_tmp, &connection->cmd_pending, list_entry) { - cmd_entry->cmd->type = CTRL_TYPE_ERROR; - cmd_entry->cmd->reply = "BSC closed the connection"; - ctrl_cmd_send(&cmd_entry->cmd->ccon->write_queue, cmd_entry->cmd); - bsc_nat_ctrl_del_pending(cmd_entry); - } - - /* close endpoints allocated by this BSC */ - bsc_mgcp_clear_endpoints_for(connection); - - osmo_fd_unregister(&connection->write_queue.bfd); - close(connection->write_queue.bfd.fd); - osmo_wqueue_clear(&connection->write_queue); - llist_del(&connection->list_entry); - - if (connection->pending_msg) { - LOGP(DNAT, LOGL_ERROR, "Dropping partial message on connection %d.\n", - connection->cfg ? connection->cfg->nr : -1); - msgb_free(connection->pending_msg); - connection->pending_msg = NULL; - } - - talloc_free(connection); -} - -static void bsc_maybe_close(struct bsc_connection *bsc) -{ - struct nat_sccp_connection *sccp; - if (!bsc->nat->blocked) - return; - - /* are there any connections left */ - llist_for_each_entry(sccp, &bsc->nat->sccp_connections, list_entry) - if (sccp->bsc == bsc) - return; - - /* nothing left, close the BSC */ - LOGP(DNAT, LOGL_NOTICE, "Cleaning up BSC %d in blocking mode.\n", - bsc->cfg ? bsc->cfg->nr : -1); - bsc_close_connection(bsc); -} - -static void ipaccess_close_bsc(void *data) -{ - struct sockaddr_in sock; - socklen_t len = sizeof(sock); - struct bsc_connection *conn = data; - - - getpeername(conn->write_queue.bfd.fd, (struct sockaddr *) &sock, &len); - LOGP(DNAT, LOGL_ERROR, "BSC on %s didn't respond to identity request. Closing.\n", - inet_ntoa(sock.sin_addr)); - bsc_close_connection(conn); -} - -static int verify_key(struct bsc_connection *conn, struct bsc_config *conf, const uint8_t *key, const int keylen) -{ - struct osmo_auth_vector vec; - - struct osmo_sub_auth_data auth = { - .type = OSMO_AUTH_TYPE_GSM, - .algo = OSMO_AUTH_ALG_MILENAGE, - }; - - /* expect a specific keylen */ - if (keylen != 8) { - LOGP(DNAT, LOGL_ERROR, "Key length is wrong: %d for bsc nr %d\n", - keylen, conf->nr); - return 0; - } - - memcpy(auth.u.umts.opc, conf->key, 16); - memcpy(auth.u.umts.k, conf->key, 16); - memset(auth.u.umts.amf, 0, 2); - auth.u.umts.sqn = 0; - - memset(&vec, 0, sizeof(vec)); - osmo_auth_gen_vec(&vec, &auth, conn->last_rand); - - if (vec.res_len != 8) { - LOGP(DNAT, LOGL_ERROR, "Res length is wrong: %d for bsc nr %d\n", - vec.res_len, conf->nr); - return 0; - } - - return osmo_constant_time_cmp(vec.res, key, 8) == 0; -} - -static void ipaccess_auth_bsc(struct tlv_parsed *tvp, struct bsc_connection *bsc) -{ - struct bsc_config *conf; - const char *token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME); - int len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME); - const uint8_t *xres = TLVP_VAL(tvp, 0x24); - const int xlen = TLVP_LEN(tvp, 0x24); - - if (bsc->cfg) { - LOGP(DNAT, LOGL_ERROR, "Reauth on fd %d bsc nr %d\n", - bsc->write_queue.bfd.fd, bsc->cfg->nr); - return; - } - - if (len <= 0) { - LOGP(DNAT, LOGL_ERROR, "Token with length zero on fd: %d\n", - bsc->write_queue.bfd.fd); - return; - } - - if (token[len - 1] != '\0') { - LOGP(DNAT, LOGL_ERROR, "Token not null terminated on fd: %d\n", - bsc->write_queue.bfd.fd); - return; - } - - /* - * New systems have fixed the structure of the message but - * we need to support old ones too. - */ - if (len >= 2 && token[len - 2] == '\0') - len -= 1; - - conf = bsc_config_by_token(bsc->nat, token, len); - if (!conf) { - LOGP(DNAT, LOGL_ERROR, - "No bsc found for token '%s' len %d on fd: %d.\n", token, - bsc->write_queue.bfd.fd, len); - bsc_close_connection(bsc); - return; - } - - /* We have set a key and expect it to be present */ - if (conf->key_present && !verify_key(bsc, conf, xres, xlen - 1)) { - LOGP(DNAT, LOGL_ERROR, - "Wrong key for bsc nr %d fd: %d.\n", conf->nr, - bsc->write_queue.bfd.fd); - bsc_close_connection(bsc); - return; - } - - rate_ctr_inc(&conf->stats.ctrg->ctr[BCFG_CTR_NET_RECONN]); - bsc->authenticated = 1; - bsc->cfg = conf; - osmo_timer_del(&bsc->id_timeout); - LOGP(DNAT, LOGL_NOTICE, "Authenticated bsc nr: %d on fd %d\n", - conf->nr, bsc->write_queue.bfd.fd); - start_ping_pong(bsc); -} - -static void handle_con_stats(struct nat_sccp_connection *con) -{ - struct rate_ctr_group *ctrg; - int id = bsc_conn_type_to_ctr(con); - - if (id == -1) - return; - - if (!con->bsc || !con->bsc->cfg) - return; - - ctrg = con->bsc->cfg->stats.ctrg; - rate_ctr_inc(&ctrg->ctr[id]); -} - -static int forward_sccp_to_msc(struct bsc_connection *bsc, struct msgb *msg) -{ - int con_filter = 0; - char *imsi = NULL; - struct bsc_msc_connection *con_msc = NULL; - struct bsc_connection *con_bsc = NULL; - int con_type; - struct bsc_nat_parsed *parsed; - struct bsc_filter_reject_cause cause; - - /* Parse and filter messages */ - parsed = bsc_nat_parse(msg); - if (!parsed) { - LOGP(DNAT, LOGL_ERROR, "Can not parse msg from BSC.\n"); - msgb_free(msg); - return -1; - } - - if (bsc_nat_filter_ipa(DIR_MSC, msg, parsed)) - goto exit; - - /* - * check authentication after filtering to not reject auth - * responses coming from the BSC. We have to make sure that - * nothing from the exit path will forward things to the MSC - */ - if (!bsc->authenticated) { - LOGP(DNAT, LOGL_ERROR, "BSC is not authenticated.\n"); - msgb_free(msg); - return -1; - } - - - /* modify the SCCP entries */ - if (parsed->ipa_proto == IPAC_PROTO_SCCP) { - int filter; - struct nat_sccp_connection *con; - switch (parsed->sccp_type) { - case SCCP_MSG_TYPE_CR: - memset(&cause, 0, sizeof(cause)); - filter = bsc_nat_filter_sccp_cr(bsc, msg, parsed, - &con_type, &imsi, &cause); - if (filter < 0) { - if (imsi) - bsc_nat_inform_reject(bsc, imsi); - bsc_stat_reject(filter, bsc, 0); - goto exit3; - } - - if (!create_sccp_src_ref(bsc, parsed)) - goto exit2; - con = patch_sccp_src_ref_to_msc(msg, parsed, bsc); - OSMO_ASSERT(con); - con->msc_con = bsc->nat->msc_con; - con_msc = con->msc_con; - con->filter_state.con_type = con_type; - con->filter_state.imsi_checked = filter; - bsc_nat_extract_lac(bsc, con, parsed, msg); - if (imsi) - con->filter_state.imsi = talloc_steal(con, imsi); - imsi = NULL; - con_bsc = con->bsc; - handle_con_stats(con); - break; - case SCCP_MSG_TYPE_RLSD: - case SCCP_MSG_TYPE_CREF: - case SCCP_MSG_TYPE_DT1: - case SCCP_MSG_TYPE_CC: - case SCCP_MSG_TYPE_IT: - con = patch_sccp_src_ref_to_msc(msg, parsed, bsc); - if (con) { - /* only filter non local connections */ - if (!con->con_local) { - memset(&cause, 0, sizeof(cause)); - filter = bsc_nat_filter_dt(bsc, msg, - con, parsed, &cause); - if (filter < 0) { - if (con->filter_state.imsi) - bsc_nat_inform_reject(bsc, - con->filter_state.imsi); - bsc_stat_reject(filter, bsc, 1); - bsc_send_con_release(bsc, con, &cause); - con = NULL; - goto exit2; - } - - /* hand data to a side channel */ - if (bsc_ussd_check(con, parsed, msg) == 1) - con->con_local = NAT_CON_END_USSD; - - /* - * Optionally rewrite setup message. This can - * replace the msg and the parsed structure becomes - * invalid. - */ - msg = bsc_nat_rewrite_msg(bsc->nat, msg, parsed, - con->filter_state.imsi); - talloc_free(parsed); - parsed = NULL; - } else if (con->con_local == NAT_CON_END_USSD) { - bsc_ussd_check(con, parsed, msg); - } - - con_bsc = con->bsc; - con_msc = con->msc_con; - con_filter = con->con_local; - } - - break; - case SCCP_MSG_TYPE_RLC: - con = patch_sccp_src_ref_to_msc(msg, parsed, bsc); - if (con) { - con_bsc = con->bsc; - con_msc = con->msc_con; - con_filter = con->con_local; - } - remove_sccp_src_ref(bsc, msg, parsed); - bsc_maybe_close(bsc); - break; - case SCCP_MSG_TYPE_UDT: - /* simply forward everything */ - con = NULL; - break; - default: - LOGP(DNAT, LOGL_ERROR, "Not forwarding to msc sccp type: 0x%x\n", parsed->sccp_type); - con = NULL; - goto exit2; - break; - } - } else if (parsed->ipa_proto == IPAC_PROTO_MGCP_OLD) { - bsc_mgcp_forward(bsc, msg); - goto exit2; - } else { - LOGP(DNAT, LOGL_ERROR, "Not forwarding unknown stream id: 0x%x\n", parsed->ipa_proto); - goto exit2; - } - - if (con_msc && con_bsc != bsc) { - LOGP(DNAT, LOGL_ERROR, "The connection belongs to a different BTS: input: %d con: %d\n", - bsc->cfg->nr, con_bsc->cfg->nr); - goto exit2; - } - - /* do not forward messages to the MSC */ - if (con_filter) - goto exit2; - - if (!con_msc) { - LOGP(DNAT, LOGL_ERROR, "Not forwarding data bsc_nr: %d ipa: %d type: 0x%x\n", - bsc->cfg->nr, - parsed ? parsed->ipa_proto : -1, - parsed ? parsed->sccp_type : -1); - goto exit2; - } - - /* send the non-filtered but maybe modified msg */ - queue_for_msc(con_msc, msg); - if (parsed) - talloc_free(parsed); - return 0; - -exit: - /* if we filter out the reset send an ack to the BSC */ - if (parsed->bssap == 0 && parsed->gsm_type == BSS_MAP_MSG_RESET) { - send_reset_ack(bsc); - send_reset_ack(bsc); - } else if (parsed->ipa_proto == IPAC_PROTO_IPACCESS) { - /* do we know who is handling this? */ - if (msg->l2h[0] == IPAC_MSGT_ID_RESP && msgb_l2len(msg) > 2) { - struct tlv_parsed tvp; - int ret; - ret = ipa_ccm_idtag_parse_off(&tvp, - (unsigned char *) msg->l2h + 2, - msgb_l2len(msg) - 2, 0); - if (ret < 0) { - LOGP(DNAT, LOGL_ERROR, "ignoring IPA response " - "message with malformed TLVs\n"); - return ret; - } - if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME)) - ipaccess_auth_bsc(&tvp, bsc); - } - - goto exit2; - } - -exit2: - if (imsi) - talloc_free(imsi); - talloc_free(parsed); - msgb_free(msg); - return -1; - -exit3: - /* send a SCCP Connection Refused */ - if (imsi) - talloc_free(imsi); - bsc_send_con_refuse(bsc, parsed, con_type, &cause); - talloc_free(parsed); - msgb_free(msg); - return -1; -} - -static int ipaccess_bsc_read_cb(struct osmo_fd *bfd) -{ - struct bsc_connection *bsc = bfd->data; - struct msgb *msg = NULL; - struct ipaccess_head *hh; - struct ipaccess_head_ext *hh_ext; - int ret; - - ret = ipa_msg_recv_buffered(bfd->fd, &msg, &bsc->pending_msg); - if (ret <= 0) { - if (ret == -EAGAIN) - return 0; - if (ret == 0) - LOGP(DNAT, LOGL_ERROR, - "The connection to the BSC Nr: %d was lost. Cleaning it\n", - bsc->cfg ? bsc->cfg->nr : -1); - else - LOGP(DNAT, LOGL_ERROR, - "Stream error on BSC Nr: %d. Failed to parse ip access message: %d (%s)\n", - bsc->cfg ? bsc->cfg->nr : -1, ret, strerror(-ret)); - - bsc_close_connection(bsc); - return -1; - } - - - LOGP(DNAT, LOGL_DEBUG, "MSG from BSC: %s proto: %d\n", osmo_hexdump(msg->data, msg->len), msg->l2h[0]); - - /* Handle messages from the BSC */ - hh = (struct ipaccess_head *) msg->data; - - /* stop the pong timeout */ - if (hh->proto == IPAC_PROTO_IPACCESS) { - if (msg->l2h[0] == IPAC_MSGT_PONG) { - osmo_timer_del(&bsc->pong_timeout); - msgb_free(msg); - return 0; - } else if (msg->l2h[0] == IPAC_MSGT_PING) { - send_pong(bsc); - msgb_free(msg); - return 0; - } - /* Message contains the ipaccess_head_ext header, investigate further */ - } else if (hh->proto == IPAC_PROTO_OSMO && - msg->len > sizeof(*hh) + sizeof(*hh_ext)) { - - hh_ext = (struct ipaccess_head_ext *) hh->data; - /* l2h is where the actual command data is expected */ - msg->l2h = hh_ext->data; - - if (hh_ext->proto == IPAC_PROTO_EXT_CTRL) - return bsc_nat_handle_ctrlif_msg(bsc, msg); - } - - /* FIXME: Currently no PONG is sent to the BSC */ - /* FIXME: Currently no ID ACK is sent to the BSC */ - forward_sccp_to_msc(bsc, msg); - - return 0; -} - -static int ipaccess_listen_bsc_cb(struct osmo_fd *bfd, unsigned int what) -{ - struct bsc_connection *bsc; - int fd, rc, on; - struct sockaddr_in sa; - socklen_t sa_len = sizeof(sa); - - if (!(what & BSC_FD_READ)) - return 0; - - fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len); - if (fd < 0) { - perror("accept"); - return fd; - } - - /* count the reconnect */ - osmo_counter_inc(nat->stats.bsc.reconn); - - /* - * if we are not connected to a msc... just close the socket - */ - if (!bsc_nat_msc_is_connected(nat)) { - LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due lack of MSC connection.\n"); - close(fd); - return 0; - } - - if (nat->blocked) { - LOGP(DNAT, LOGL_NOTICE, "Disconnecting BSC due NAT being blocked.\n"); - close(fd); - return 0; - } - - on = 1; - rc = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); - if (rc != 0) - LOGP(DNAT, LOGL_ERROR, "Failed to set TCP_NODELAY: %s\n", strerror(errno)); - - rc = setsockopt(fd, IPPROTO_IP, IP_TOS, - &nat->bsc_ip_dscp, sizeof(nat->bsc_ip_dscp)); - if (rc != 0) - LOGP(DNAT, LOGL_ERROR, "Failed to set IP_TOS: %s\n", strerror(errno)); - - /* todo... do something with the connection */ - /* todo... use GNUtls to see if we want to trust this as a BTS */ - - /* - * - */ - bsc = bsc_connection_alloc(nat); - if (!bsc) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate BSC struct.\n"); - close(fd); - return -1; - } - - bsc->write_queue.bfd.data = bsc; - bsc->write_queue.bfd.fd = fd; - bsc->write_queue.read_cb = ipaccess_bsc_read_cb; - bsc->write_queue.write_cb = bsc_write_cb; - bsc->write_queue.bfd.when = BSC_FD_READ; - if (osmo_fd_register(&bsc->write_queue.bfd) < 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to register BSC fd.\n"); - close(fd); - talloc_free(bsc); - return -2; - } - - LOGP(DNAT, LOGL_NOTICE, "BSC connection on %d with IP: %s\n", - fd, inet_ntoa(sa.sin_addr)); - - llist_add(&bsc->list_entry, &nat->bsc_connections); - bsc->last_id = 0; - - send_id_ack(bsc); - send_id_req(nat, bsc); - send_mgcp_reset(bsc); - - /* - * start the hangup timer - */ - osmo_timer_setup(&bsc->id_timeout, ipaccess_close_bsc, bsc); - osmo_timer_schedule(&bsc->id_timeout, nat->auth_timeout, 0); - return 0; -} - -static void print_usage() -{ - printf("Usage: bsc_nat\n"); -} - -static void print_help() -{ - printf(" Some useful help...\n"); - printf(" -h --help this text\n"); - printf(" -d option --debug=DRLL:DCC:DMM:DRR:DRSL:DNM enable debugging\n"); - printf(" -D --daemonize Fork the process into a background daemon\n"); - printf(" -s --disable-color\n"); - printf(" -c --config-file filename The config file to use.\n"); - printf(" -m --msc=IP. The address of the MSC.\n"); - printf(" -l --local=IP. The local address of this BSC.\n"); -} - -static void handle_options(int argc, char **argv) -{ - while (1) { - int option_index = 0, c; - static struct option long_options[] = { - {"help", 0, 0, 'h'}, - {"debug", 1, 0, 'd'}, - {"daemonize", 0, 0, 'D'}, - {"config-file", 1, 0, 'c'}, - {"disable-color", 0, 0, 's'}, - {"timestamp", 0, 0, 'T'}, - {"msc", 1, 0, 'm'}, - {"local", 1, 0, 'l'}, - {0, 0, 0, 0} - }; - - c = getopt_long(argc, argv, "hd:sTPc:m:l:D", - long_options, &option_index); - if (c == -1) - break; - - switch (c) { - case 'h': - print_usage(); - print_help(); - exit(0); - case 's': - log_set_use_color(osmo_stderr_target, 0); - break; - case 'd': - log_parse_category_mask(osmo_stderr_target, optarg); - break; - case 'D': - daemonize = 1; - break; - case 'c': - config_file = optarg; - break; - case 'T': - log_set_print_timestamp(osmo_stderr_target, 1); - break; - case 'm': - msc_ip = optarg; - break; - case 'l': - local_addr = optarg; - break; - default: - /* ignore */ - break; - } - } -} - -static void signal_handler(int signal) -{ - switch (signal) { - case SIGABRT: - /* in case of abort, we want to obtain a talloc report - * and then return to the caller, who will abort the process */ - case SIGUSR1: - talloc_report_full(tall_bsc_ctx, stderr); - break; - default: - break; - } -} - -static void sccp_close_unconfirmed(void *_data) -{ - int destroyed = 0; - struct bsc_connection *bsc, *bsc_tmp; - struct nat_sccp_connection *conn, *tmp1; - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - - llist_for_each_entry_safe(conn, tmp1, &nat->sccp_connections, list_entry) { - if (conn->has_remote_ref) - continue; - - int diff = (now.tv_sec - conn->creation_time.tv_sec) / 60; - if (diff < SCCP_CLOSE_TIME_TIMEOUT) - continue; - - LOGP(DNAT, LOGL_ERROR, - "SCCP connection 0x%x/0x%x was never confirmed on bsc nr. %d\n", - sccp_src_ref_to_int(&conn->real_ref), - sccp_src_ref_to_int(&conn->patched_ref), - conn->bsc->cfg->nr); - sccp_connection_destroy(conn); - destroyed = 1; - } - - if (!destroyed) - goto out; - - /* now close out any BSC */ - llist_for_each_entry_safe(bsc, bsc_tmp, &nat->bsc_connections, list_entry) - bsc_maybe_close(bsc); - -out: - osmo_timer_schedule(&sccp_close, SCCP_CLOSE_TIME, 0); -} - -extern void *tall_sigh_ctx; -extern void *tall_ctr_ctx; - -static void talloc_init_ctx() -{ - tall_bsc_ctx = talloc_named_const(NULL, 0, "nat"); - msgb_talloc_ctx_init(tall_bsc_ctx, 0); - - tall_sigh_ctx = talloc_named_const(tall_bsc_ctx, 0, "signal_handler"); - tall_ctr_ctx = talloc_named_const(tall_bsc_ctx, 0, "counter"); -} - -static int bsc_vty_go_parent(struct vty *vty) -{ - switch (vty->node) { - case NAT_BSC_NODE: - vty->node = NAT_NODE; - { - struct bsc_config *bsc_config = vty->index; - vty->index = bsc_config->nat; - } - break; - case PGROUP_NODE: - vty->node = NAT_NODE; - vty->index = NULL; - break; - case TRUNK_NODE: - vty->node = MGCP_NODE; - vty->index = NULL; - break; - case NAT_NODE: - vty->node = CONFIG_NODE; - vty->index = NULL; - break; - default: - osmo_ss7_vty_go_parent(vty); - } - - return vty->node; -} - -static int bsc_vty_is_config_node(struct vty *vty, int node) -{ - /* Check if libosmo-sccp declares the node in - * question as config node */ - if (osmo_ss7_is_config_node(vty, node)) - return 1; - - switch (node) { - /* add items that are not config */ - case CONFIG_NODE: - return 0; - - default: - return 1; - } -} - -static struct vty_app_info vty_info = { - .name = "OsmoBSCNAT", - .version = PACKAGE_VERSION, - .go_parent_cb = bsc_vty_go_parent, - .is_config_node = bsc_vty_is_config_node, -}; - -static const struct log_info_cat log_categories[] = { - [DNM] = { - .name = "DNM", - .description = "A-bis Network Management / O&M (NM/OML)", - .color = "\033[1;36m", - .enabled = 1, .loglevel = LOGL_INFO, - }, - [DNAT] = { - .name = "DNAT", - .description = "GSM 08.08 NAT/Multiplexer", - .enabled = 1, .loglevel = LOGL_NOTICE, - }, - [DMSC] = { - .name = "DMSC", - .description = "Mobile Switching Center", - .enabled = 1, .loglevel = LOGL_NOTICE, - }, - [DCTRL] = { - .name = "DCTRL", - .description = "Control interface", - .enabled = 1, .loglevel = LOGL_NOTICE, - }, - [DFILTER] = { - .name = "DFILTER", - .description = "BSC/NAT IMSI based filtering", - .enabled = 1, .loglevel = LOGL_DEBUG, - }, -}; - -static const struct log_info log_info = { - .cat = log_categories, - .num_cat = ARRAY_SIZE(log_categories), -}; - -int main(int argc, char **argv) -{ - int rc; - - talloc_init_ctx(); - - osmo_init_logging(&log_info); - - nat = bsc_nat_alloc(); - if (!nat) { - fprintf(stderr, "Failed to allocate the BSC nat.\n"); - return -4; - } - - nat->mgcp_cfg = mgcp_config_alloc(); - if (!nat->mgcp_cfg) { - fprintf(stderr, "Failed to allocate MGCP cfg.\n"); - return -5; - } - - /* We need to add mode-set for amr codecs */ - nat->sdp_ensure_amr_mode_set = 1; - - vty_info.copyright = openbsc_copyright; - vty_init(&vty_info); - logging_vty_add_cmds(NULL); - osmo_stats_vty_add_cmds(&log_info); - bsc_nat_vty_init(nat); - ctrl_vty_init(tall_bsc_ctx); - - - /* parse options */ - local_addr = NULL; - handle_options(argc, argv); - - nat->include_base = dirname(talloc_strdup(tall_bsc_ctx, config_file)); - - rate_ctr_init(tall_bsc_ctx); - osmo_stats_init(tall_bsc_ctx); - - /* Ensure that forced enpoint allocation is turned on by default */ - nat->mgcp_cfg->trunk.force_realloc = 1; - - /* init vty and parse */ - if (mgcp_parse_config(config_file, nat->mgcp_cfg, MGCP_BSC_NAT) < 0) { - fprintf(stderr, "Failed to parse the config file: '%s'\n", config_file); - return -3; - } - - /* start telnet after reading config for vty_get_bind_addr() */ - if (telnet_init_dynif(tall_bsc_ctx, NULL, vty_get_bind_addr(), - OSMO_VTY_PORT_BSC_NAT)) { - fprintf(stderr, "Creating VTY telnet line failed\n"); - return -5; - } - - /* over rule the VTY config for MSC IP */ - if (msc_ip) - bsc_nat_set_msc_ip(nat, msc_ip); - - /* seed the PRNG */ - srand(time(NULL)); - - LOGP(DNAT, LOGL_NOTICE, "BSCs configured from %s\n", nat->resolved_path); - - /* - * Setup the MGCP code.. - */ - if (bsc_mgcp_nat_init(nat) != 0) - return -4; - - /* connect to the MSC */ - nat->msc_con = bsc_msc_create(nat, &nat->dests); - if (!nat->msc_con) { - fprintf(stderr, "Creating a bsc_msc_connection failed.\n"); - exit(1); - } - - /* start control interface after reading config for - * ctrl_vty_get_bind_addr() */ - nat->ctrl = bsc_nat_controlif_setup(nat, ctrl_vty_get_bind_addr(), - OSMO_CTRL_PORT_BSC_NAT); - if (!nat->ctrl) { - fprintf(stderr, "Creating the control interface failed.\n"); - exit(1); - } - - nat->msc_con->name = "main MSC"; - nat->msc_con->connection_loss = msc_connection_was_lost; - nat->msc_con->connected = msc_connection_connected; - nat->msc_con->write_queue.read_cb = ipaccess_msc_read_cb; - nat->msc_con->write_queue.write_cb = ipaccess_msc_write_cb;; - nat->msc_con->write_queue.bfd.data = nat->msc_con; - bsc_msc_connect(nat->msc_con); - - /* wait for the BSC */ - bsc_listen.cb = ipaccess_listen_bsc_cb; - bsc_listen.data = nat; - rc = osmo_sock_init_ofd(&bsc_listen, AF_INET, SOCK_STREAM, IPPROTO_TCP, - local_addr, 5000, OSMO_SOCK_F_BIND); - if (rc != 0) { - fprintf(stderr, "Failed to listen for BSC.\n"); - exit(1); - } - - rc = bsc_ussd_init(nat); - if (rc != 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to bind the USSD socket.\n"); - exit(1); - } - - signal(SIGABRT, &signal_handler); - signal(SIGUSR1, &signal_handler); - osmo_init_ignore_signals(); - - if (daemonize) { - rc = osmo_daemonize(); - if (rc < 0) { - perror("Error during daemonize"); - exit(1); - } - } - - /* recycle timer */ - sccp_set_log_area(DSCCP); - osmo_timer_setup(&sccp_close, sccp_close_unconfirmed, NULL); - osmo_timer_schedule(&sccp_close, SCCP_CLOSE_TIME, 0); - - while (1) { - osmo_select_main(0); - } - - return 0; -} - -/* Close all connections handed out to the USSD module */ -int bsc_ussd_close_connections(struct bsc_nat *nat) -{ - struct nat_sccp_connection *con; - llist_for_each_entry(con, &nat->sccp_connections, list_entry) { - if (con->con_local != NAT_CON_END_USSD) - continue; - if (!con->bsc) - continue; - - nat_send_clrc_bsc(con); - nat_send_rlsd_bsc(con); - } - - return 0; -} diff --git a/src/osmo-bsc_nat/bsc_nat_ctrl.c b/src/osmo-bsc_nat/bsc_nat_ctrl.c deleted file mode 100644 index 75c0dfaa5..000000000 --- a/src/osmo-bsc_nat/bsc_nat_ctrl.c +++ /dev/null @@ -1,531 +0,0 @@ -/* - * (C) 2011-2012 by Holger Hans Peter Freyther - * (C) 2011-2012 by On-Waves - * (C) 2011 by Daniel Willmann - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <osmocom/core/talloc.h> - -#include <osmocom/ctrl/control_cmd.h> -#include <osmocom/ctrl/control_if.h> -#include <osmocom/ctrl/ports.h> - -#include <osmocom/vty/misc.h> - -#include <osmocom/bsc/ctrl.h> -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_msg_filter.h> -#include <osmocom/bsc/vty.h> -#include <osmocom/bsc/gsm_data.h> -#include <osmocom/bsc/debug.h> - -#include <unistd.h> -#include <string.h> -#include <errno.h> - - -#define NAT_MAX_CTRL_ID 65535 - -static struct bsc_nat *g_nat; - -static int bsc_id_unused(int id, struct bsc_connection *bsc) -{ - struct bsc_cmd_list *pending; - - llist_for_each_entry(pending, &bsc->cmd_pending, list_entry) { - if (pending->nat_id == id) - return 0; - } - return 1; -} - -static int get_next_free_bsc_id(struct bsc_connection *bsc) -{ - int new_id, overflow = 0; - - new_id = bsc->last_id; - - do { - new_id++; - if (new_id == NAT_MAX_CTRL_ID) { - new_id = 1; - overflow++; - } - - if (bsc_id_unused(new_id, bsc)) { - bsc->last_id = new_id; - return new_id; - } - } while (overflow != 2); - - return -1; -} - -void bsc_nat_ctrl_del_pending(struct bsc_cmd_list *pending) -{ - llist_del(&pending->list_entry); - osmo_timer_del(&pending->timeout); - talloc_free(pending); -} - -static struct bsc_cmd_list *bsc_get_pending(struct bsc_connection *bsc, char *id_str) -{ - struct bsc_cmd_list *cmd_entry; - int id = atoi(id_str); - if (id == 0) - return NULL; - - llist_for_each_entry(cmd_entry, &bsc->cmd_pending, list_entry) { - if (cmd_entry->nat_id == id) { - return cmd_entry; - } - } - return NULL; -} - -int bsc_nat_handle_ctrlif_msg(struct bsc_connection *bsc, struct msgb *msg) -{ - struct ctrl_cmd *cmd; - struct bsc_cmd_list *pending; - char *var; - - cmd = ctrl_cmd_parse(bsc, msg); - msgb_free(msg); - - if (!cmd) { - cmd = talloc_zero(bsc, struct ctrl_cmd); - if (!cmd) { - LOGP(DNAT, LOGL_ERROR, "OOM!\n"); - return -ENOMEM; - } - cmd->type = CTRL_TYPE_ERROR; - cmd->id = "err"; - cmd->reply = "Failed to parse command."; - goto err; - } - - if (bsc->cfg && !llist_empty(&bsc->cfg->lac_list)) { - if (cmd->variable) { - var = talloc_asprintf(cmd, "net.0.bsc.%i.%s", bsc->cfg->nr, - cmd->variable); - if (!var) { - cmd->type = CTRL_TYPE_ERROR; - cmd->reply = "OOM"; - goto err; - } - talloc_free(cmd->variable); - cmd->variable = var; - } - - /* We have to handle TRAPs before matching pending */ - if (cmd->type == CTRL_TYPE_TRAP) { - ctrl_cmd_send_to_all(bsc->nat->ctrl, cmd); - talloc_free(cmd); - return 0; - } - - /* Find the pending command */ - pending = bsc_get_pending(bsc, cmd->id); - if (pending) { - osmo_talloc_replace_string(cmd, &cmd->id, pending->cmd->id); - if (!cmd->id) { - cmd->type = CTRL_TYPE_ERROR; - cmd->reply = "OOM"; - goto err; - } - ctrl_cmd_send(&pending->cmd->ccon->write_queue, cmd); - bsc_nat_ctrl_del_pending(pending); - } else { - /* We need to handle TRAPS here */ - if ((cmd->type != CTRL_TYPE_ERROR) && - (cmd->type != CTRL_TYPE_TRAP)) { - LOGP(DNAT, LOGL_NOTICE, "Got control message " - "from BSC without pending entry\n"); - cmd->type = CTRL_TYPE_ERROR; - cmd->reply = "No request outstanding"; - goto err; - } - } - } - talloc_free(cmd); - return 0; -err: - ctrl_cmd_send(&bsc->write_queue, cmd); - talloc_free(cmd); - return 0; -} - -static void pending_timeout_cb(void *data) -{ - struct bsc_cmd_list *pending = data; - LOGP(DNAT, LOGL_ERROR, "Command timed out\n"); - pending->cmd->type = CTRL_TYPE_ERROR; - pending->cmd->reply = "Command timed out"; - ctrl_cmd_send(&pending->cmd->ccon->write_queue, pending->cmd); - - bsc_nat_ctrl_del_pending(pending); -} - -static void ctrl_conn_closed_cb(struct ctrl_connection *connection) -{ - struct bsc_connection *bsc; - struct bsc_cmd_list *pending, *tmp; - - llist_for_each_entry(bsc, &g_nat->bsc_connections, list_entry) { - llist_for_each_entry_safe(pending, tmp, &bsc->cmd_pending, list_entry) { - if (pending->cmd->ccon == connection) - bsc_nat_ctrl_del_pending(pending); - } - } -} - -static int extract_bsc_nr_variable(char *variable, unsigned int *nr, char **bsc_variable) -{ - char *nr_str, *tmp, *saveptr = NULL; - - tmp = strtok_r(variable, ".", &saveptr); - tmp = strtok_r(NULL, ".", &saveptr); - tmp = strtok_r(NULL, ".", &saveptr); - nr_str = strtok_r(NULL, ".", &saveptr); - if (!nr_str) - return 0; - *nr = atoi(nr_str); - - tmp = strtok_r(NULL, "\0", &saveptr); - if (!tmp) - return 0; - - *bsc_variable = tmp; - return 1; -} - -static int forward_to_bsc(struct ctrl_cmd *cmd) -{ - int ret = CTRL_CMD_HANDLED; - struct ctrl_cmd *bsc_cmd = NULL; - struct bsc_connection *bsc; - struct bsc_cmd_list *pending = NULL; - unsigned int nr; - char *bsc_variable; - - /* Skip over the beginning (bsc.) */ - if (!extract_bsc_nr_variable(cmd->variable, &nr, &bsc_variable)) { - cmd->reply = "command incomplete"; - goto err; - } - - - llist_for_each_entry(bsc, &g_nat->bsc_connections, list_entry) { - if (!bsc->cfg) - continue; - if (!bsc->authenticated) - continue; - if (bsc->cfg->nr != nr) - continue; - - /* Add pending command to list */ - pending = talloc_zero(bsc, struct bsc_cmd_list); - if (!pending) { - cmd->reply = "OOM"; - goto err; - } - - pending->nat_id = get_next_free_bsc_id(bsc); - if (pending->nat_id < 0) { - cmd->reply = "No free ID found"; - goto err; - } - - bsc_cmd = ctrl_cmd_cpy(bsc, cmd); - if (!bsc_cmd) { - cmd->reply = "Could not forward command"; - goto err; - } - - talloc_free(bsc_cmd->id); - bsc_cmd->id = talloc_asprintf(bsc_cmd, "%i", pending->nat_id); - if (!bsc_cmd->id) { - cmd->reply = "OOM"; - goto err; - } - - talloc_free(bsc_cmd->variable); - bsc_cmd->variable = talloc_strdup(bsc_cmd, bsc_variable); - if (!bsc_cmd->variable) { - cmd->reply = "OOM"; - goto err; - } - - if (ctrl_cmd_send(&bsc->write_queue, bsc_cmd)) { - cmd->reply = "Sending failed"; - goto err; - } - - /* caller owns cmd param and will destroy it after we return */ - pending->cmd = ctrl_cmd_cpy(pending, cmd); - if (!pending->cmd) { - cmd->reply = "Could not answer command"; - goto err; - } - cmd->ccon->closed_cb = ctrl_conn_closed_cb; - pending->cmd->ccon = cmd->ccon; - - /* Setup the timeout */ - osmo_timer_setup(&pending->timeout, pending_timeout_cb, - pending); - /* TODO: Make timeout configurable */ - osmo_timer_schedule(&pending->timeout, 10, 0); - llist_add_tail(&pending->list_entry, &bsc->cmd_pending); - - goto done; - } - /* We end up here if there's no bsc to handle our LAC */ - cmd->reply = "no BSC with this nr"; -err: - ret = CTRL_CMD_ERROR; - talloc_free(pending); -done: - talloc_free(bsc_cmd); - return ret; - -} - - -CTRL_CMD_DEFINE(fwd_cmd, "net 0 bsc *"); -static int get_fwd_cmd(struct ctrl_cmd *cmd, void *data) -{ - return forward_to_bsc(cmd); -} - -static int set_fwd_cmd(struct ctrl_cmd *cmd, void *data) -{ - return forward_to_bsc(cmd); -} - -static int verify_fwd_cmd(struct ctrl_cmd *cmd, const char *value, void *data) -{ - return 0; -} - -static int extract_bsc_cfg_variable(struct ctrl_cmd *cmd, struct bsc_config **cfg, - char **bsc_variable) -{ - unsigned int nr; - - if (!extract_bsc_nr_variable(cmd->variable, &nr, bsc_variable)) { - cmd->reply = "command incomplete"; - return 0; - } - - *cfg = bsc_config_num(g_nat, nr); - if (!*cfg) { - cmd->reply = "Unknown BSC"; - return 0; - } - - return 1; -} - -CTRL_CMD_DEFINE(net_cfg_cmd, "net 0 bsc_cfg *"); -static int get_net_cfg_cmd(struct ctrl_cmd *cmd, void *data) -{ - char *bsc_variable; - struct bsc_config *bsc_cfg; - - if (!extract_bsc_cfg_variable(cmd, &bsc_cfg, &bsc_variable)) - return CTRL_CMD_ERROR; - - if (strcmp(bsc_variable, "access-list-name") == 0) { - cmd->reply = talloc_asprintf(cmd, "%s", - bsc_cfg->acc_lst_name ? bsc_cfg->acc_lst_name : ""); - return CTRL_CMD_REPLY; - } - - cmd->reply = "unknown command"; - return CTRL_CMD_ERROR; -} - -static int set_net_cfg_cmd(struct ctrl_cmd *cmd, void *data) -{ - char *bsc_variable; - struct bsc_config *bsc_cfg; - - if (!extract_bsc_cfg_variable(cmd, &bsc_cfg, &bsc_variable)) - return CTRL_CMD_ERROR; - - if (strcmp(bsc_variable, "access-list-name") == 0) { - osmo_talloc_replace_string(bsc_cfg, &bsc_cfg->acc_lst_name, cmd->value); - cmd->reply = talloc_asprintf(cmd, "%s", - bsc_cfg->acc_lst_name ? bsc_cfg->acc_lst_name : ""); - return CTRL_CMD_REPLY; - } else if (strcmp(bsc_variable, "no-access-list-name") == 0) { - talloc_free(bsc_cfg->acc_lst_name); - bsc_cfg->acc_lst_name = NULL; - cmd->reply = ""; - return CTRL_CMD_REPLY; - } - - cmd->reply = "unknown command"; - return CTRL_CMD_ERROR; -} - -static int verify_net_cfg_cmd(struct ctrl_cmd *cmd, const char *value, void *data) -{ - return 0; -} - -CTRL_CMD_DEFINE(net_cfg_acc_cmd, "net 0 add allow access-list *"); -static const char *extract_acc_name(const char *var) -{ - char *str; - - str = strstr(var, "net.0.add.allow.access-list."); - if (!str) - return NULL; - str += strlen("net.0.add.allow.access-list."); - if (strlen(str) == 0) - return NULL; - return str; -} - -static int get_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data) -{ - cmd->reply = "Append only"; - return CTRL_CMD_ERROR; -} - -static int set_net_cfg_acc_cmd(struct ctrl_cmd *cmd, void *data) -{ - const char *access_name = extract_acc_name(cmd->variable); - struct bsc_msg_acc_lst *acc; - struct bsc_msg_acc_lst_entry *entry; - const char *value = cmd->value; - int rc; - - /* Should have been caught by verify_net_cfg_acc_cmd */ - acc = bsc_msg_acc_lst_find(&g_nat->access_lists, access_name); - if (!acc) { - cmd->reply = "Access list not found"; - return CTRL_CMD_ERROR; - } - - entry = bsc_msg_acc_lst_entry_create(acc); - if (!entry) { - cmd->reply = "OOM"; - return CTRL_CMD_ERROR; - } - - rc = gsm_parse_reg(acc, &entry->imsi_allow_re, &entry->imsi_allow, 1, &value); - if (rc != 0) { - cmd->reply = "Failed to compile expression"; - return CTRL_CMD_ERROR; - } - - cmd->reply = "IMSI allow added to access list"; - return CTRL_CMD_REPLY; -} - -static int verify_net_cfg_acc_cmd(struct ctrl_cmd *cmd, const char *value, void *data) -{ - const char *access_name = extract_acc_name(cmd->variable); - struct bsc_msg_acc_lst *acc = bsc_msg_acc_lst_find(&g_nat->access_lists, access_name); - - if (!acc) { - cmd->reply = "Access list not known"; - return -1; - } - - return 0; -} - -CTRL_CMD_DEFINE_WO_NOVRF(net_save_cmd, "net 0 save-configuration"); - -static int set_net_save_cmd(struct ctrl_cmd *cmd, void *data) -{ - int rc = osmo_vty_save_config_file(); - cmd->reply = talloc_asprintf(cmd, "%d", rc); - if (!cmd->reply) { - cmd->reply = "OOM"; - return CTRL_CMD_ERROR; - } - - return CTRL_CMD_REPLY; -} - -struct ctrl_handle *bsc_nat_controlif_setup(struct bsc_nat *nat, - const char *bind_addr, int port) -{ - struct ctrl_handle *ctrl; - int rc; - - - ctrl = bsc_controlif_setup(NULL, bind_addr, OSMO_CTRL_PORT_BSC_NAT); - if (!ctrl) { - fprintf(stderr, "Failed to initialize the control interface. Exiting.\n"); - return NULL; - } - - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_fwd_cmd); - if (rc) { - fprintf(stderr, "Failed to install the control command. Exiting.\n"); - goto error; - } - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_cfg_cmd); - if (rc) { - fprintf(stderr, "Failed to install the net cfg command. Exiting.\n"); - goto error; - } - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_cfg_acc_cmd); - if (rc) { - fprintf(stderr, "Failed to install the net acc command. Exiting.\n"); - goto error; - } - rc = ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_net_save_cmd); - if (rc) { - fprintf(stderr, "Failed to install the net save command. Exiting.\n"); - goto error; - } - - g_nat = nat; - return ctrl; - -error: - osmo_fd_unregister(&ctrl->listen_fd); - close(ctrl->listen_fd.fd); - talloc_free(ctrl); - return NULL; -} - -void bsc_nat_inform_reject(struct bsc_connection *conn, const char *imsi) -{ - struct ctrl_cmd *cmd; - - cmd = ctrl_cmd_create(conn, CTRL_TYPE_TRAP); - if (!cmd) { - LOGP(DCTRL, LOGL_ERROR, "Failed to create TRAP command.\n"); - return; - } - - cmd->id = "0"; - cmd->variable = talloc_asprintf(cmd, "net.0.bsc.%d.notification-rejection-v1", - conn->cfg->nr); - cmd->reply = talloc_asprintf(cmd, "imsi=%s", imsi); - - ctrl_cmd_send_to_all(conn->cfg->nat->ctrl, cmd); - talloc_free(cmd); -} diff --git a/src/osmo-bsc_nat/bsc_nat_filter.c b/src/osmo-bsc_nat/bsc_nat_filter.c deleted file mode 100644 index cd7ca25a4..000000000 --- a/src/osmo-bsc_nat/bsc_nat_filter.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * (C) 2010-2015 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010-2012 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_nat_sccp.h> -#include <osmocom/bsc/bsc_msg_filter.h> -#include <osmocom/bsc/debug.h> - -#include <osmocom/gsm/gsm0808.h> - -#include <osmocom/gsm/protocol/gsm_08_08.h> -#include <osmocom/gsm/protocol/gsm_04_11.h> - -#include <osmocom/sccp/sccp.h> - -/* Filter out CR data... */ -int bsc_nat_filter_sccp_cr(struct bsc_connection *bsc, struct msgb *msg, - struct bsc_nat_parsed *parsed, int *con_type, - char **imsi, struct bsc_filter_reject_cause *cause) -{ - struct bsc_filter_request req; - struct tlv_parsed tp; - struct gsm48_hdr *hdr48; - int hdr48_len; - int len; - - *con_type = FLT_CON_TYPE_NONE; - cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - *imsi = NULL; - - if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) { - LOGP(DNAT, LOGL_ERROR, - "Rejecting CR message due wrong GSM Type %d\n", parsed->gsm_type); - return -1; - } - - /* the parsed has had some basic l3 length check */ - len = msg->l3h[1]; - if (msgb_l3len(msg) - 3 < len) { - LOGP(DNAT, LOGL_ERROR, - "The CR Data has not enough space...\n"); - return -1; - } - - msg->l4h = &msg->l3h[3]; - len -= 1; - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h, len, 0, 0); - - if (!TLVP_PRESENT(&tp, GSM0808_IE_LAYER_3_INFORMATION)) { - LOGP(DNAT, LOGL_ERROR, "CR Data does not contain layer3 information.\n"); - return -1; - } - - hdr48_len = TLVP_LEN(&tp, GSM0808_IE_LAYER_3_INFORMATION); - - if (hdr48_len < sizeof(*hdr48)) { - LOGP(DNAT, LOGL_ERROR, "GSM48 header does not fit.\n"); - return -1; - } - - hdr48 = (struct gsm48_hdr *) TLVP_VAL(&tp, GSM0808_IE_LAYER_3_INFORMATION); - req.ctx = bsc; - req.black_list = &bsc->nat->imsi_black_list; - req.access_lists = &bsc->nat->access_lists; - req.local_lst_name = bsc->cfg->acc_lst_name; - req.global_lst_name = bsc->nat->acc_lst_name; - req.bsc_nr = bsc->cfg->nr; - return bsc_msg_filter_initial(hdr48, hdr48_len, &req, con_type, imsi, cause); -} - -int bsc_nat_filter_dt(struct bsc_connection *bsc, struct msgb *msg, - struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, - struct bsc_filter_reject_cause *cause) -{ - uint32_t len; - struct gsm48_hdr *hdr48; - struct bsc_filter_request req; - - cause->cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - cause->lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED; - - if (con->filter_state.imsi_checked) - return 0; - - /* only care about DTAP messages */ - if (parsed->bssap != BSSAP_MSG_DTAP) - return 0; - - hdr48 = bsc_unpack_dtap(parsed, msg, &len); - if (!hdr48) - return -1; - - req.ctx = con; - req.black_list = &bsc->nat->imsi_black_list; - req.access_lists = &bsc->nat->access_lists; - req.local_lst_name = bsc->cfg->acc_lst_name; - req.global_lst_name = bsc->nat->acc_lst_name; - req.bsc_nr = bsc->cfg->nr; - return bsc_msg_filter_data(hdr48, len, &req, &con->filter_state, cause); -} diff --git a/src/osmo-bsc_nat/bsc_nat_rewrite.c b/src/osmo-bsc_nat/bsc_nat_rewrite.c deleted file mode 100644 index 7db9234ef..000000000 --- a/src/osmo-bsc_nat/bsc_nat_rewrite.c +++ /dev/null @@ -1,730 +0,0 @@ -/* - * Message rewriting functionality - */ -/* - * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010-2013 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_nat_sccp.h> -#include <osmocom/bsc/bsc_msc.h> -#include <osmocom/bsc/gsm_data.h> -#include <osmocom/bsc/debug.h> -#include <osmocom/bsc/ipaccess.h> -#include <osmocom/bsc/nat_rewrite_trie.h> - -#include <osmocom/core/linuxlist.h> -#include <osmocom/core/talloc.h> -#include <osmocom/core/utils.h> -#include <osmocom/gsm/gsm0808.h> -#include <osmocom/gsm/ipa.h> -#include <osmocom/gsm/mncc.h> -#include <osmocom/gsm/gsm48.h> - -#include <osmocom/gsm/protocol/gsm_08_08.h> -#include <osmocom/gsm/protocol/gsm_04_11.h> - -#include <osmocom/sccp/sccp.h> - -static char *trie_lookup(struct nat_rewrite *trie, const char *number, - regoff_t off, void *ctx) -{ - struct nat_rewrite_rule *rule; - - if (!trie) { - LOGP(DCC, LOGL_ERROR, - "Asked to do a table lookup but no table.\n"); - return NULL; - } - - rule = nat_rewrite_lookup(trie, number); - if (!rule) { - LOGP(DCC, LOGL_DEBUG, - "Couldn't find a prefix rule for %s\n", number); - return NULL; - } - - return talloc_asprintf(ctx, "%s%s", rule->rewrite, &number[off]); -} - -static char *match_and_rewrite_number(void *ctx, const char *number, - const char *imsi, struct llist_head *list, - struct nat_rewrite *trie) -{ - struct bsc_nat_num_rewr_entry *entry; - char *new_number = NULL; - - /* need to find a replacement and then fix it */ - llist_for_each_entry(entry, list, list) { - regmatch_t matches[2]; - - /* check the IMSI match */ - if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0) - continue; - - /* this regexp matches... */ - if (regexec(&entry->num_reg, number, 2, matches, 0) == 0 - && matches[1].rm_eo != -1) { - if (entry->is_prefix_lookup) - new_number = trie_lookup(trie, number, - matches[1].rm_so, ctx); - else - new_number = talloc_asprintf(ctx, "%s%s", - entry->replace, - &number[matches[1].rm_so]); - } - - if (new_number) - break; - } - - return new_number; -} - -static char *rewrite_isdn_number(struct bsc_nat *nat, struct llist_head *rewr_list, - void *ctx, const char *imsi, - struct gsm_mncc_number *called) -{ - char int_number[sizeof(called->number) + 2]; - char *number = called->number; - - if (llist_empty(&nat->num_rewr)) { - LOGP(DCC, LOGL_DEBUG, "Rewrite rules empty.\n"); - return NULL; - } - - /* only ISDN plan */ - if (called->plan != 1) { - LOGP(DCC, LOGL_DEBUG, "Called plan is not 1 it was %d\n", - called->plan); - return NULL; - } - - /* international, prepend */ - if (called->type == 1) { - int_number[0] = '+'; - memcpy(&int_number[1], number, strlen(number) + 1); - number = int_number; - } - - return match_and_rewrite_number(ctx, number, - imsi, rewr_list, nat->num_rewr_trie); -} - -static void update_called_number(struct gsm_mncc_number *called, - const char *chosen_number) -{ - if (strncmp(chosen_number, "00", 2) == 0) { - called->type = 1; - osmo_strlcpy(called->number, chosen_number + 2, - sizeof(called->number)); - } else { - /* rewrite international to unknown */ - if (called->type == 1) - called->type = 0; - osmo_strlcpy(called->number, chosen_number, - sizeof(called->number)); - } -} - -/** - * Rewrite non global numbers... according to rules based on the IMSI - */ -static struct msgb *rewrite_setup(struct bsc_nat *nat, struct msgb *msg, - struct bsc_nat_parsed *parsed, const char *imsi, - struct gsm48_hdr *hdr48, const uint32_t len) -{ - struct tlv_parsed tp; - unsigned int payload_len; - struct gsm_mncc_number called; - struct msgb *out; - char *new_number_pre = NULL, *new_number_post = NULL, *chosen_number; - uint8_t *outptr; - const uint8_t *msgptr; - int sec_len; - - /* decode and rewrite the message */ - payload_len = len - sizeof(*hdr48); - tlv_parse(&tp, &gsm48_att_tlvdef, hdr48->data, payload_len, 0, 0); - - /* no number, well let us ignore it */ - if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) - return NULL; - - memset(&called, 0, sizeof(called)); - gsm48_decode_called(&called, - TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 1); - - /* check if it looks international and stop */ - LOGP(DCC, LOGL_DEBUG, - "Pre-Rewrite for IMSI(%s) Plan(%d) Type(%d) Number(%s)\n", - imsi, called.plan, called.type, called.number); - new_number_pre = rewrite_isdn_number(nat, &nat->num_rewr, msg, imsi, &called); - - if (!new_number_pre) { - LOGP(DCC, LOGL_DEBUG, "No IMSI(%s) match found, returning message.\n", - imsi); - return NULL; - } - - if (strlen(new_number_pre) > sizeof(called.number)) { - LOGP(DCC, LOGL_ERROR, "Number %s is too long for structure.\n", - new_number_pre); - talloc_free(new_number_pre); - return NULL; - } - update_called_number(&called, new_number_pre); - - /* another run through the re-write engine with other rules */ - LOGP(DCC, LOGL_DEBUG, - "Post-Rewrite for IMSI(%s) Plan(%d) Type(%d) Number(%s)\n", - imsi, called.plan, called.type, called.number); - new_number_post = rewrite_isdn_number(nat, &nat->num_rewr_post, msg, - imsi, &called); - chosen_number = new_number_post ? new_number_post : new_number_pre; - - - if (strlen(chosen_number) > sizeof(called.number)) { - LOGP(DCC, LOGL_ERROR, "Number %s is too long for structure.\n", - chosen_number); - talloc_free(new_number_pre); - talloc_free(new_number_post); - return NULL; - } - - /* - * Need to create a new message now based on the old onew - * with a new number. We can sadly not patch this in place - * so we will need to regenerate it. - */ - - out = msgb_alloc_headroom(4096, 128, "changed-setup"); - if (!out) { - LOGP(DCC, LOGL_ERROR, "Failed to allocate.\n"); - talloc_free(new_number_pre); - talloc_free(new_number_post); - return NULL; - } - - /* copy the header */ - outptr = msgb_put(out, sizeof(*hdr48)); - memcpy(outptr, hdr48, sizeof(*hdr48)); - - /* copy everything up to the number */ - sec_len = TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 2 - &hdr48->data[0]; - outptr = msgb_put(out, sec_len); - memcpy(outptr, &hdr48->data[0], sec_len); - - /* create the new number */ - update_called_number(&called, chosen_number); - LOGP(DCC, LOGL_DEBUG, - "Chosen number for IMSI(%s) is Plan(%d) Type(%d) Number(%s)\n", - imsi, called.plan, called.type, called.number); - gsm48_encode_called(out, &called); - - /* copy thre rest */ - msgptr = TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) + - TLVP_LEN(&tp, GSM48_IE_CALLED_BCD); - sec_len = payload_len - (msgptr - &hdr48->data[0]); - outptr = msgb_put(out, sec_len); - memcpy(outptr, msgptr, sec_len); - - talloc_free(new_number_pre); - talloc_free(new_number_post); - return out; -} - -/** - * Find a new SMSC address, returns an allocated string that needs to be - * freed or is NULL. - */ -static char *find_new_smsc(struct bsc_nat *nat, void *ctx, const char *imsi, - const char *smsc_addr, const char *dest_nr) -{ - struct bsc_nat_num_rewr_entry *entry; - char *new_number = NULL; - uint8_t dest_match = llist_empty(&nat->tpdest_match); - - /* We will find a new number now */ - llist_for_each_entry(entry, &nat->smsc_rewr, list) { - regmatch_t matches[2]; - - /* check the IMSI match */ - if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0) - continue; - - /* this regexp matches... */ - if (regexec(&entry->num_reg, smsc_addr, 2, matches, 0) == 0 && - matches[1].rm_eo != -1) - new_number = talloc_asprintf(ctx, "%s%s", - entry->replace, - &smsc_addr[matches[1].rm_so]); - if (new_number) - break; - } - - if (!new_number) - return NULL; - - /* - * now match the number against another list - */ - llist_for_each_entry(entry, &nat->tpdest_match, list) { - /* check the IMSI match */ - if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0) - continue; - - if (regexec(&entry->num_reg, dest_nr, 0, NULL, 0) == 0) { - dest_match = 1; - break; - } - } - - if (!dest_match) { - talloc_free(new_number); - return NULL; - } - - return new_number; -} - -/** - * Clear the TP-SRR from the TPDU header - */ -static uint8_t sms_new_tpdu_hdr(struct bsc_nat *nat, const char *imsi, - const char *dest_nr, uint8_t hdr) -{ - struct bsc_nat_num_rewr_entry *entry; - - /* We will find a new number now */ - llist_for_each_entry(entry, &nat->sms_clear_tp_srr, list) { - /* check the IMSI match */ - if (regexec(&entry->msisdn_reg, imsi, 0, NULL, 0) != 0) - continue; - if (regexec(&entry->num_reg, dest_nr, 0, NULL, 0) != 0) - continue; - - /* matched phone number and imsi */ - return hdr & ~0x20; - } - - return hdr; -} - -/** - * Check if we need to rewrite the number. For this SMS. - */ -static char *sms_new_dest_nr(struct bsc_nat *nat, void *ctx, - const char *imsi, const char *dest_nr) -{ - return match_and_rewrite_number(ctx, dest_nr, imsi, - &nat->sms_num_rewr, NULL); -} - -/** - * This is a helper for GSM 04.11 8.2.5.2 Destination address element - */ -static bool sms_encode_addr_element(struct msgb *out, const char *new_number, - int format, int tp_data) -{ - int new_addr_len; - uint8_t new_addr[26]; - - /* - * Copy the new number. We let libosmocore encode it, then set - * the extension followed after the length. Depending on if - * we want to write RP we will let the TLV code add the - * length for us or we need to use strlen... This is not very clear - * as of 03.40 and 04.11. - */ - new_addr_len = gsm48_encode_bcd_number(new_addr, ARRAY_SIZE(new_addr), - 1, new_number); - if (new_addr_len < 0) - return false; - - new_addr[1] = format; - if (tp_data) { - uint8_t *data = msgb_put(out, new_addr_len); - memcpy(data, new_addr, new_addr_len); - data[0] = strlen(new_number); - } else { - msgb_lv_put(out, new_addr_len - 1, new_addr + 1); - } - - return true; -} - -static struct msgb *sms_create_new(uint8_t type, uint8_t ref, - struct gsm48_hdr *old_hdr48, - const uint8_t *orig_addr_ptr, - int orig_addr_len, const char *new_number, - const uint8_t *data_ptr, int data_len, - uint8_t tpdu_first_byte, - const int old_dest_len, const char *new_dest_nr) -{ - struct gsm48_hdr *new_hdr48; - struct msgb *out; - - /* - * We need to re-create the patched structure. This is why we have - * saved the above pointers. - */ - out = msgb_alloc_headroom(4096, 128, "changed-smsc"); - if (!out) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n"); - return NULL; - } - - out->l2h = out->data; - msgb_v_put(out, GSM411_MT_RP_DATA_MO); - msgb_v_put(out, ref); - msgb_lv_put(out, orig_addr_len, orig_addr_ptr); - - if (!sms_encode_addr_element(out, new_number, 0x91, 0)) { - LOGP(DNAT, LOGL_ERROR, "Failed to encode SMS address.\n"); - return NULL; - } - - - /* Patch the TPDU from here on */ - - /** - * Do we need to put a new TP-Destination-Address (TP-DA) here or - * can we copy the old thing? For the TP-DA we need to find out the - * new size. - */ - if (new_dest_nr) { - uint8_t *data, *new_size; - - /* reserve the size and write the header */ - new_size = msgb_put(out, 1); - out->l3h = new_size + 1; - msgb_v_put(out, tpdu_first_byte); - msgb_v_put(out, data_ptr[1]); - - /* encode the new number and put it */ - if (strncmp(new_dest_nr, "00", 2) == 0) { - if (!sms_encode_addr_element(out, new_dest_nr + 2, 0x91, 1)) { - LOGP(DNAT, LOGL_ERROR, "Failed to encode SMS address.\n"); - return NULL; - } - } else { - if (!sms_encode_addr_element(out, new_dest_nr, 0x81, 1)) { - LOGP(DNAT, LOGL_ERROR, "Failed to encode SMS address.\n"); - return NULL; - } - } - /* Copy the rest after the TP-DS */ - data = msgb_put(out, data_len - 2 - 1 - old_dest_len); - memcpy(data, &data_ptr[2 + 1 + old_dest_len], data_len - 2 - 1 - old_dest_len); - - /* fill in the new size */ - new_size[0] = msgb_l3len(out); - } else { - msgb_v_put(out, data_len); - msgb_tv_fixed_put(out, tpdu_first_byte, data_len - 1, &data_ptr[1]); - } - - /* prepend GSM 04.08 header */ - new_hdr48 = (struct gsm48_hdr *) msgb_push(out, sizeof(*new_hdr48) + 1); - memcpy(new_hdr48, old_hdr48, sizeof(*old_hdr48)); - new_hdr48->data[0] = msgb_l2len(out); - - return out; -} - -/** - * Parse the SMS and check if it needs to be rewritten - */ -static struct msgb *rewrite_sms(struct bsc_nat *nat, struct msgb *msg, - struct bsc_nat_parsed *parsed, const char *imsi, - struct gsm48_hdr *hdr48, const uint32_t len) -{ - unsigned int payload_len; - unsigned int cp_len; - - uint8_t ref; - uint8_t orig_addr_len, *orig_addr_ptr; - uint8_t dest_addr_len, *dest_addr_ptr; - uint8_t data_len, *data_ptr; - char smsc_addr[30]; - - - uint8_t dest_len, orig_dest_len; - char _dest_nr[30]; - char *dest_nr; - char *new_dest_nr; - - char *new_number = NULL; - uint8_t tpdu_hdr; - struct msgb *out; - - payload_len = len - sizeof(*hdr48); - if (payload_len < 1) { - LOGP(DNAT, LOGL_ERROR, "SMS too short for things. %d\n", payload_len); - return NULL; - } - - cp_len = hdr48->data[0]; - if (payload_len + 1 < cp_len) { - LOGP(DNAT, LOGL_ERROR, "SMS RPDU can not fit in: %d %d\n", cp_len, payload_len); - return NULL; - } - - if (hdr48->data[1] != GSM411_MT_RP_DATA_MO) - return NULL; - - if (cp_len < 5) { - LOGP(DNAT, LOGL_ERROR, "RD-DATA can not fit in the CP len: %d\n", cp_len); - return NULL; - } - - /* RP */ - ref = hdr48->data[2]; - orig_addr_len = hdr48->data[3]; - orig_addr_ptr = &hdr48->data[4]; - - /* the +1 is for checking if the following element has some space */ - if (cp_len < 3 + orig_addr_len + 1) { - LOGP(DNAT, LOGL_ERROR, "RP-Originator addr does not fit: %d\n", orig_addr_len); - return NULL; - } - - dest_addr_len = hdr48->data[3 + orig_addr_len + 1]; - dest_addr_ptr = &hdr48->data[3 + orig_addr_len + 2]; - - if (cp_len < 3 + orig_addr_len + 1 + dest_addr_len + 1) { - LOGP(DNAT, LOGL_ERROR, "RP-Destination addr does not fit: %d\n", dest_addr_len); - return NULL; - } - gsm48_decode_bcd_number(smsc_addr, ARRAY_SIZE(smsc_addr), dest_addr_ptr - 1, 1); - - data_len = hdr48->data[3 + orig_addr_len + 1 + dest_addr_len + 1]; - data_ptr = &hdr48->data[3 + orig_addr_len + 1 + dest_addr_len + 2]; - - if (cp_len < 3 + orig_addr_len + 1 + dest_addr_len + 1 + data_len) { - LOGP(DNAT, LOGL_ERROR, "RP-Data does not fit: %d\n", data_len); - return NULL; - } - - if (data_len < 3) { - LOGP(DNAT, LOGL_ERROR, "SMS-SUBMIT is too short.\n"); - return NULL; - } - - /* TP-PDU starts here */ - if ((data_ptr[0] & 0x03) != GSM340_SMS_SUBMIT_MS2SC) - return NULL; - - /* - * look into the phone number. The length is in semi-octets, we will - * need to add the byte for the number type as well. - */ - orig_dest_len = data_ptr[2]; - dest_len = ((orig_dest_len + 1) / 2) + 1; - if (data_len < dest_len + 3 || dest_len < 2) { - LOGP(DNAT, LOGL_ERROR, "SMS-SUBMIT can not have TP-DestAddr.\n"); - return NULL; - } - - if ((data_ptr[3] & 0x80) == 0) { - LOGP(DNAT, LOGL_ERROR, "TP-DestAddr has extension. Not handled.\n"); - return NULL; - } - - if ((data_ptr[3] & 0x0F) == 0) { - LOGP(DNAT, LOGL_ERROR, "TP-DestAddr is of unknown type.\n"); - return NULL; - } - - /** - * Besides of what I think I read in GSM 03.40 and 04.11 the TP-DA - * contains the semi-octets as length (strlen), change it to the - * the number of bytes, but then change it back. - */ - data_ptr[2] = dest_len; - gsm48_decode_bcd_number(_dest_nr + 2, ARRAY_SIZE(_dest_nr) - 2, - &data_ptr[2], 1); - data_ptr[2] = orig_dest_len; - if ((data_ptr[3] & 0x70) == 0x10) { - _dest_nr[0] = _dest_nr[1] = '0'; - dest_nr = &_dest_nr[0]; - } else { - dest_nr = &_dest_nr[2]; - } - - /** - * Call functions to rewrite the data - */ - tpdu_hdr = sms_new_tpdu_hdr(nat, imsi, dest_nr, data_ptr[0]); - new_number = find_new_smsc(nat, msg, imsi, smsc_addr, dest_nr); - new_dest_nr = sms_new_dest_nr(nat, msg, imsi, dest_nr); - - if (tpdu_hdr == data_ptr[0] && !new_number && !new_dest_nr) - return NULL; - - out = sms_create_new(GSM411_MT_RP_DATA_MO, ref, hdr48, - orig_addr_ptr, orig_addr_len, - new_number ? new_number : smsc_addr, - data_ptr, data_len, tpdu_hdr, - dest_len, new_dest_nr); - talloc_free(new_number); - talloc_free(new_dest_nr); - return out; -} - -struct msgb *bsc_nat_rewrite_msg(struct bsc_nat *nat, struct msgb *msg, struct bsc_nat_parsed *parsed, const char *imsi) -{ - struct gsm48_hdr *hdr48; - uint32_t len; - uint8_t msg_type, proto; - struct msgb *new_msg = NULL, *sccp; - uint8_t link_id; - - if (!imsi || strlen(imsi) < 5) - return msg; - - /* only care about DTAP messages */ - if (parsed->bssap != BSSAP_MSG_DTAP) - return msg; - if (!parsed->dest_local_ref) - return msg; - - hdr48 = bsc_unpack_dtap(parsed, msg, &len); - if (!hdr48) - return msg; - - link_id = msg->l3h[1]; - proto = gsm48_hdr_pdisc(hdr48); - msg_type = gsm48_hdr_msg_type(hdr48); - - if (proto == GSM48_PDISC_CC && msg_type == GSM48_MT_CC_SETUP) - new_msg = rewrite_setup(nat, msg, parsed, imsi, hdr48, len); - else if (proto == GSM48_PDISC_SMS && msg_type == GSM411_MT_CP_DATA) - new_msg = rewrite_sms(nat, msg, parsed, imsi, hdr48, len); - - if (!new_msg) - return msg; - - /* wrap with DTAP, SCCP, then IPA. TODO: Stop copying */ - gsm0808_prepend_dtap_header(new_msg, link_id); - sccp = sccp_create_dt1(parsed->dest_local_ref, new_msg->data, new_msg->len); - talloc_free(new_msg); - - if (!sccp) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n"); - return msg; - } - - ipa_prepend_header(sccp, IPAC_PROTO_SCCP); - - /* the parsed hangs off from msg but it needs to survive */ - talloc_steal(sccp, parsed); - msgb_free(msg); - return sccp; -} - -static void num_rewr_free_data(struct bsc_nat_num_rewr_entry *entry) -{ - regfree(&entry->msisdn_reg); - regfree(&entry->num_reg); - talloc_free(entry->replace); -} - -void bsc_nat_num_rewr_entry_adapt(void *ctx, struct llist_head *head, - const struct osmo_config_list *list) -{ - struct bsc_nat_num_rewr_entry *entry, *tmp; - struct osmo_config_entry *cfg_entry; - - /* free the old data */ - llist_for_each_entry_safe(entry, tmp, head, list) { - num_rewr_free_data(entry); - llist_del(&entry->list); - talloc_free(entry); - } - - - if (!list) - return; - - llist_for_each_entry(cfg_entry, &list->entry, list) { - char *regexp; - if (cfg_entry->text[0] == '+') { - LOGP(DNAT, LOGL_ERROR, - "Plus is not allowed in the number\n"); - continue; - } - - entry = talloc_zero(ctx, struct bsc_nat_num_rewr_entry); - if (!entry) { - LOGP(DNAT, LOGL_ERROR, - "Allocation of the num_rewr entry failed.\n"); - continue; - } - - entry->replace = talloc_strdup(entry, cfg_entry->text); - if (!entry->replace) { - LOGP(DNAT, LOGL_ERROR, - "Failed to copy the replacement text.\n"); - talloc_free(entry); - continue; - } - - if (strcmp("prefix_lookup", entry->replace) == 0) - entry->is_prefix_lookup = 1; - - /* we will now build a regexp string */ - if (cfg_entry->mcc[0] == '^') { - regexp = talloc_strdup(entry, cfg_entry->mcc); - } else { - regexp = talloc_asprintf(entry, "^%s%s", - cfg_entry->mcc[0] == '*' ? - "[0-9][0-9][0-9]" : cfg_entry->mcc, - cfg_entry->mnc[0] == '*' ? - "[0-9][0-9]" : cfg_entry->mnc); - } - - if (!regexp) { - LOGP(DNAT, LOGL_ERROR, "Failed to create a regexp string.\n"); - talloc_free(entry); - continue; - } - - if (regcomp(&entry->msisdn_reg, regexp, 0) != 0) { - LOGP(DNAT, LOGL_ERROR, - "Failed to compile regexp '%s'\n", regexp); - talloc_free(regexp); - talloc_free(entry); - continue; - } - - talloc_free(regexp); - if (regcomp(&entry->num_reg, cfg_entry->option, REG_EXTENDED) != 0) { - LOGP(DNAT, LOGL_ERROR, - "Failed to compile regexp '%s'\n", cfg_entry->option); - regfree(&entry->msisdn_reg); - talloc_free(entry); - continue; - } - - /* we have copied the number */ - llist_add_tail(&entry->list, head); - } -} diff --git a/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c b/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c deleted file mode 100644 index af346eff7..000000000 --- a/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c +++ /dev/null @@ -1,259 +0,0 @@ -/* Handling for loading a re-write file/database */ -/* - * (C) 2013 by On-Waves - * (C) 2013 by Holger Hans Peter Freyther <zecke@selfish.org> - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <osmocom/bsc/nat_rewrite_trie.h> -#include <osmocom/bsc/debug.h> -#include <osmocom/bsc/vty.h> - -#include <osmocom/core/talloc.h> -#include <osmocom/core/utils.h> - -#include <assert.h> -#include <stdio.h> -#include <string.h> -#include <ctype.h> - -#define CHECK_IS_DIGIT_OR_FAIL(prefix, pos) \ - if (!isdigit(prefix[pos]) && prefix[pos] != '+') { \ - LOGP(DNAT, LOGL_ERROR, \ - "Prefix(%s) contains non ascii text at(%d=%c)\n", \ - prefix, pos, prefix[pos]); \ - goto fail; \ - } -#define TO_INT(c) \ - ((c) == '+' ? 10 : ((c - '0') % 10)) - -static void insert_rewrite_node(struct nat_rewrite_rule *rule, struct nat_rewrite *root) -{ - struct nat_rewrite_rule *new = &root->rule; - - const int len = strlen(rule->prefix); - int i; - - if (len <= 0) { - LOGP(DNAT, LOGL_ERROR, "An empty prefix does not make sense.\n"); - goto fail; - } - - for (i = 0; i < len - 1; ++i) { - int pos; - - /* check if the input is valid */ - CHECK_IS_DIGIT_OR_FAIL(rule->prefix, i); - - /* check if the next node is already valid */ - pos = TO_INT(rule->prefix[i]); - if (!new->rules[pos]) { - new->rules[pos] = talloc_zero(root, struct nat_rewrite_rule); - if (!new->rules[pos]) { - LOGP(DNAT, LOGL_ERROR, - "Failed to allocate memory.\n"); - goto fail; - } - - new->rules[pos]->empty = 1; - } - - /* we continue here */ - new = new->rules[pos]; - } - - /* new now points to the place where we want to add it */ - int pos; - - /* check if the input is valid */ - CHECK_IS_DIGIT_OR_FAIL(rule->prefix, (len - 1)); - - /* check if the next node is already valid */ - pos = TO_INT(rule->prefix[len - 1]); - if (!new->rules[pos]) - new->rules[pos] = rule; - else if (new->rules[pos]->empty) { - /* copy over entries */ - new->rules[pos]->empty = 0; - memcpy(new->rules[pos]->prefix, rule->prefix, sizeof(rule->prefix)); - memcpy(new->rules[pos]->rewrite, rule->rewrite, sizeof(rule->rewrite)); - talloc_free(rule); - } else { - LOGP(DNAT, LOGL_ERROR, - "Prefix(%s) is already installed\n", rule->prefix); - goto fail; - } - - root->prefixes += 1; - return; - -fail: - talloc_free(rule); - return; -} - -static void handle_line(struct nat_rewrite *rewrite, char *line) -{ - char *split; - struct nat_rewrite_rule *rule; - size_t size_prefix, size_end, len; - - - /* Find the ',' in the line */ - len = strlen(line); - split = strstr(line, ","); - if (!split) { - LOGP(DNAT, LOGL_ERROR, "Line doesn't contain ','\n"); - return; - } - - /* Check if there is space for the rewrite rule */ - size_prefix = split - line; - if (len - size_prefix <= 2) { - LOGP(DNAT, LOGL_ERROR, "No rewrite available.\n"); - return; - } - - /* Continue after the ',' to the end */ - split = &line[size_prefix + 1]; - size_end = strlen(split) - 1; - - /* Check if both strings can fit into the static array */ - if (size_prefix > sizeof(rule->prefix) - 1) { - LOGP(DNAT, LOGL_ERROR, - "Prefix is too long with %zu\n", size_prefix); - return; - } - - if (size_end > sizeof(rule->rewrite) - 1) { - LOGP(DNAT, LOGL_ERROR, - "Rewrite is too long with %zu on %s\n", - size_end, &line[size_prefix + 1]); - return; - } - - /* Now create the entry and insert it into the trie */ - rule = talloc_zero(rewrite, struct nat_rewrite_rule); - if (!rule) { - LOGP(DNAT, LOGL_ERROR, "Can not allocate memory\n"); - return; - } - - memcpy(rule->prefix, line, size_prefix); - assert(size_prefix < sizeof(rule->prefix)); - rule->prefix[size_prefix] = '\0'; - - memcpy(rule->rewrite, split, size_end); - assert(size_end < sizeof(rule->rewrite)); - rule->rewrite[size_end] = '\0'; - - /* now insert and balance the tree */ - insert_rewrite_node(rule, rewrite); -} - -struct nat_rewrite *nat_rewrite_parse(void *ctx, const char *filename) -{ - FILE *file; - char *line = NULL; - size_t n = 0; - struct nat_rewrite *res; - - file = fopen(filename, "r"); - if (!file) - return NULL; - - res = talloc_zero(ctx, struct nat_rewrite); - if (!res) { - fclose(file); - return NULL; - } - - /* mark the root as empty */ - res->rule.empty = 1; - - while (getline(&line, &n, file) != -1) { - handle_line(res, line); - } - - free(line); - fclose(file); - return res; -} - -/** - * Simple find that tries to do a longest match... - */ -struct nat_rewrite_rule *nat_rewrite_lookup(struct nat_rewrite *rewrite, - const char *prefix) -{ - struct nat_rewrite_rule *rule = &rewrite->rule; - struct nat_rewrite_rule *last = NULL; - const int len = OSMO_MIN(strlen(prefix), (sizeof(rule->prefix) - 1)); - int i; - - for (i = 0; rule && i < len; ++i) { - int pos; - - CHECK_IS_DIGIT_OR_FAIL(prefix, i); - pos = TO_INT(prefix[i]); - - rule = rule->rules[pos]; - if (rule && !rule->empty) - last = rule; - } - - return last; - -fail: - return NULL; -} - -static void nat_rewrite_dump_rec(struct nat_rewrite_rule *rule) -{ - int i; - if (!rule->empty) - printf("%s,%s\n", rule->prefix, rule->rewrite); - - for (i = 0; i < ARRAY_SIZE(rule->rules); ++i) { - if (!rule->rules[i]) - continue; - nat_rewrite_dump_rec(rule->rules[i]); - } -} - -void nat_rewrite_dump(struct nat_rewrite *rewrite) -{ - nat_rewrite_dump_rec(&rewrite->rule); -} - -static void nat_rewrite_dump_rec_vty(struct vty *vty, struct nat_rewrite_rule *rule) -{ - int i; - if (!rule->empty) - vty_out(vty, "%s,%s%s", rule->prefix, rule->rewrite, VTY_NEWLINE); - - for (i = 0; i < ARRAY_SIZE(rule->rules); ++i) { - if (!rule->rules[i]) - continue; - nat_rewrite_dump_rec_vty(vty, rule->rules[i]); - } -} - -void nat_rewrite_dump_vty(struct vty *vty, struct nat_rewrite *rewrite) -{ - nat_rewrite_dump_rec_vty(vty, &rewrite->rule); -} diff --git a/src/osmo-bsc_nat/bsc_nat_utils.c b/src/osmo-bsc_nat/bsc_nat_utils.c deleted file mode 100644 index 3094bbd6e..000000000 --- a/src/osmo-bsc_nat/bsc_nat_utils.c +++ /dev/null @@ -1,535 +0,0 @@ - -/* BSC Multiplexer/NAT Utilities */ - -/* - * (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010-2011 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_nat_sccp.h> -#include <osmocom/bsc/bsc_msg_filter.h> -#include <osmocom/bsc/bsc_msc.h> -#include <osmocom/bsc/gsm_data.h> -#include <osmocom/bsc/debug.h> -#include <osmocom/bsc/ipaccess.h> -#include <osmocom/bsc/vty.h> - -#include <osmocom/core/linuxlist.h> -#include <osmocom/core/talloc.h> -#include <osmocom/core/stats.h> -#include <osmocom/gsm/gsm0808.h> -#include <osmocom/gsm/ipa.h> - -#include <osmocom/gsm/protocol/gsm_08_08.h> -#include <osmocom/gsm/protocol/gsm_04_11.h> - -#include <osmocom/sccp/sccp.h> - -#include <netinet/in.h> -#include <arpa/inet.h> -#include <unistd.h> - -static const struct rate_ctr_desc bsc_cfg_ctr_description[] = { - [BCFG_CTR_SCCP_CONN] = { "sccp.conn", "SCCP Connections "}, - [BCFG_CTR_SCCP_CALLS] = { "sccp.calls", "SCCP Assignment Commands "}, - [BCFG_CTR_NET_RECONN] = { "net.reconnects", "Network reconnects "}, - [BCFG_CTR_DROPPED_SCCP] = { "dropped.sccp", "Dropped SCCP connections."}, - [BCFG_CTR_DROPPED_CALLS] = { "dropped.calls", "Dropped active calls. "}, - [BCFG_CTR_REJECTED_CR] = { "rejected.cr", "Rejected CR due filter "}, - [BCFG_CTR_REJECTED_MSG] = { "rejected.msg", "Rejected MSG due filter "}, - [BCFG_CTR_ILL_PACKET] = { "rejected.ill", "Rejected due parse error "}, - [BCFG_CTR_CON_TYPE_LU] = { "conn.lu", "Conn Location Update "}, - [BCFG_CTR_CON_CMSERV_RQ] = { "conn.rq", "Conn CM Service Req "}, - [BCFG_CTR_CON_PAG_RESP] = { "conn.pag", "Conn Paging Response "}, - [BCFG_CTR_CON_SSA] = { "conn.ssa", "Conn USSD "}, - [BCFG_CTR_CON_OTHER] = { "conn.other", "Conn Other "}, -}; - -static const struct rate_ctr_group_desc bsc_cfg_ctrg_desc = { - .group_name_prefix = "nat.bsc", - .group_description = "NAT BSC Statistics", - .num_ctr = ARRAY_SIZE(bsc_cfg_ctr_description), - .ctr_desc = bsc_cfg_ctr_description, - .class_id = OSMO_STATS_CLASS_PEER, -}; - -struct bsc_nat *bsc_nat_alloc(void) -{ - struct bsc_nat *nat = talloc_zero(tall_bsc_ctx, struct bsc_nat); - if (!nat) - return NULL; - - nat->main_dest = talloc_zero(nat, struct bsc_msc_dest); - if (!nat->main_dest) { - talloc_free(nat); - return NULL; - } - - INIT_LLIST_HEAD(&nat->sccp_connections); - INIT_LLIST_HEAD(&nat->bsc_connections); - INIT_LLIST_HEAD(&nat->paging_groups); - INIT_LLIST_HEAD(&nat->bsc_configs); - INIT_LLIST_HEAD(&nat->access_lists); - INIT_LLIST_HEAD(&nat->dests); - INIT_LLIST_HEAD(&nat->num_rewr); - INIT_LLIST_HEAD(&nat->num_rewr_post); - INIT_LLIST_HEAD(&nat->smsc_rewr); - INIT_LLIST_HEAD(&nat->tpdest_match); - INIT_LLIST_HEAD(&nat->sms_clear_tp_srr); - INIT_LLIST_HEAD(&nat->sms_num_rewr); - - nat->stats.sccp.conn = osmo_counter_alloc("nat.sccp.conn"); - nat->stats.sccp.calls = osmo_counter_alloc("nat.sccp.calls"); - nat->stats.bsc.reconn = osmo_counter_alloc("nat.bsc.conn"); - nat->stats.bsc.auth_fail = osmo_counter_alloc("nat.bsc.auth_fail"); - nat->stats.msc.reconn = osmo_counter_alloc("nat.msc.conn"); - nat->stats.ussd.reconn = osmo_counter_alloc("nat.ussd.conn"); - nat->auth_timeout = 2; - nat->ping_timeout = 20; - nat->pong_timeout = 5; - - llist_add(&nat->main_dest->list, &nat->dests); - nat->main_dest->ip = talloc_strdup(nat, "127.0.0.1"); - nat->main_dest->port = 5000; - - return nat; -} - -void bsc_nat_free(struct bsc_nat *nat) -{ - struct bsc_config *cfg, *tmp; - struct bsc_msg_acc_lst *lst, *tmp_lst; - - llist_for_each_entry_safe(cfg, tmp, &nat->bsc_configs, entry) - bsc_config_free(cfg); - llist_for_each_entry_safe(lst, tmp_lst, &nat->access_lists, list) - bsc_msg_acc_lst_delete(lst); - - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr_post, NULL); - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_clear_tp_srr, NULL); - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_num_rewr, NULL); - bsc_nat_num_rewr_entry_adapt(nat, &nat->tpdest_match, NULL); - - osmo_counter_free(nat->stats.sccp.conn); - osmo_counter_free(nat->stats.sccp.calls); - osmo_counter_free(nat->stats.bsc.reconn); - osmo_counter_free(nat->stats.bsc.auth_fail); - osmo_counter_free(nat->stats.msc.reconn); - osmo_counter_free(nat->stats.ussd.reconn); - talloc_free(nat->mgcp_cfg); - talloc_free(nat); -} - -void bsc_nat_set_msc_ip(struct bsc_nat *nat, const char *ip) -{ - osmo_talloc_replace_string(nat, &nat->main_dest->ip, ip); -} - -struct bsc_connection *bsc_connection_alloc(struct bsc_nat *nat) -{ - struct bsc_connection *con = talloc_zero(nat, struct bsc_connection); - if (!con) - return NULL; - - con->nat = nat; - osmo_wqueue_init(&con->write_queue, 100); - INIT_LLIST_HEAD(&con->cmd_pending); - INIT_LLIST_HEAD(&con->pending_dlcx); - return con; -} - -struct bsc_config *bsc_config_alloc(struct bsc_nat *nat, const char *token, - unsigned int number) -{ - struct bsc_config *conf = talloc_zero(nat, struct bsc_config); - if (!conf) - return NULL; - - conf->token = talloc_strdup(conf, token); - conf->nr = number; - conf->nat = nat; - conf->max_endpoints = 32; - conf->paging_group = PAGIN_GROUP_UNASSIGNED; - - INIT_LLIST_HEAD(&conf->lac_list); - - llist_add_tail(&conf->entry, &nat->bsc_configs); - ++nat->num_bsc; - - conf->stats.ctrg = rate_ctr_group_alloc(conf, &bsc_cfg_ctrg_desc, conf->nr); - if (!conf->stats.ctrg) { - llist_del(&conf->entry); - talloc_free(conf); - return NULL; - } - - return conf; -} - -struct bsc_config *bsc_config_by_token(struct bsc_nat *nat, const char *token, int len) -{ - struct bsc_config *conf; - - llist_for_each_entry(conf, &nat->bsc_configs, entry) { - /* - * Add the '\0' of the token for the memcmp, the IPA messages - * for some reason added null termination. - */ - const int token_len = strlen(conf->token) + 1; - - if (token_len == len && memcmp(conf->token, token, token_len) == 0) - return conf; - } - - return NULL; -} - -void bsc_config_free(struct bsc_config *cfg) -{ - llist_del(&cfg->entry); - rate_ctr_group_free(cfg->stats.ctrg); - cfg->nat->num_bsc--; - OSMO_ASSERT(cfg->nat->num_bsc >= 0); - talloc_free(cfg); -} - -static void _add_lac(void *ctx, struct llist_head *list, int _lac) -{ - struct bsc_lac_entry *lac; - - llist_for_each_entry(lac, list, entry) - if (lac->lac == _lac) - return; - - lac = talloc_zero(ctx, struct bsc_lac_entry); - if (!lac) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate.\n"); - return; - } - - lac->lac = _lac; - llist_add_tail(&lac->entry, list); -} - -static void _del_lac(struct llist_head *list, int _lac) -{ - struct bsc_lac_entry *lac; - - llist_for_each_entry(lac, list, entry) - if (lac->lac == _lac) { - llist_del(&lac->entry); - talloc_free(lac); - return; - } -} - -void bsc_config_add_lac(struct bsc_config *cfg, int _lac) -{ - _add_lac(cfg, &cfg->lac_list, _lac); -} - -void bsc_config_del_lac(struct bsc_config *cfg, int _lac) -{ - _del_lac(&cfg->lac_list, _lac); -} - -struct bsc_nat_paging_group *bsc_nat_paging_group_create(struct bsc_nat *nat, int group) -{ - struct bsc_nat_paging_group *pgroup; - - pgroup = talloc_zero(nat, struct bsc_nat_paging_group); - if (!pgroup) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate a paging group.\n"); - return NULL; - } - - pgroup->nr = group; - INIT_LLIST_HEAD(&pgroup->lists); - llist_add_tail(&pgroup->entry, &nat->paging_groups); - return pgroup; -} - -void bsc_nat_paging_group_delete(struct bsc_nat_paging_group *pgroup) -{ - llist_del(&pgroup->entry); - talloc_free(pgroup); -} - -struct bsc_nat_paging_group *bsc_nat_paging_group_num(struct bsc_nat *nat, int group) -{ - struct bsc_nat_paging_group *pgroup; - - llist_for_each_entry(pgroup, &nat->paging_groups, entry) - if (pgroup->nr == group) - return pgroup; - - return NULL; -} - -void bsc_nat_paging_group_add_lac(struct bsc_nat_paging_group *pgroup, int lac) -{ - _add_lac(pgroup, &pgroup->lists, lac); -} - -void bsc_nat_paging_group_del_lac(struct bsc_nat_paging_group *pgroup, int lac) -{ - _del_lac(&pgroup->lists, lac); -} - -int bsc_config_handles_lac(struct bsc_config *cfg, int lac_nr) -{ - struct bsc_nat_paging_group *pgroup; - struct bsc_lac_entry *entry; - - llist_for_each_entry(entry, &cfg->lac_list, entry) - if (entry->lac == lac_nr) - return 1; - - /* now lookup the paging group */ - pgroup = bsc_nat_paging_group_num(cfg->nat, cfg->paging_group); - if (!pgroup) - return 0; - - llist_for_each_entry(entry, &pgroup->lists, entry) - if (entry->lac == lac_nr) - return 1; - - return 0; -} - -void sccp_connection_destroy(struct nat_sccp_connection *conn) -{ - LOGP(DNAT, LOGL_DEBUG, "Destroy 0x%x <-> 0x%x mapping for con %p\n", - sccp_src_ref_to_int(&conn->real_ref), - sccp_src_ref_to_int(&conn->patched_ref), conn->bsc); - bsc_mgcp_dlcx(conn); - llist_del(&conn->list_entry); - talloc_free(conn); -} - - -int bsc_nat_find_paging(struct msgb *msg, - const uint8_t **out_data, int *out_leng) -{ - int data_length; - const uint8_t *data; - struct tlv_parsed tp; - - if (!msg->l3h || msgb_l3len(msg) < 3) { - LOGP(DNAT, LOGL_ERROR, "Paging message is too short.\n"); - return -1; - } - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0); - if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST)) { - LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n"); - return -2; - } - - data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST); - data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER_LIST); - - /* No need to try a different BSS */ - if (data[0] == CELL_IDENT_BSS) { - return -3; - } else if (data[0] != CELL_IDENT_LAC) { - LOGP(DNAT, LOGL_ERROR, "Unhandled cell ident discrminator: %d\n", data[0]); - return -4; - } - - *out_data = &data[1]; - *out_leng = data_length - 1; - return 0; -} - -int bsc_write_mgcp(struct bsc_connection *bsc, const uint8_t *data, unsigned int length) -{ - struct msgb *msg; - - if (length > 4096 - 128) { - LOGP(DLINP, LOGL_ERROR, "Can not send message of that size.\n"); - return -1; - } - - msg = msgb_alloc_headroom(4096, 128, "to-bsc"); - if (!msg) { - LOGP(DLINP, LOGL_ERROR, "Failed to allocate memory for BSC msg.\n"); - return -1; - } - - /* copy the data */ - msg->l3h = msgb_put(msg, length); - memcpy(msg->l3h, data, length); - - return bsc_write(bsc, msg, IPAC_PROTO_MGCP_OLD); -} - -int bsc_write(struct bsc_connection *bsc, struct msgb *msg, int proto) -{ - return bsc_do_write(&bsc->write_queue, msg, proto); -} - -int bsc_do_write(struct osmo_wqueue *queue, struct msgb *msg, int proto) -{ - /* prepend the header */ - ipa_prepend_header(msg, proto); - return bsc_write_msg(queue, msg); -} - -int bsc_write_msg(struct osmo_wqueue *queue, struct msgb *msg) -{ - if (osmo_wqueue_enqueue(queue, msg) != 0) { - LOGP(DLINP, LOGL_ERROR, "Failed to enqueue the write.\n"); - msgb_free(msg); - return -1; - } - - return 0; -} - -struct gsm48_hdr *bsc_unpack_dtap(struct bsc_nat_parsed *parsed, - struct msgb *msg, uint32_t *len) -{ - /* gsm_type is actually the size of the dtap */ - *len = parsed->gsm_type; - if (*len < msgb_l3len(msg) - 3) { - LOGP(DNAT, LOGL_ERROR, "Not enough space for DTAP.\n"); - return NULL; - } - - if (msgb_l3len(msg) - 3 < msg->l3h[2]) { - LOGP(DNAT, LOGL_ERROR, - "GSM48 payload does not fit: %d %d\n", - msg->l3h[2], msgb_l3len(msg) - 3); - return NULL; - } - - msg->l4h = &msg->l3h[3]; - return (struct gsm48_hdr *) msg->l4h; -} - -static const char *con_types [] = { - [FLT_CON_TYPE_NONE] = "n/a", - [FLT_CON_TYPE_LU] = "Location Update", - [FLT_CON_TYPE_CM_SERV_REQ] = "CM Serv Req", - [FLT_CON_TYPE_PAG_RESP] = "Paging Response", - [FLT_CON_TYPE_SSA] = "Supplementar Service Activation", - [FLT_CON_TYPE_LOCAL_REJECT] = "Local Reject", - [FLT_CON_TYPE_OTHER] = "Other", -}; - -const char *bsc_con_type_to_string(int type) -{ - return con_types[type]; -} - -int bsc_nat_msc_is_connected(struct bsc_nat *nat) -{ - return nat->msc_con->is_connected; -} - -static const int con_to_ctr[] = { - [FLT_CON_TYPE_NONE] = -1, - [FLT_CON_TYPE_LU] = BCFG_CTR_CON_TYPE_LU, - [FLT_CON_TYPE_CM_SERV_REQ] = BCFG_CTR_CON_CMSERV_RQ, - [FLT_CON_TYPE_PAG_RESP] = BCFG_CTR_CON_PAG_RESP, - [FLT_CON_TYPE_SSA] = BCFG_CTR_CON_SSA, - [FLT_CON_TYPE_LOCAL_REJECT] = -1, - [FLT_CON_TYPE_OTHER] = BCFG_CTR_CON_OTHER, -}; - -int bsc_conn_type_to_ctr(struct nat_sccp_connection *conn) -{ - return con_to_ctr[conn->filter_state.con_type]; -} - -int bsc_write_cb(struct osmo_fd *bfd, struct msgb *msg) -{ - int rc; - - rc = write(bfd->fd, msg->data, msg->len); - if (rc != msg->len) - LOGP(DNAT, LOGL_ERROR, "Failed to write message to the BSC.\n"); - - return rc; -} - -static void extract_lac(const uint8_t *data, uint16_t *lac, uint16_t *ci) -{ - memcpy(lac, &data[0], sizeof(*lac)); - memcpy(ci, &data[2], sizeof(*ci)); - - *lac = ntohs(*lac); - *ci = ntohs(*ci); -} - -int bsc_nat_extract_lac(struct bsc_connection *bsc, - struct nat_sccp_connection *con, - struct bsc_nat_parsed *parsed, struct msgb *msg) -{ - int data_length; - const uint8_t *data; - struct tlv_parsed tp; - uint16_t lac, ci; - - if (parsed->gsm_type != BSS_MAP_MSG_COMPLETE_LAYER_3) { - LOGP(DNAT, LOGL_ERROR, "Can only extract LAC from Complete Layer3\n"); - return -1; - } - - if (!msg->l3h || msgb_l3len(msg) < 3) { - LOGP(DNAT, LOGL_ERROR, "Complete Layer3 mssage is too short.\n"); - return -1; - } - - tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l3h + 3, msgb_l3len(msg) - 3, 0, 0); - if (!TLVP_PRESENT(&tp, GSM0808_IE_CELL_IDENTIFIER)) { - LOGP(DNAT, LOGL_ERROR, "No CellIdentifier List inside paging msg.\n"); - return -2; - } - - data_length = TLVP_LEN(&tp, GSM0808_IE_CELL_IDENTIFIER); - data = TLVP_VAL(&tp, GSM0808_IE_CELL_IDENTIFIER); - - /* Attemt to get the LAC/CI from it */ - if (data[0] == CELL_IDENT_WHOLE_GLOBAL) { - if (data_length != 8) { - LOGP(DNAT, LOGL_ERROR, - "Ident too short: %d\n", data_length); - return -3; - } - extract_lac(&data[1 + 3], &lac, &ci); - } else if (data[0] == CELL_IDENT_LAC_AND_CI) { - if (data_length != 5) { - LOGP(DNAT, LOGL_ERROR, - "Ident too short: %d\n", data_length); - return -3; - } - extract_lac(&data[1], &lac, &ci); - } else { - LOGP(DNAT, LOGL_ERROR, - "Unhandled cell identifier: %d\n", data[0]); - return -1; - } - - con->lac = lac; - con->ci = ci; - return 0; -} diff --git a/src/osmo-bsc_nat/bsc_nat_vty.c b/src/osmo-bsc_nat/bsc_nat_vty.c deleted file mode 100644 index 5d8d0c79d..000000000 --- a/src/osmo-bsc_nat/bsc_nat_vty.c +++ /dev/null @@ -1,1408 +0,0 @@ -/* OpenBSC NAT interface to quagga VTY */ -/* (C) 2010-2015 by Holger Hans Peter Freyther - * (C) 2010-2015 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <osmocom/bsc/vty.h> -#include <osmocom/bsc/gsm_data.h> -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_nat_sccp.h> -#include <osmocom/bsc/bsc_msg_filter.h> -#include <osmocom/bsc/bsc_msc.h> -#include <osmocom/legacy_mgcp/mgcp.h> -#include <osmocom/bsc/vty.h> -#include <osmocom/bsc/nat_rewrite_trie.h> -#include <osmocom/bsc/debug.h> - -#include <osmocom/core/talloc.h> -#include <osmocom/core/rate_ctr.h> -#include <osmocom/core/utils.h> -#include <osmocom/vty/logging.h> -#include <osmocom/vty/misc.h> -#include <osmocom/bsc/osmux.h> - -#include <osmocom/sccp/sccp.h> - -#include <stdlib.h> -#include <stdbool.h> - -static struct bsc_nat *_nat; - - -#define BSC_STR "Information about BSCs\n" -#define MGCP_STR "MGCP related status\n" -#define PAGING_STR "Paging\n" -#define SMSC_REWRITE "SMSC Rewriting\n" - -static struct cmd_node nat_node = { - NAT_NODE, - "%s(config-nat)# ", - 1, -}; - -static struct cmd_node bsc_node = { - NAT_BSC_NODE, - "%s(config-nat-bsc)# ", - 1, -}; - -static struct cmd_node pgroup_node = { - PGROUP_NODE, - "%s(config-nat-paging-group)# ", - 1, -}; - -static int config_write_pgroup(struct vty *vty) -{ - return CMD_SUCCESS; -} - -static void dump_lac(struct vty *vty, struct llist_head *head) -{ - struct bsc_lac_entry *lac; - llist_for_each_entry(lac, head, entry) - vty_out(vty, " location_area_code %u%s", lac->lac, VTY_NEWLINE); -} - - -static void write_pgroup_lst(struct vty *vty, struct bsc_nat_paging_group *pgroup) -{ - vty_out(vty, " paging-group %d%s", pgroup->nr, VTY_NEWLINE); - dump_lac(vty, &pgroup->lists); -} - -static int config_write_nat(struct vty *vty) -{ - struct bsc_msg_acc_lst *lst; - struct bsc_nat_paging_group *pgroup; - - vty_out(vty, "nat%s", VTY_NEWLINE); - vty_out(vty, " msc ip %s%s", _nat->main_dest->ip, VTY_NEWLINE); - vty_out(vty, " msc port %d%s", _nat->main_dest->port, VTY_NEWLINE); - vty_out(vty, " timeout auth %d%s", _nat->auth_timeout, VTY_NEWLINE); - vty_out(vty, " timeout ping %d%s", _nat->ping_timeout, VTY_NEWLINE); - vty_out(vty, " timeout pong %d%s", _nat->pong_timeout, VTY_NEWLINE); - if (_nat->include_file) - vty_out(vty, " bscs-config-file %s%s", _nat->include_file, VTY_NEWLINE); - if (_nat->token) - vty_out(vty, " token %s%s", _nat->token, VTY_NEWLINE); - vty_out(vty, " ip-dscp %d%s", _nat->bsc_ip_dscp, VTY_NEWLINE); - if (_nat->acc_lst_name) - vty_out(vty, " access-list-name %s%s", _nat->acc_lst_name, VTY_NEWLINE); - if (_nat->imsi_black_list_fn) - vty_out(vty, " imsi-black-list-file-name %s%s", - _nat->imsi_black_list_fn, VTY_NEWLINE); - if (_nat->ussd_lst_name) - vty_out(vty, " ussd-list-name %s%s", _nat->ussd_lst_name, VTY_NEWLINE); - if (_nat->ussd_query) - vty_out(vty, " ussd-query %s%s", _nat->ussd_query, VTY_NEWLINE); - if (_nat->ussd_token) - vty_out(vty, " ussd-token %s%s", _nat->ussd_token, VTY_NEWLINE); - if (_nat->ussd_local) - vty_out(vty, " ussd-local-ip %s%s", _nat->ussd_local, VTY_NEWLINE); - - if (_nat->num_rewr_name) - vty_out(vty, " number-rewrite %s%s", _nat->num_rewr_name, VTY_NEWLINE); - if (_nat->num_rewr_post_name) - vty_out(vty, " number-rewrite-post %s%s", - _nat->num_rewr_post_name, VTY_NEWLINE); - - if (_nat->smsc_rewr_name) - vty_out(vty, " rewrite-smsc addr %s%s", - _nat->smsc_rewr_name, VTY_NEWLINE); - if (_nat->tpdest_match_name) - vty_out(vty, " rewrite-smsc tp-dest-match %s%s", - _nat->tpdest_match_name, VTY_NEWLINE); - if (_nat->sms_clear_tp_srr_name) - vty_out(vty, " sms-clear-tp-srr %s%s", - _nat->sms_clear_tp_srr_name, VTY_NEWLINE); - if (_nat->sms_num_rewr_name) - vty_out(vty, " sms-number-rewrite %s%s", - _nat->sms_num_rewr_name, VTY_NEWLINE); - if (_nat->num_rewr_trie_name) - vty_out(vty, " prefix-tree %s%s", - _nat->num_rewr_trie_name, VTY_NEWLINE); - - llist_for_each_entry(lst, &_nat->access_lists, list) - bsc_msg_acc_lst_write(vty, lst); - llist_for_each_entry(pgroup, &_nat->paging_groups, entry) - write_pgroup_lst(vty, pgroup); - if (_nat->mgcp_ipa) - vty_out(vty, " use-msc-ipa-for-mgcp%s", VTY_NEWLINE); - vty_out(vty, " %ssdp-ensure-amr-mode-set%s", - _nat->sdp_ensure_amr_mode_set ? "" : "no ", VTY_NEWLINE); - - return CMD_SUCCESS; -} - -static void config_write_bsc_single(struct vty *vty, struct bsc_config *bsc) -{ - vty_out(vty, " bsc %u%s", bsc->nr, VTY_NEWLINE); - vty_out(vty, " token %s%s", bsc->token, VTY_NEWLINE); - if (bsc->key_present) - vty_out(vty, " auth-key %s%s", osmo_hexdump(bsc->key, 16), VTY_NEWLINE); - dump_lac(vty, &bsc->lac_list); - if (bsc->description) - vty_out(vty, " description %s%s", bsc->description, VTY_NEWLINE); - if (bsc->acc_lst_name) - vty_out(vty, " access-list-name %s%s", bsc->acc_lst_name, VTY_NEWLINE); - vty_out(vty, " max-endpoints %d%s", bsc->max_endpoints, VTY_NEWLINE); - if (bsc->paging_group != -1) - vty_out(vty, " paging group %d%s", bsc->paging_group, VTY_NEWLINE); - vty_out(vty, " paging forbidden %d%s", bsc->forbid_paging, VTY_NEWLINE); - switch (bsc->osmux) { - case OSMUX_USAGE_ON: - vty_out(vty, " osmux on%s", VTY_NEWLINE); - break; - case OSMUX_USAGE_ONLY: - vty_out(vty, " osmux only%s", VTY_NEWLINE); - break; - } - if (bsc->bts_use_jibuf_override) - vty_out(vty, " %sbts-jitter-buffer%s", bsc->bts_use_jibuf? "" : "no ", VTY_NEWLINE); - if (bsc->bts_jitter_delay_min_override) - vty_out(vty, " bts-jitter-delay-min %"PRIu32"%s", bsc->bts_jitter_delay_min, VTY_NEWLINE); - if (bsc->bts_jitter_delay_max_override) - vty_out(vty, " bts-jitter-delay-max %"PRIu32"%s", bsc->bts_jitter_delay_max, VTY_NEWLINE); -} - -static int config_write_bsc(struct vty *vty) -{ - struct bsc_config *bsc; - - llist_for_each_entry(bsc, &_nat->bsc_configs, entry) - config_write_bsc_single(vty, bsc); - return CMD_SUCCESS; -} - -DEFUN(show_bscs, show_bscs_cmd, "show bscs-config", - SHOW_STR "Show configured BSCs\n" - "Both from included file and vty\n") -{ - vty_out(vty, "BSCs configuration loaded from %s:%s", _nat->resolved_path, - VTY_NEWLINE); - return config_write_bsc(vty); -} - -DEFUN(show_sccp, show_sccp_cmd, "show sccp connections", - SHOW_STR "Display information about SCCP\n" - "All active connections\n") -{ - struct nat_sccp_connection *con; - vty_out(vty, "Listing all open SCCP connections%s", VTY_NEWLINE); - - llist_for_each_entry(con, &_nat->sccp_connections, list_entry) { - vty_out(vty, "For BSC Nr: %d BSC ref: 0x%x; MUX ref: 0x%x; Network has ref: %d ref: 0x%x MSC/BSC mux: 0x%x/0x%x type: %s%s", - con->bsc->cfg ? con->bsc->cfg->nr : -1, - sccp_src_ref_to_int(&con->real_ref), - sccp_src_ref_to_int(&con->patched_ref), - con->has_remote_ref, - sccp_src_ref_to_int(&con->remote_ref), - con->msc_endp, con->bsc_endp, - bsc_con_type_to_string(con->filter_state.con_type), - VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(show_nat_bsc, show_nat_bsc_cmd, "show nat num-bscs-configured", - SHOW_STR "Display NAT configuration details\n" - "BSCs-related\n") -{ - vty_out(vty, "%d BSCs configured%s", _nat->num_bsc, VTY_NEWLINE); - return CMD_SUCCESS; -} - -DEFUN(show_bsc, show_bsc_cmd, "show bsc connections", - SHOW_STR BSC_STR - "All active connections\n") -{ - struct bsc_connection *con; - struct sockaddr_in sock; - socklen_t len = sizeof(sock); - - llist_for_each_entry(con, &_nat->bsc_connections, list_entry) { - getpeername(con->write_queue.bfd.fd, (struct sockaddr *) &sock, &len); - vty_out(vty, "BSC nr: %d auth: %d fd: %d peername: %s pending-stats: %u%s", - con->cfg ? con->cfg->nr : -1, - con->authenticated, con->write_queue.bfd.fd, - inet_ntoa(sock.sin_addr), con->pending_dlcx_count, - VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(show_bsc_mgcp, show_bsc_mgcp_cmd, "show bsc mgcp NR", - SHOW_STR BSC_STR MGCP_STR "Identifier of the BSC\n") -{ - struct bsc_connection *con; - int nr = atoi(argv[0]); - int i, j, endp; - - llist_for_each_entry(con, &_nat->bsc_connections, list_entry) { - int max; - if (!con->cfg) - continue; - if (con->cfg->nr != nr) - continue; - - /* this bsc has no audio endpoints yet */ - if (!con->_endpoint_status) - continue; - - vty_out(vty, "MGCP Status for %d%s", con->cfg->nr, VTY_NEWLINE); - max = bsc_mgcp_nr_multiplexes(con->max_endpoints); - for (i = 0; i < max; ++i) { - for (j = 1; j < 32; ++j) { - endp = mgcp_timeslot_to_endpoint(i, j); - vty_out(vty, " Endpoint 0x%x %s%s", endp, - con->_endpoint_status[endp] == 0 - ? "free" : "allocated", - VTY_NEWLINE); - } - } - break; - } - - return CMD_SUCCESS; -} - -DEFUN(show_bsc_cfg, show_bsc_cfg_cmd, "show bsc config", - SHOW_STR BSC_STR "Configuration of BSCs\n") -{ - struct bsc_config *conf; - llist_for_each_entry(conf, &_nat->bsc_configs, entry) { - vty_out(vty, "BSC token: '%s' nr: %u%s", - conf->token, conf->nr, VTY_NEWLINE); - if (conf->acc_lst_name) - vty_out(vty, " access-list: %s%s", - conf->acc_lst_name, VTY_NEWLINE); - vty_out(vty, " paging forbidden: %d%s", - conf->forbid_paging, VTY_NEWLINE); - if (conf->description) - vty_out(vty, " description: %s%s", conf->description, VTY_NEWLINE); - else - vty_out(vty, " No description.%s", VTY_NEWLINE); - - } - - return CMD_SUCCESS; -} - -static void dump_stat_total(struct vty *vty, struct bsc_nat *nat) -{ - vty_out(vty, "NAT statistics%s", VTY_NEWLINE); - vty_out(vty, " SCCP Connections %lu total, %lu calls%s", - osmo_counter_get(nat->stats.sccp.conn), - osmo_counter_get(nat->stats.sccp.calls), VTY_NEWLINE); - vty_out(vty, " MSC Connections %lu%s", - osmo_counter_get(nat->stats.msc.reconn), VTY_NEWLINE); - vty_out(vty, " MSC Connected: %d%s", - bsc_nat_msc_is_connected(nat), VTY_NEWLINE); - vty_out(vty, " BSC Connections %lu total, %lu auth failed.%s", - osmo_counter_get(nat->stats.bsc.reconn), - osmo_counter_get(nat->stats.bsc.auth_fail), VTY_NEWLINE); -} - -static void dump_stat_bsc(struct vty *vty, struct bsc_config *conf) -{ - int connected = 0; - struct bsc_connection *con; - - vty_out(vty, " BSC nr: %d%s", - conf->nr, VTY_NEWLINE); - vty_out_rate_ctr_group(vty, " ", conf->stats.ctrg); - - llist_for_each_entry(con, &conf->nat->bsc_connections, list_entry) { - if (con->cfg != conf) - continue; - connected = 1; - break; - } - - vty_out(vty, " Connected: %d%s", connected, VTY_NEWLINE); -} - -DEFUN(show_stats, - show_stats_cmd, - "show statistics [NR]", - SHOW_STR "Display network statistics\n" - "Number of the BSC\n") -{ - struct bsc_config *conf; - - int nr = -1; - - if (argc == 1) - nr = atoi(argv[0]); - - dump_stat_total(vty, _nat); - llist_for_each_entry(conf, &_nat->bsc_configs, entry) { - if (argc == 1 && nr != conf->nr) - continue; - dump_stat_bsc(vty, conf); - } - - return CMD_SUCCESS; -} - -DEFUN(show_stats_lac, - show_stats_lac_cmd, - "show statistics-by-lac <0-65535>", - SHOW_STR "Display network statistics by lac\n" - "The lac of the BSC\n") -{ - int lac; - struct bsc_config *conf; - - lac = atoi(argv[0]); - - dump_stat_total(vty, _nat); - llist_for_each_entry(conf, &_nat->bsc_configs, entry) { - if (!bsc_config_handles_lac(conf, lac)) - continue; - dump_stat_bsc(vty, conf); - } - - return CMD_SUCCESS; -} - -DEFUN(show_msc, - show_msc_cmd, - "show msc connection", - SHOW_STR "MSC related information\n" - "Status of the A-link connection\n") -{ - if (!_nat->msc_con) { - vty_out(vty, "The MSC is not yet configured.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - vty_out(vty, "MSC is connected: %d%s", - bsc_nat_msc_is_connected(_nat), VTY_NEWLINE); - return CMD_SUCCESS; -} - -DEFUN(close_bsc, - close_bsc_cmd, - "close bsc connection BSC_NR", - "Close\n" "A-link\n" "Connection\n" "Identifier of the BSC\n") -{ - struct bsc_connection *bsc; - int bsc_nr = atoi(argv[0]); - - llist_for_each_entry(bsc, &_nat->bsc_connections, list_entry) { - if (!bsc->cfg || bsc->cfg->nr != bsc_nr) - continue; - bsc_close_connection(bsc); - break; - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_nat, cfg_nat_cmd, "nat", "Configure the NAT") -{ - vty->index = _nat; - vty->node = NAT_NODE; - - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_msc_ip, - cfg_nat_msc_ip_cmd, - "msc ip A.B.C.D", - "MSC related configuration\n" - "Configure the IP address\n" IP_STR) -{ - bsc_nat_set_msc_ip(_nat, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_msc_port, - cfg_nat_msc_port_cmd, - "msc port <1-65500>", - "MSC related configuration\n" - "Configure the port\n" - "Port number\n") -{ - _nat->main_dest->port = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_auth_time, - cfg_nat_auth_time_cmd, - "timeout auth <1-256>", - "Timeout configuration\n" - "Authentication timeout\n" - "Timeout in seconds\n") -{ - _nat->auth_timeout = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_ping_time, - cfg_nat_ping_time_cmd, - "timeout ping NR", - "Timeout configuration\n" - "Time between two pings\n" - "Timeout in seconds\n") -{ - _nat->ping_timeout = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_pong_time, - cfg_nat_pong_time_cmd, - "timeout pong NR", - "Timeout configuration\n" - "Waiting for pong timeout\n" - "Timeout in seconds\n") -{ - _nat->pong_timeout = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_token, cfg_nat_token_cmd, - "token TOKEN", - "Authentication token configuration\n" - "Token of the BSC, currently transferred in cleartext\n") -{ - osmo_talloc_replace_string(_nat, &_nat->token, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_bsc_ip_dscp, cfg_nat_bsc_ip_dscp_cmd, - "ip-dscp <0-255>", - "Set the IP DSCP for the BSCs to use\n" "Set the IP_TOS attribute") -{ - _nat->bsc_ip_dscp = atoi(argv[0]); - return CMD_SUCCESS; -} - -ALIAS_DEPRECATED(cfg_nat_bsc_ip_dscp, cfg_nat_bsc_ip_tos_cmd, - "ip-tos <0-255>", - "Use ip-dscp in the future.\n" "Set the DSCP\n") - - -DEFUN(cfg_nat_acc_lst_name, - cfg_nat_acc_lst_name_cmd, - "access-list-name NAME", - "Set the name of the access list to use.\n" - "The name of the to be used access list.") -{ - osmo_talloc_replace_string(_nat, &_nat->acc_lst_name, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_include, - cfg_nat_include_cmd, - "bscs-config-file NAME", - "Set the filename of the BSC configuration to include.\n" - "The filename to be included.") -{ - char *path; - int rc; - struct bsc_config *cf1, *cf2; - struct bsc_connection *con1, *con2; - - if ('/' == argv[0][0]) - osmo_talloc_replace_string(_nat, &_nat->resolved_path, argv[0]); - else { - path = talloc_asprintf(_nat, "%s/%s", _nat->include_base, - argv[0]); - osmo_talloc_replace_string(_nat, &_nat->resolved_path, path); - talloc_free(path); - } - - llist_for_each_entry_safe(cf1, cf2, &_nat->bsc_configs, entry) { - cf1->remove = true; - cf1->token_updated = false; - } - - rc = vty_read_config_file(_nat->resolved_path, NULL); - if (rc < 0) { - vty_out(vty, "Failed to parse the config file %s: %s%s", - _nat->resolved_path, strerror(-rc), VTY_NEWLINE); - return CMD_WARNING; - } - - osmo_talloc_replace_string(_nat, &_nat->include_file, argv[0]); - - llist_for_each_entry_safe(con1, con2, &_nat->bsc_connections, - list_entry) { - if (con1->cfg) - if (con1->cfg->token_updated || con1->cfg->remove) - bsc_close_connection(con1); - } - - llist_for_each_entry_safe(cf1, cf2, &_nat->bsc_configs, entry) { - if (cf1->remove) - bsc_config_free(cf1); - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_no_acc_lst_name, - cfg_nat_no_acc_lst_name_cmd, - "no access-list-name", - NO_STR "Remove the access list from the NAT.\n") -{ - if (_nat->acc_lst_name) { - talloc_free(_nat->acc_lst_name); - _nat->acc_lst_name = NULL; - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_imsi_black_list_fn, - cfg_nat_imsi_black_list_fn_cmd, - "imsi-black-list-file-name NAME", - "IMSI black listing\n" "Filename IMSI and reject-cause\n") -{ - - osmo_talloc_replace_string(_nat, &_nat->imsi_black_list_fn, argv[0]); - if (_nat->imsi_black_list_fn) { - int rc; - struct osmo_config_list *rewr = NULL; - rewr = osmo_config_list_parse(_nat, _nat->imsi_black_list_fn); - rc = bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, rewr); - if (rc != 0) { - vty_out(vty, "%%There was an error parsing the list." - " Please see the error log.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - return CMD_SUCCESS; - } - - bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, NULL); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_no_imsi_black_list_fn, - cfg_nat_no_imsi_black_list_fn_cmd, - "no imsi-black-list-file-name", - NO_STR "Remove the imsi-black-list\n") -{ - talloc_free(_nat->imsi_black_list_fn); - _nat->imsi_black_list_fn = NULL; - bsc_filter_barr_adapt(_nat, &_nat->imsi_black_list, NULL); - return CMD_SUCCESS; -} - -static int replace_rules(struct bsc_nat *nat, char **name, - struct llist_head *head, const char *file) -{ - struct osmo_config_list *rewr = NULL; - - osmo_talloc_replace_string(nat, name, file); - if (*name) { - rewr = osmo_config_list_parse(nat, *name); - bsc_nat_num_rewr_entry_adapt(nat, head, rewr); - talloc_free(rewr); - return CMD_SUCCESS; - } else { - bsc_nat_num_rewr_entry_adapt(nat, head, NULL); - return CMD_SUCCESS; - } -} - -DEFUN(cfg_nat_number_rewrite, - cfg_nat_number_rewrite_cmd, - "number-rewrite FILENAME", - "Set the file with rewriting rules.\n" "Filename") -{ - return replace_rules(_nat, &_nat->num_rewr_name, - &_nat->num_rewr, argv[0]); -} - -DEFUN(cfg_nat_no_number_rewrite, - cfg_nat_no_number_rewrite_cmd, - "no number-rewrite", - NO_STR "Set the file with rewriting rules.\n") -{ - talloc_free(_nat->num_rewr_name); - _nat->num_rewr_name = NULL; - - bsc_nat_num_rewr_entry_adapt(NULL, &_nat->num_rewr, NULL); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_number_rewrite_post, - cfg_nat_number_rewrite_post_cmd, - "number-rewrite-post FILENAME", - "Set the file with post-routing rewriting rules.\n" "Filename") -{ - return replace_rules(_nat, &_nat->num_rewr_post_name, - &_nat->num_rewr_post, argv[0]); -} - -DEFUN(cfg_nat_no_number_rewrite_post, - cfg_nat_no_number_rewrite_post_cmd, - "no number-rewrite-post", - NO_STR "Set the file with post-routing rewriting rules.\n") -{ - talloc_free(_nat->num_rewr_post_name); - _nat->num_rewr_post_name = NULL; - - bsc_nat_num_rewr_entry_adapt(NULL, &_nat->num_rewr_post, NULL); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_smsc_addr, - cfg_nat_smsc_addr_cmd, - "rewrite-smsc addr FILENAME", - SMSC_REWRITE - "The SMSC Address to match and replace in RP-DATA\n" - "File with rules for the SMSC Address replacing\n") -{ - return replace_rules(_nat, &_nat->smsc_rewr_name, - &_nat->smsc_rewr, argv[0]); -} - -DEFUN(cfg_nat_smsc_tpdest, - cfg_nat_smsc_tpdest_cmd, - "rewrite-smsc tp-dest-match FILENAME", - SMSC_REWRITE - "Match TP-Destination of a SMS.\n" - "File with rules for matching MSISDN and TP-DEST\n") -{ - return replace_rules(_nat, &_nat->tpdest_match_name, - &_nat->tpdest_match, argv[0]); -} - -DEFUN(cfg_nat_sms_clear_tpsrr, - cfg_nat_sms_clear_tpsrr_cmd, - "sms-clear-tp-srr FILENAME", - "SMS TPDU Sender Report Request clearing\n" - "Files with rules for matching MSISDN\n") -{ - return replace_rules(_nat, &_nat->sms_clear_tp_srr_name, - &_nat->sms_clear_tp_srr, argv[0]); -} - -DEFUN(cfg_nat_no_sms_clear_tpsrr, - cfg_nat_no_sms_clear_tpsrr_cmd, - "no sms-clear-tp-srr", - NO_STR - "SMS TPDU Sender Report Request clearing\n") -{ - talloc_free(_nat->sms_clear_tp_srr_name); - _nat->sms_clear_tp_srr_name = NULL; - - bsc_nat_num_rewr_entry_adapt(NULL, &_nat->sms_clear_tp_srr, NULL); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_sms_number_rewrite, - cfg_nat_sms_number_rewrite_cmd, - "sms-number-rewrite FILENAME", - "SMS TP-DA Number rewriting\n" - "Files with rules for matching MSISDN\n") -{ - return replace_rules(_nat, &_nat->sms_num_rewr_name, - &_nat->sms_num_rewr, argv[0]); -} - -DEFUN(cfg_nat_no_sms_number_rewrite, - cfg_nat_no_sms_number_rewrite_cmd, - "no sms-number-rewrite", - NO_STR "Disable SMS TP-DA rewriting\n") -{ - talloc_free(_nat->sms_num_rewr_name); - _nat->sms_num_rewr_name = NULL; - - bsc_nat_num_rewr_entry_adapt(NULL, &_nat->sms_num_rewr, NULL); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_prefix_trie, - cfg_nat_prefix_trie_cmd, - "prefix-tree FILENAME", - "Prefix tree for number rewriting\n" "File to load\n") -{ - /* give up the old data */ - talloc_free(_nat->num_rewr_trie); - _nat->num_rewr_trie = NULL; - - /* replace the file name */ - osmo_talloc_replace_string(_nat, &_nat->num_rewr_trie_name, argv[0]); - if (!_nat->num_rewr_trie_name) { - vty_out(vty, "%% prefix-tree no filename is present.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - _nat->num_rewr_trie = nat_rewrite_parse(_nat, _nat->num_rewr_trie_name); - if (!_nat->num_rewr_trie) { - vty_out(vty, "%% prefix-tree parsing has failed.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - vty_out(vty, "%% prefix-tree loaded %zu rules.%s", - _nat->num_rewr_trie->prefixes, VTY_NEWLINE); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_no_prefix_trie, cfg_nat_no_prefix_trie_cmd, - "no prefix-tree", - NO_STR "Prefix tree for number rewriting\n") -{ - talloc_free(_nat->num_rewr_trie); - _nat->num_rewr_trie = NULL; - talloc_free(_nat->num_rewr_trie_name); - _nat->num_rewr_trie_name = NULL; - - return CMD_SUCCESS; -} - -DEFUN(show_prefix_tree, show_prefix_tree_cmd, - "show prefix-tree", - SHOW_STR "Prefix tree for number rewriting\n") -{ - if (!_nat->num_rewr_trie) { - vty_out(vty, "%% there is now prefix tree loaded.%s", - VTY_NEWLINE); - return CMD_WARNING; - } - - nat_rewrite_dump_vty(vty, _nat->num_rewr_trie); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_ussd_lst_name, - cfg_nat_ussd_lst_name_cmd, - "ussd-list-name NAME", - "Set the name of the access list to check for IMSIs for USSD message\n" - "The name of the access list for HLR USSD handling") -{ - osmo_talloc_replace_string(_nat, &_nat->ussd_lst_name, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_ussd_query, - cfg_nat_ussd_query_cmd, - "ussd-query REGEXP", - "Set the USSD query to match with the ussd-list-name\n" - "The query to match") -{ - if (gsm_parse_reg(_nat, &_nat->ussd_query_re, &_nat->ussd_query, argc, argv) != 0) - return CMD_WARNING; - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_ussd_token, - cfg_nat_ussd_token_cmd, - "ussd-token TOKEN", - "Set the token used to identify the USSD module\n" "Secret key\n") -{ - osmo_talloc_replace_string(_nat, &_nat->ussd_token, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_ussd_local, - cfg_nat_ussd_local_cmd, - "ussd-local-ip A.B.C.D", - "Set the IP to listen for the USSD Provider\n" "IP Address\n") -{ - osmo_talloc_replace_string(_nat, &_nat->ussd_local, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_use_ipa_for_mgcp, - cfg_nat_use_ipa_for_mgcp_cmd, - "use-msc-ipa-for-mgcp", - "This needs to be set at start. Handle MGCP messages through " - "the IPA protocol and not through the UDP socket.\n") -{ - if (_nat->mgcp_cfg->data) - vty_out(vty, - "%%the setting will not be applied right now.%s", - VTY_NEWLINE); - _nat->mgcp_ipa = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_sdp_amr_mode_set, - cfg_nat_sdp_amr_mode_set_cmd, - "sdp-ensure-amr-mode-set", - "Ensure that SDP records include a mode-set\n") -{ - _nat->sdp_ensure_amr_mode_set = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_no_sdp_amr_mode_set, - cfg_nat_no_sdp_amr_mode_set_cmd, - "no sdp-ensure-amr-mode-set", - NO_STR "Ensure that SDP records include a mode-set\n") -{ - _nat->sdp_ensure_amr_mode_set = 0; - return CMD_SUCCESS; -} - -/* per BSC configuration */ -DEFUN(cfg_bsc, cfg_bsc_cmd, "bsc BSC_NR", - "BSC configuration\n" "Identifier of the BSC\n") -{ - int bsc_nr = atoi(argv[0]); - struct bsc_config *bsc = bsc_config_num(_nat, bsc_nr); - - /* allocate a new one */ - if (!bsc) - bsc = bsc_config_alloc(_nat, "unknown", bsc_nr); - - if (!bsc) - return CMD_WARNING; - - bsc->remove = false; - vty->index = bsc; - vty->node = NAT_BSC_NODE; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_token, cfg_bsc_token_cmd, "token TOKEN", - "Authentication token configuration\n" - "Token of the BSC, currently transferred in cleartext\n") -{ - struct bsc_config *conf = vty->index; - - if (strncmp(conf->token, argv[0], 128) != 0) - conf->token_updated = true; - - osmo_talloc_replace_string(conf, &conf->token, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_auth_key, cfg_bsc_auth_key_cmd, - "auth-key KEY", - "Authentication (secret) key configuration\n" - "Non null security key\n") -{ - struct bsc_config *conf = vty->index; - - memset(conf->key, 0, sizeof(conf->key)); - osmo_hexparse(argv[0], conf->key, sizeof(conf->key)); - conf->key_present = 1; - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_no_auth_key, cfg_bsc_no_auth_key_cmd, - "no auth-key", - NO_STR "Authentication (secret) key configuration\n") -{ - struct bsc_config *conf = vty->index; - - memset(conf->key, 0, sizeof(conf->key)); - conf->key_present = 0; - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_lac, cfg_bsc_lac_cmd, "location_area_code <0-65535>", - "Add the Location Area Code (LAC) of this BSC\n" "LAC\n") -{ - struct bsc_config *tmp; - struct bsc_config *conf = vty->index; - - int lac = atoi(argv[0]); - - if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) { - vty_out(vty, "%% LAC %d is reserved by GSM 04.08%s", - lac, VTY_NEWLINE); - return CMD_WARNING; - } - - /* verify that the LACs are unique */ - llist_for_each_entry(tmp, &_nat->bsc_configs, entry) { - if (bsc_config_handles_lac(tmp, lac)) { - if (tmp->nr != conf->nr) { - vty_out(vty, "%% LAC %d is already used.%s", lac, - VTY_NEWLINE); - return CMD_ERR_INCOMPLETE; - } - } - } - - bsc_config_add_lac(conf, lac); - - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_no_lac, cfg_bsc_no_lac_cmd, - "no location_area_code <0-65535>", - NO_STR "Remove the Location Area Code (LAC) of this BSC\n" "LAC\n") -{ - int lac = atoi(argv[0]); - struct bsc_config *conf = vty->index; - - bsc_config_del_lac(conf, lac); - return CMD_SUCCESS; -} - -DEFUN(show_bar_lst, - show_bar_lst_cmd, - "show imsi-black-list", - SHOW_STR "IMSIs barred from the network\n") -{ - struct rb_node *node; - - vty_out(vty, "IMSIs barred from the network:%s", VTY_NEWLINE); - - for (node = rb_first(&_nat->imsi_black_list); node; node = rb_next(node)) { - struct bsc_filter_barr_entry *entry; - entry = rb_entry(node, struct bsc_filter_barr_entry, node); - - vty_out(vty, " IMSI(%s) CM-Reject-Cause(%d) LU-Reject-Cause(%d)%s", - entry->imsi, entry->cm_reject_cause, entry->lu_reject_cause, - VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - - -DEFUN(cfg_bsc_acc_lst_name, - cfg_bsc_acc_lst_name_cmd, - "access-list-name NAME", - "Set the name of the access list to use.\n" - "The name of the to be used access list.") -{ - struct bsc_config *conf = vty->index; - - osmo_talloc_replace_string(conf, &conf->acc_lst_name, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_no_acc_lst_name, - cfg_bsc_no_acc_lst_name_cmd, - "no access-list-name", - NO_STR "Do not use an access-list for the BSC.\n") -{ - struct bsc_config *conf = vty->index; - - if (conf->acc_lst_name) { - talloc_free(conf->acc_lst_name); - conf->acc_lst_name = NULL; - } - - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_max_endps, cfg_bsc_max_endps_cmd, - "max-endpoints <1-1024>", - "Highest endpoint to use (exclusively)\n" "Number of ports\n") -{ - struct bsc_config *conf = vty->index; - - conf->max_endpoints = atoi(argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_paging, - cfg_bsc_paging_cmd, - "paging forbidden (0|1)", - PAGING_STR "Forbid sending PAGING REQUESTS to the BSC.\n" - "Do not forbid\n" "Forbid\n") -{ - struct bsc_config *conf = vty->index; - - if (strcmp("1", argv[0]) == 0) - conf->forbid_paging = 1; - else - conf->forbid_paging = 0; - - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_desc, - cfg_bsc_desc_cmd, - "description DESC", - "Provide a description for the given BSC.\n" "Description\n") -{ - struct bsc_config *conf = vty->index; - - osmo_talloc_replace_string(conf, &conf->description, argv[0]); - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_paging_grp, - cfg_bsc_paging_grp_cmd, - "paging group <0-1000>", - PAGING_STR "Use a paging group\n" "Paging Group to use\n") -{ - struct bsc_config *conf = vty->index; - conf->paging_group = atoi(argv[0]); - return CMD_SUCCESS; -} - -ALIAS_DEPRECATED(cfg_bsc_paging_grp, cfg_bsc_old_grp_cmd, - "paging-group <0-1000>", - "Use a paging group\n" "Paging Group to use\n") - -DEFUN(cfg_bsc_no_paging_grp, - cfg_bsc_no_paging_grp_cmd, - "no paging group", - NO_STR PAGING_STR "Disable the usage of a paging group.\n") -{ - struct bsc_config *conf = vty->index; - conf->paging_group = PAGIN_GROUP_UNASSIGNED; - return CMD_SUCCESS; -} - -DEFUN(test_regex, test_regex_cmd, - "test regex PATTERN STRING", - "Test utilities\n" - "Regexp testing\n" "The regexp pattern\n" - "The string to match\n") -{ - regex_t reg; - char *str = NULL; - - memset(®, 0, sizeof(reg)); - if (gsm_parse_reg(_nat, ®, &str, 1, argv) != 0) - return CMD_WARNING; - - vty_out(vty, "String matches allow pattern: %d%s", - regexec(®, argv[1], 0, NULL, 0) == 0, VTY_NEWLINE); - - talloc_free(str); - regfree(®); - return CMD_SUCCESS; -} - -DEFUN(set_last_endp, set_last_endp_cmd, - "set bsc last-used-endpoint <0-9999999999> <0-1024>", - "Set a value\n" "Operate on a BSC\n" - "Last used endpoint for an assignment\n" "BSC configuration number\n" - "Endpoint number used\n") -{ - struct bsc_connection *con; - int nr = atoi(argv[0]); - int endp = atoi(argv[1]); - - - llist_for_each_entry(con, &_nat->bsc_connections, list_entry) { - if (!con->cfg) - continue; - if (con->cfg->nr != nr) - continue; - - con->last_endpoint = endp; - vty_out(vty, "Updated the last endpoint for %d to %d.%s", - con->cfg->nr, con->last_endpoint, VTY_NEWLINE); - } - - return CMD_SUCCESS; -} - -DEFUN(block_new_conn, block_new_conn_cmd, - "nat-block (block|unblock)", - "Block the NAT for new connections\n" - "Block\n" "Unblock\n") -{ - _nat->blocked = argv[0][0] == 'b'; - vty_out(vty, "%%Going to %s the NAT.%s", - _nat->blocked ? "block" : "unblock", VTY_NEWLINE); - return CMD_SUCCESS; -} - -/* paging group */ -DEFUN(cfg_nat_pgroup, cfg_nat_pgroup_cmd, - "paging-group <0-1000>", - "Create a Paging Group\n" "Number of the Group\n") -{ - int group = atoi(argv[0]); - struct bsc_nat_paging_group *pgroup; - pgroup = bsc_nat_paging_group_num(_nat, group); - if (!pgroup) - pgroup = bsc_nat_paging_group_create(_nat, group); - if (!pgroup) { - vty_out(vty, "Failed to create the group.%s", VTY_NEWLINE); - return CMD_WARNING; - } - - vty->index = pgroup; - vty->node = PGROUP_NODE; - return CMD_SUCCESS; -} - -DEFUN(cfg_nat_no_pgroup, cfg_nat_no_pgroup_cmd, - "no paging-group <0-1000>", - NO_STR "Delete paging-group\n" "Paging-group number\n") -{ - int group = atoi(argv[0]); - struct bsc_nat_paging_group *pgroup; - pgroup = bsc_nat_paging_group_num(_nat, group); - if (!pgroup) { - vty_out(vty, "No such paging group %d.%s", group, VTY_NEWLINE); - return CMD_WARNING; - } - - bsc_nat_paging_group_delete(pgroup); - return CMD_SUCCESS; -} - -DEFUN(cfg_pgroup_lac, cfg_pgroup_lac_cmd, - "location_area_code <0-65535>", - "Add the Location Area Code (LAC)\n" "LAC\n") -{ - struct bsc_nat_paging_group *pgroup = vty->index; - - int lac = atoi(argv[0]); - if (lac == GSM_LAC_RESERVED_DETACHED || lac == GSM_LAC_RESERVED_ALL_BTS) { - vty_out(vty, "%% LAC %d is reserved by GSM 04.08%s", - lac, VTY_NEWLINE); - return CMD_WARNING; - } - - bsc_nat_paging_group_add_lac(pgroup, lac); - return CMD_SUCCESS; -} - -DEFUN(cfg_pgroup_no_lac, cfg_pgroup_no_lac_cmd, - "no location_area_code <0-65535>", - NO_STR "Remove the Location Area Code (LAC)\n" "LAC\n") -{ - int lac = atoi(argv[0]); - struct bsc_nat_paging_group *pgroup = vty->index; - - bsc_nat_paging_group_del_lac(pgroup, lac); - return CMD_SUCCESS; -} - -DEFUN(show_ussd_connection, - show_ussd_connection_cmd, - "show ussd-connection", - SHOW_STR "USSD connection related information\n") -{ - vty_out(vty, "The USSD side channel provider is %sconnected and %sauthorized.%s", - _nat->ussd_con ? "" : "not ", - _nat->ussd_con && _nat->ussd_con->authorized? "" : "not ", - VTY_NEWLINE); - return CMD_SUCCESS; -} - -#define OSMUX_STR "RTP multiplexing\n" -DEFUN(cfg_bsc_osmux, - cfg_bsc_osmux_cmd, - "osmux (on|off|only)", - OSMUX_STR "Enable OSMUX\n" "Disable OSMUX\n" "Only OSMUX\n") -{ - struct bsc_config *conf = vty->index; - int old = conf->osmux; - - if (strcmp(argv[0], "on") == 0) - conf->osmux = OSMUX_USAGE_ON; - else if (strcmp(argv[0], "off") == 0) - conf->osmux = OSMUX_USAGE_OFF; - else if (strcmp(argv[0], "only") == 0) - conf->osmux = OSMUX_USAGE_ONLY; - - if (old == 0 && conf->osmux > 0 && !conf->nat->mgcp_cfg->osmux_init) { - LOGP(DLMGCP, LOGL_NOTICE, "Setting up OSMUX socket\n"); - if (osmux_init(OSMUX_ROLE_BSC_NAT, conf->nat->mgcp_cfg) < 0) { - LOGP(DLMGCP, LOGL_ERROR, "Cannot init OSMUX\n"); - vty_out(vty, "%% failed to create Osmux socket%s", - VTY_NEWLINE); - return CMD_WARNING; - } - } else if (old > 0 && conf->osmux == 0) { - LOGP(DLMGCP, LOGL_NOTICE, "Disabling OSMUX socket\n"); - /* Don't stop the socket, we may already have ongoing voice - * flows already using Osmux. This just switch indicates that - * new upcoming flows should use RTP. - */ - } - - return CMD_SUCCESS; -} - -#define DEJITTER_STR "Uplink Jitter Buffer" -DEFUN(cfg_bsc_bts_use_jibuf, - cfg_bsc_bts_use_jibuf_cmd, - "bts-jitter-buffer", - DEJITTER_STR "\n") -{ - struct bsc_config *conf = vty->index; - conf->bts_use_jibuf = true; - conf->bts_use_jibuf_override = true; - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_no_bts_use_jibuf, - cfg_bsc_no_bts_use_jibuf_cmd, - "no bts-jitter-buffer", - NO_STR DEJITTER_STR "\n") -{ - struct bsc_config *conf = vty->index; - conf->bts_use_jibuf = false; - conf->bts_use_jibuf_override = true; - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_bts_jitter_delay_min, - cfg_bsc_bts_jitter_delay_min_cmd, - "bts-jitter-buffer-delay-min <1-65535>", - DEJITTER_STR " Minimum Delay in ms\n" "Minimum Delay in ms\n") -{ - struct bsc_config *conf = vty->index; - conf->bts_jitter_delay_min = atoi(argv[0]); - if (!conf->bts_jitter_delay_min) { - vty_out(vty, "bts-jitter-buffer-delay-min cannot be zero.%s", VTY_NEWLINE); - return CMD_WARNING; - } - if (conf->bts_jitter_delay_min && conf->bts_jitter_delay_max && - conf->bts_jitter_delay_min > conf->bts_jitter_delay_max) { - vty_out(vty, "bts-jitter-buffer-delay-min cannot be bigger than " \ - "bts-jitter-buffer-delay-max.%s", VTY_NEWLINE); - return CMD_WARNING; - } - conf->bts_jitter_delay_min_override = true; - return CMD_SUCCESS; -} - -DEFUN(cfg_bsc_bts_jitter_delay_max, - cfg_bsc_bts_jitter_delay_max_cmd, - "bts-jitter-buffer-delay-max <1-65535>", - DEJITTER_STR " Maximum Delay in ms\n" "Maximum Delay in ms\n") -{ - struct bsc_config *conf = vty->index; - conf->bts_jitter_delay_max = atoi(argv[0]); - if (!conf->bts_jitter_delay_max) { - vty_out(vty, "bts-jitter-buffer-delay-max cannot be zero.%s", VTY_NEWLINE); - return CMD_WARNING; - } - if (conf->bts_jitter_delay_min && conf->bts_jitter_delay_max && - conf->bts_jitter_delay_min > conf->bts_jitter_delay_max) { - vty_out(vty, "bts-jitter-buffer-delay-max cannot be smaller than " \ - "bts-jitter-buffer-delay-min.%s", VTY_NEWLINE); - return CMD_WARNING; - } - conf->bts_jitter_delay_max_override = true; - return CMD_SUCCESS; -} - -int bsc_nat_vty_init(struct bsc_nat *nat) -{ - _nat = nat; - - /* show commands */ - install_element_ve(&show_sccp_cmd); - install_element_ve(&show_bsc_cmd); - install_element_ve(&show_nat_bsc_cmd); - install_element_ve(&show_bsc_cfg_cmd); - install_element_ve(&show_stats_cmd); - install_element_ve(&show_stats_lac_cmd); - install_element_ve(&close_bsc_cmd); - install_element_ve(&show_msc_cmd); - install_element_ve(&test_regex_cmd); - install_element_ve(&show_bsc_mgcp_cmd); - install_element_ve(&show_bscs_cmd); - install_element_ve(&show_bar_lst_cmd); - install_element_ve(&show_prefix_tree_cmd); - install_element_ve(&show_ussd_connection_cmd); - - install_element(ENABLE_NODE, &set_last_endp_cmd); - install_element(ENABLE_NODE, &block_new_conn_cmd); - - /* nat group */ - install_element(CONFIG_NODE, &cfg_nat_cmd); - install_node(&nat_node, config_write_nat); - install_element(NAT_NODE, &cfg_nat_msc_ip_cmd); - install_element(NAT_NODE, &cfg_nat_msc_port_cmd); - install_element(NAT_NODE, &cfg_nat_auth_time_cmd); - install_element(NAT_NODE, &cfg_nat_ping_time_cmd); - install_element(NAT_NODE, &cfg_nat_pong_time_cmd); - install_element(NAT_NODE, &cfg_nat_token_cmd); - install_element(NAT_NODE, &cfg_nat_bsc_ip_dscp_cmd); - install_element(NAT_NODE, &cfg_nat_bsc_ip_tos_cmd); - install_element(NAT_NODE, &cfg_nat_acc_lst_name_cmd); - install_element(NAT_NODE, &cfg_nat_no_acc_lst_name_cmd); - install_element(NAT_NODE, &cfg_nat_include_cmd); - install_element(NAT_NODE, &cfg_nat_imsi_black_list_fn_cmd); - install_element(NAT_NODE, &cfg_nat_no_imsi_black_list_fn_cmd); - install_element(NAT_NODE, &cfg_nat_ussd_lst_name_cmd); - install_element(NAT_NODE, &cfg_nat_ussd_query_cmd); - install_element(NAT_NODE, &cfg_nat_ussd_token_cmd); - install_element(NAT_NODE, &cfg_nat_ussd_local_cmd); - install_element(NAT_NODE, &cfg_nat_use_ipa_for_mgcp_cmd); - - bsc_msg_lst_vty_init(nat, &nat->access_lists, NAT_NODE); - - /* number rewriting */ - install_element(NAT_NODE, &cfg_nat_number_rewrite_cmd); - install_element(NAT_NODE, &cfg_nat_no_number_rewrite_cmd); - install_element(NAT_NODE, &cfg_nat_number_rewrite_post_cmd); - install_element(NAT_NODE, &cfg_nat_no_number_rewrite_post_cmd); - install_element(NAT_NODE, &cfg_nat_smsc_addr_cmd); - install_element(NAT_NODE, &cfg_nat_smsc_tpdest_cmd); - install_element(NAT_NODE, &cfg_nat_sms_clear_tpsrr_cmd); - install_element(NAT_NODE, &cfg_nat_no_sms_clear_tpsrr_cmd); - install_element(NAT_NODE, &cfg_nat_sms_number_rewrite_cmd); - install_element(NAT_NODE, &cfg_nat_no_sms_number_rewrite_cmd); - install_element(NAT_NODE, &cfg_nat_prefix_trie_cmd); - install_element(NAT_NODE, &cfg_nat_no_prefix_trie_cmd); - - install_element(NAT_NODE, &cfg_nat_sdp_amr_mode_set_cmd); - install_element(NAT_NODE, &cfg_nat_no_sdp_amr_mode_set_cmd); - - install_element(NAT_NODE, &cfg_nat_pgroup_cmd); - install_element(NAT_NODE, &cfg_nat_no_pgroup_cmd); - install_node(&pgroup_node, config_write_pgroup); - install_element(PGROUP_NODE, &cfg_pgroup_lac_cmd); - install_element(PGROUP_NODE, &cfg_pgroup_no_lac_cmd); - - /* BSC subgroups */ - install_element(NAT_NODE, &cfg_bsc_cmd); - install_node(&bsc_node, NULL); - install_element(NAT_BSC_NODE, &cfg_bsc_token_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_auth_key_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_no_auth_key_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_lac_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_no_lac_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_paging_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_desc_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_acc_lst_name_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_no_acc_lst_name_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_max_endps_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_old_grp_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_paging_grp_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_no_paging_grp_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_osmux_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_bts_use_jibuf_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_no_bts_use_jibuf_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_bts_jitter_delay_min_cmd); - install_element(NAT_BSC_NODE, &cfg_bsc_bts_jitter_delay_max_cmd); - - mgcp_vty_init(); - - return 0; -} - - -/* called by the telnet interface... we have our own init above */ -int bsc_vty_init(struct gsm_network *network) -{ - logging_vty_add_cmds(NULL); - return 0; -} diff --git a/src/osmo-bsc_nat/bsc_sccp.c b/src/osmo-bsc_nat/bsc_sccp.c deleted file mode 100644 index bb882a664..000000000 --- a/src/osmo-bsc_nat/bsc_sccp.c +++ /dev/null @@ -1,247 +0,0 @@ -/* SCCP patching and handling routines */ -/* - * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <osmocom/bsc/debug.h> -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_nat_sccp.h> - -#include <osmocom/sccp/sccp.h> - -#include <osmocom/core/talloc.h> - -#include <string.h> -#include <time.h> - -static int equal(struct sccp_source_reference *ref1, struct sccp_source_reference *ref2) -{ - return memcmp(ref1, ref2, sizeof(*ref1)) == 0; -} - -/* - * SCCP patching below - */ - -/* check if we are using this ref for patched already */ -static int sccp_ref_is_free(struct sccp_source_reference *ref, struct bsc_nat *nat) -{ - struct nat_sccp_connection *conn; - - llist_for_each_entry(conn, &nat->sccp_connections, list_entry) { - if (equal(ref, &conn->patched_ref)) - return -1; - } - - return 0; -} - -/* copied from sccp.c */ -static int assign_src_local_reference(struct sccp_source_reference *ref, struct bsc_nat *nat) -{ - static uint32_t last_ref = 0x50000; - int wrapped = 0; - - do { - struct sccp_source_reference reference; - reference.octet1 = (last_ref >> 0) & 0xff; - reference.octet2 = (last_ref >> 8) & 0xff; - reference.octet3 = (last_ref >> 16) & 0xff; - - ++last_ref; - /* do not use the reversed word and wrap around */ - if ((last_ref & 0x00FFFFFF) == 0x00FFFFFF) { - LOGP(DNAT, LOGL_NOTICE, "Wrapped searching for a free code\n"); - last_ref = 0; - ++wrapped; - } - - if (sccp_ref_is_free(&reference, nat) == 0) { - *ref = reference; - return 0; - } - } while (wrapped != 2); - - LOGP(DNAT, LOGL_ERROR, "Finding a free reference failed\n"); - return -1; -} - -struct nat_sccp_connection *create_sccp_src_ref(struct bsc_connection *bsc, - struct bsc_nat_parsed *parsed) -{ - struct nat_sccp_connection *conn; - - /* Some commercial BSCs like to reassign there SRC ref */ - llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) { - if (conn->bsc != bsc) - continue; - if (!equal(parsed->src_local_ref, &conn->real_ref)) - continue; - - /* the BSC has reassigned the SRC ref and we failed to keep track */ - memset(&conn->remote_ref, 0, sizeof(conn->remote_ref)); - if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) { - LOGP(DNAT, LOGL_ERROR, "BSC %d reused src ref: %d and we failed to generate a new id.\n", - bsc->cfg->nr, sccp_src_ref_to_int(parsed->src_local_ref)); - bsc_mgcp_dlcx(conn); - llist_del(&conn->list_entry); - talloc_free(conn); - return NULL; - } else { - clock_gettime(CLOCK_MONOTONIC, &conn->creation_time); - bsc_mgcp_dlcx(conn); - return conn; - } - } - - - conn = talloc_zero(bsc->nat, struct nat_sccp_connection); - if (!conn) { - LOGP(DNAT, LOGL_ERROR, "Memory allocation failure.\n"); - return NULL; - } - - conn->bsc = bsc; - clock_gettime(CLOCK_MONOTONIC, &conn->creation_time); - conn->real_ref = *parsed->src_local_ref; - if (assign_src_local_reference(&conn->patched_ref, bsc->nat) != 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to assign a ref.\n"); - talloc_free(conn); - return NULL; - } - - bsc_mgcp_init(conn); - llist_add_tail(&conn->list_entry, &bsc->nat->sccp_connections); - rate_ctr_inc(&bsc->cfg->stats.ctrg->ctr[BCFG_CTR_SCCP_CONN]); - osmo_counter_inc(bsc->cfg->nat->stats.sccp.conn); - - LOGP(DNAT, LOGL_DEBUG, "Created 0x%x <-> 0x%x mapping for con %p\n", - sccp_src_ref_to_int(&conn->real_ref), - sccp_src_ref_to_int(&conn->patched_ref), bsc); - - return conn; -} - -int update_sccp_src_ref(struct nat_sccp_connection *sccp, struct bsc_nat_parsed *parsed) -{ - if (!parsed->dest_local_ref || !parsed->src_local_ref) { - LOGP(DNAT, LOGL_ERROR, "CC MSG should contain both local and dest address.\n"); - return -1; - } - - sccp->remote_ref = *parsed->src_local_ref; - sccp->has_remote_ref = 1; - LOGP(DNAT, LOGL_DEBUG, "Updating 0x%x to remote 0x%x on %p\n", - sccp_src_ref_to_int(&sccp->patched_ref), - sccp_src_ref_to_int(&sccp->remote_ref), sccp->bsc); - - return 0; -} - -void remove_sccp_src_ref(struct bsc_connection *bsc, struct msgb *msg, struct bsc_nat_parsed *parsed) -{ - struct nat_sccp_connection *conn; - - llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) { - if (equal(parsed->src_local_ref, &conn->patched_ref)) { - sccp_connection_destroy(conn); - return; - } - } - - LOGP(DNAT, LOGL_ERROR, "Can not remove connection: 0x%x\n", - sccp_src_ref_to_int(parsed->src_local_ref)); -} - -/* - * We have a message from the MSC to the BSC. The MSC is using - * an address that was assigned by the MUX, we need to update the - * dest reference to the real network. - */ -struct nat_sccp_connection *patch_sccp_src_ref_to_bsc(struct msgb *msg, - struct bsc_nat_parsed *parsed, - struct bsc_nat *nat) -{ - struct nat_sccp_connection *conn; - - if (!parsed->dest_local_ref) { - LOGP(DNAT, LOGL_ERROR, "MSG should contain dest_local_ref.\n"); - return NULL; - } - - - llist_for_each_entry(conn, &nat->sccp_connections, list_entry) { - if (!equal(parsed->dest_local_ref, &conn->patched_ref)) - continue; - - /* Change the dest address to the real one */ - *parsed->dest_local_ref = conn->real_ref; - return conn; - } - - return NULL; -} - -/* - * These are message to the MSC. We will need to find the BSC - * Connection by either the SRC or the DST local reference. - * - * In case of a CR we need to work by the SRC local reference - * in all other cases we need to work by the destination local - * reference.. - */ -struct nat_sccp_connection *patch_sccp_src_ref_to_msc(struct msgb *msg, - struct bsc_nat_parsed *parsed, - struct bsc_connection *bsc) -{ - struct nat_sccp_connection *conn; - - llist_for_each_entry(conn, &bsc->nat->sccp_connections, list_entry) { - if (conn->bsc != bsc) - continue; - - if (parsed->src_local_ref) { - if (equal(parsed->src_local_ref, &conn->real_ref)) { - *parsed->src_local_ref = conn->patched_ref; - return conn; - } - } else if (parsed->dest_local_ref) { - if (equal(parsed->dest_local_ref, &conn->remote_ref)) - return conn; - } else { - LOGP(DNAT, LOGL_ERROR, "Header has neither loc/dst ref.\n"); - return NULL; - } - } - - return NULL; -} - -struct nat_sccp_connection *bsc_nat_find_con_by_bsc(struct bsc_nat *nat, - struct sccp_source_reference *ref) -{ - struct nat_sccp_connection *conn; - - llist_for_each_entry(conn, &nat->sccp_connections, list_entry) { - if (equal(ref, &conn->real_ref)) - return conn; - } - - return NULL; -} diff --git a/src/osmo-bsc_nat/bsc_ussd.c b/src/osmo-bsc_nat/bsc_ussd.c deleted file mode 100644 index 985a558dc..000000000 --- a/src/osmo-bsc_nat/bsc_ussd.c +++ /dev/null @@ -1,452 +0,0 @@ -/* USSD Filter Code */ - -/* - * (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010-2011 by On-Waves - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <osmocom/core/socket.h> - -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_nat_sccp.h> -#include <osmocom/bsc/bsc_msg_filter.h> -#include <osmocom/bsc/ipaccess.h> -#include <osmocom/bsc/debug.h> - -#include <osmocom/gsm/protocol/gsm_08_08.h> -#include <osmocom/gsm/gsm0480.h> -#include <osmocom/core/talloc.h> -#include <osmocom/gsm/tlv.h> -#include <osmocom/gsm/ipa.h> -#include <osmocom/gsm/gsm0480.h> - -#include <osmocom/sccp/sccp.h> - -#include <osmocom/abis/ipa.h> - -#include <sys/socket.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> - -#define USSD_LAC_IE 0 -#define USSD_CI_IE 1 - -static void ussd_auth_con(struct tlv_parsed *, struct bsc_nat_ussd_con *); - -static struct bsc_nat_ussd_con *bsc_nat_ussd_alloc(struct bsc_nat *nat) -{ - struct bsc_nat_ussd_con *con; - - con = talloc_zero(nat, struct bsc_nat_ussd_con); - if (!con) - return NULL; - - con->nat = nat; - return con; -} - -static void bsc_nat_ussd_destroy(struct bsc_nat_ussd_con *con) -{ - if (con->nat->ussd_con == con) { - bsc_ussd_close_connections(con->nat); - con->nat->ussd_con = NULL; - } - - close(con->queue.bfd.fd); - osmo_fd_unregister(&con->queue.bfd); - osmo_timer_del(&con->auth_timeout); - osmo_wqueue_clear(&con->queue); - - msgb_free(con->pending_msg); - talloc_free(con); -} - -static void ussd_pong(struct bsc_nat_ussd_con *conn) -{ - struct msgb *msg; - - msg = msgb_alloc_headroom(4096, 128, "pong message"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate pong msg\n"); - return; - } - - msgb_v_put(msg, IPAC_MSGT_PONG); - bsc_do_write(&conn->queue, msg, IPAC_PROTO_IPACCESS); -} - -static int forward_sccp(struct bsc_nat *nat, struct msgb *msg) -{ - struct nat_sccp_connection *con; - struct bsc_nat_parsed *parsed; - - - parsed = bsc_nat_parse(msg); - if (!parsed) { - LOGP(DNAT, LOGL_ERROR, "Can not parse msg from USSD.\n"); - msgb_free(msg); - return -1; - } - - if (!parsed->dest_local_ref) { - LOGP(DNAT, LOGL_ERROR, "No destination local reference.\n"); - msgb_free(msg); - return -1; - } - - con = bsc_nat_find_con_by_bsc(nat, parsed->dest_local_ref); - if (!con || !con->bsc) { - LOGP(DNAT, LOGL_ERROR, "No active connection found.\n"); - msgb_free(msg); - return -1; - } - - talloc_free(parsed); - bsc_write_msg(&con->bsc->write_queue, msg); - return 0; -} - -static int ussd_read_cb(struct osmo_fd *bfd) -{ - struct bsc_nat_ussd_con *conn = bfd->data; - struct msgb *msg = NULL; - struct ipaccess_head *hh; - int ret; - - ret = ipa_msg_recv_buffered(bfd->fd, &msg, &conn->pending_msg); - if (ret <= 0) { - if (ret == -EAGAIN) - return 0; - LOGP(DNAT, LOGL_ERROR, "USSD Connection was lost.\n"); - bsc_nat_ussd_destroy(conn); - return -1; - } - - LOGP(DNAT, LOGL_NOTICE, "MSG from USSD: %s proto: %d\n", - osmo_hexdump(msg->data, msg->len), msg->l2h[0]); - hh = (struct ipaccess_head *) msg->data; - - if (hh->proto == IPAC_PROTO_IPACCESS) { - if (msg->l2h[0] == IPAC_MSGT_ID_RESP) { - struct tlv_parsed tvp; - int ret; - ret = ipa_ccm_idtag_parse(&tvp, - (unsigned char *) msg->l2h + 2, - msgb_l2len(msg) - 2); - if (ret < 0) { - LOGP(DNAT, LOGL_ERROR, "ignoring IPA response " - "message with malformed TLVs\n"); - msgb_free(msg); - return ret; - } - if (TLVP_PRESENT(&tvp, IPAC_IDTAG_UNITNAME)) - ussd_auth_con(&tvp, conn); - } else if (msg->l2h[0] == IPAC_MSGT_PING) { - LOGP(DNAT, LOGL_DEBUG, "Got USSD ping request.\n"); - ussd_pong(conn); - } else { - LOGP(DNAT, LOGL_NOTICE, "Got unknown IPACCESS message 0x%02x.\n", msg->l2h[0]); - } - - msgb_free(msg); - } else if (hh->proto == IPAC_PROTO_SCCP) { - forward_sccp(conn->nat, msg); - } else { - msgb_free(msg); - } - - return 0; -} - -static void ussd_auth_cb(void *_data) -{ - LOGP(DNAT, LOGL_ERROR, "USSD module didn't authenticate\n"); - bsc_nat_ussd_destroy((struct bsc_nat_ussd_con *) _data); -} - -static void ussd_auth_con(struct tlv_parsed *tvp, struct bsc_nat_ussd_con *conn) -{ - const char *token; - int len; - if (!conn->nat->ussd_token) { - LOGP(DNAT, LOGL_ERROR, "No USSD token set. Closing\n"); - bsc_nat_ussd_destroy(conn); - return; - } - - token = (const char *) TLVP_VAL(tvp, IPAC_IDTAG_UNITNAME); - len = TLVP_LEN(tvp, IPAC_IDTAG_UNITNAME); - - /* last byte should be a NULL */ - if (strlen(conn->nat->ussd_token) != len - 1) - goto disconnect; - /* compare everything including the null byte */ - if (memcmp(conn->nat->ussd_token, token, len) != 0) - goto disconnect; - - /* it is authenticated now */ - if (conn->nat->ussd_con && conn->nat->ussd_con != conn) - bsc_nat_ussd_destroy(conn->nat->ussd_con); - - LOGP(DNAT, LOGL_ERROR, "USSD token specified. USSD provider is connected.\n"); - osmo_timer_del(&conn->auth_timeout); - conn->authorized = 1; - conn->nat->ussd_con = conn; - return; - -disconnect: - LOGP(DNAT, LOGL_ERROR, "Wrong USSD token by client: %d\n", - conn->queue.bfd.fd); - bsc_nat_ussd_destroy(conn); -} - -static void ussd_start_auth(struct bsc_nat_ussd_con *conn) -{ - struct msgb *msg; - - osmo_timer_setup(&conn->auth_timeout, ussd_auth_cb, conn); - osmo_timer_schedule(&conn->auth_timeout, conn->nat->auth_timeout, 0); - - msg = msgb_alloc_headroom(4096, 128, "auth message"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate auth msg\n"); - return; - } - - msgb_v_put(msg, IPAC_MSGT_ID_GET); - bsc_do_write(&conn->queue, msg, IPAC_PROTO_IPACCESS); -} - -static int ussd_listen_cb(struct osmo_fd *bfd, unsigned int what) -{ - struct bsc_nat_ussd_con *conn; - struct bsc_nat *nat; - struct sockaddr_in sa; - socklen_t sa_len = sizeof(sa); - int fd; - - if (!(what & BSC_FD_READ)) - return 0; - - fd = accept(bfd->fd, (struct sockaddr *) &sa, &sa_len); - if (fd < 0) { - perror("accept"); - return fd; - } - - nat = (struct bsc_nat *) bfd->data; - osmo_counter_inc(nat->stats.ussd.reconn); - - conn = bsc_nat_ussd_alloc(nat); - if (!conn) { - LOGP(DNAT, LOGL_ERROR, "Failed to allocate USSD con struct.\n"); - close(fd); - return -1; - } - - osmo_wqueue_init(&conn->queue, 10); - conn->queue.bfd.data = conn; - conn->queue.bfd.fd = fd; - conn->queue.bfd.when = BSC_FD_READ; - conn->queue.read_cb = ussd_read_cb; - conn->queue.write_cb = bsc_write_cb; - - if (osmo_fd_register(&conn->queue.bfd) < 0) { - LOGP(DNAT, LOGL_ERROR, "Failed to register USSD fd.\n"); - bsc_nat_ussd_destroy(conn); - return -1; - } - - LOGP(DNAT, LOGL_NOTICE, "USSD Connection on %d with IP: %s\n", - fd, inet_ntoa(sa.sin_addr)); - - /* do authentication */ - ussd_start_auth(conn); - return 0; -} - -int bsc_ussd_init(struct bsc_nat *nat) -{ - nat->ussd_listen.cb = ussd_listen_cb; - nat->ussd_listen.data = nat; - return osmo_sock_init_ofd(&nat->ussd_listen, AF_INET, SOCK_STREAM, IPPROTO_TCP, - nat->ussd_local, 5001, OSMO_SOCK_F_BIND); -} - -static int forward_ussd_simple(struct nat_sccp_connection *con, struct msgb *input) -{ - struct msgb *copy; - struct bsc_nat_ussd_con *ussd; - - if (!con->bsc->nat->ussd_con) - return -1; - - copy = msgb_alloc_headroom(4096, 128, "forward bts"); - if (!copy) { - LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); - return -1; - } - - /* copy the data into the copy */ - copy->l2h = msgb_put(copy, msgb_l2len(input)); - memcpy(copy->l2h, input->l2h, msgb_l2len(input)); - - /* send it out */ - ussd = con->bsc->nat->ussd_con; - bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP); - return 0; -} - -static int forward_ussd(struct nat_sccp_connection *con, const struct ussd_request *req, - struct msgb *input) -{ - struct msgb *msg, *copy; - struct ipac_msgt_sccp_state *state; - struct bsc_nat_ussd_con *ussd; - uint16_t lac, ci; - - if (!con->bsc->nat->ussd_con) - return -1; - - msg = msgb_alloc_headroom(4096, 128, "forward ussd"); - if (!msg) { - LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); - return -1; - } - - copy = msgb_alloc_headroom(4096, 128, "forward bts"); - if (!copy) { - LOGP(DNAT, LOGL_ERROR, "Allocation failed, not forwarding.\n"); - msgb_free(msg); - return -1; - } - - copy->l2h = msgb_put(copy, msgb_l2len(input)); - memcpy(copy->l2h, input->l2h, msgb_l2len(input)); - - msg->l2h = msgb_put(msg, 1); - msg->l2h[0] = IPAC_MSGT_SCCP_OLD; - - /* fill out the data */ - state = (struct ipac_msgt_sccp_state *) msgb_put(msg, sizeof(*state)); - state->trans_id = req->transaction_id; - state->invoke_id = req->invoke_id; - memcpy(&state->src_ref, &con->remote_ref, sizeof(con->remote_ref)); - memcpy(&state->dst_ref, &con->real_ref, sizeof(con->real_ref)); - memcpy(state->imsi, con->filter_state.imsi, strlen(con->filter_state.imsi)); - - /* add additional tag/values */ - lac = htons(con->lac); - ci = htons(con->ci); - msgb_tv_fixed_put(msg, USSD_LAC_IE, sizeof(lac), (const uint8_t *) &lac); - msgb_tv_fixed_put(msg, USSD_CI_IE, sizeof(ci), (const uint8_t *) &ci); - - ussd = con->bsc->nat->ussd_con; - bsc_do_write(&ussd->queue, msg, IPAC_PROTO_IPACCESS); - bsc_do_write(&ussd->queue, copy, IPAC_PROTO_SCCP); - - return 0; -} - -int bsc_ussd_check(struct nat_sccp_connection *con, struct bsc_nat_parsed *parsed, - struct msgb *msg) -{ - uint32_t len; - uint8_t msg_type; - uint8_t proto; - uint8_t ti; - struct gsm48_hdr *hdr48; - struct bsc_msg_acc_lst *lst; - struct ussd_request req; - - /* - * various checks to avoid the decoding work. Right now we only want to - * decode if the connection was created for USSD, we do have a USSD access - * list, a query, a IMSI and such... - */ - if (con->filter_state.con_type != FLT_CON_TYPE_SSA) - return 0; - - if (!con->filter_state.imsi) - return 0; - - /* We have not verified the IMSI yet */ - if (!con->authorized) - return 0; - - if (!con->bsc->nat->ussd_lst_name) - return 0; - if (!con->bsc->nat->ussd_query) - return 0; - - if (parsed->bssap != BSSAP_MSG_DTAP) - return 0; - - if (strlen(con->filter_state.imsi) > GSM23003_IMSI_MAX_DIGITS) - return 0; - - hdr48 = bsc_unpack_dtap(parsed, msg, &len); - if (!hdr48) - return 0; - - proto = gsm48_hdr_pdisc(hdr48); - msg_type = gsm48_hdr_msg_type(hdr48); - ti = gsm48_hdr_trans_id_no_ti(hdr48); - if (proto != GSM48_PDISC_NC_SS) - return 0; - - if (msg_type == GSM0480_MTYPE_REGISTER) { - - /* now check if it is a IMSI we care about */ - lst = bsc_msg_acc_lst_find(&con->bsc->nat->access_lists, - con->bsc->nat->ussd_lst_name); - if (!lst) - return 0; - - if (bsc_msg_acc_lst_check_allow(lst, con->filter_state.imsi) != 0) - return 0; - - /* now decode the message and see if we really want to handle it */ - memset(&req, 0, sizeof(req)); - if (gsm0480_decode_ussd_request(hdr48, len, &req) != 1) - return 0; - if (req.text[0] == 0xff) - return 0; - - if (regexec(&con->bsc->nat->ussd_query_re, - req.text, 0, NULL, 0) == REG_NOMATCH) - return 0; - - /* found a USSD query for our subscriber */ - LOGP(DNAT, LOGL_NOTICE, "Found USSD query for %s\n", - con->filter_state.imsi); - con->ussd_ti[ti] = 1; - if (forward_ussd(con, &req, msg) != 0) - return 0; - return 1; - } else if (msg_type == GSM0480_MTYPE_FACILITY && con->ussd_ti[ti]) { - LOGP(DNAT, LOGL_NOTICE, "Forwarding message part of TI: %d %s\n", - ti, con->filter_state.imsi); - if (forward_ussd_simple(con, msg) != 0) - return 0; - return 1; - } - - return 0; -} diff --git a/tests/Makefile.am b/tests/Makefile.am index 652dfe194..20368ee2f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -5,8 +5,6 @@ SUBDIRS = \ abis \ subscr \ nanobts_omlattr \ - bsc-nat \ - bsc-nat-trie \ bssap \ handover \ $(NULL) diff --git a/tests/bsc-nat-trie/Makefile.am b/tests/bsc-nat-trie/Makefile.am deleted file mode 100644 index 4afa1a4d7..000000000 --- a/tests/bsc-nat-trie/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -AM_CFLAGS=-Wall -ggdb3 $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGSM_CFLAGS) $(LIBOSMOSCCP_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) \ - $(LIBOSMOLEGACYMGCP_CFLAGS) \ - $(NULL) -AM_LDFLAGS = $(COVERAGE_LDFLAGS) - -EXTRA_DIST = bsc_nat_trie_test.ok prefixes.csv - -noinst_PROGRAMS = bsc_nat_trie_test - -bsc_nat_trie_test_SOURCES = bsc_nat_trie_test.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c -bsc_nat_trie_test_LDADD = $(top_builddir)/src/libbsc/libbsc.a \ - $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) -lrt \ - $(LIBOSMOSCCP_LIBS) $(LIBOSMOVTY_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMOLEGACYMGCP_LIBS) \ - $(LIBRARY_GSM) \ - $(NULL) diff --git a/tests/bsc-nat-trie/bsc_nat_trie_test.c b/tests/bsc-nat-trie/bsc_nat_trie_test.c deleted file mode 100644 index 32323d9fa..000000000 --- a/tests/bsc-nat-trie/bsc_nat_trie_test.c +++ /dev/null @@ -1,95 +0,0 @@ -/* - * (C) 2013 by On-Waves - * (C) 2013 by Holger Hans Peter Freyther <zecke@selfish.org> - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include <osmocom/bsc/nat_rewrite_trie.h> -#include <osmocom/bsc/debug.h> - -#include <osmocom/core/application.h> -#include <osmocom/core/backtrace.h> -#include <osmocom/core/talloc.h> -#include <osmocom/core/utils.h> - -#include <string.h> - -static const struct log_info_cat log_categories[] = { -}; - -static const struct log_info log_info = { - .cat = log_categories, - .num_cat = ARRAY_SIZE(log_categories), -}; - -int main(int argc, char **argv) -{ - struct nat_rewrite *trie; - void *tall_ctx = talloc_named_const(NULL, 1, "bsc_nat_trie_test"); - osmo_init_logging2(tall_ctx, &log_info); - - printf("Testing the trie\n"); - - trie = nat_rewrite_parse(NULL, "prefixes.csv"); - OSMO_ASSERT(trie); - - /* verify that it has been parsed */ - OSMO_ASSERT(trie->prefixes == 17); - printf("Dumping the internal trie\n"); - nat_rewrite_dump(trie); - - /* now do the matching... */ - OSMO_ASSERT(!nat_rewrite_lookup(trie, "")); - OSMO_ASSERT(!nat_rewrite_lookup(trie, "2")); - - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1")->rewrite, "1") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12")->rewrite, "2") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "123")->rewrite, "3") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1234")->rewrite, "4") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345")->rewrite, "5") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "123456")->rewrite, "6") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1234567")->rewrite, "7") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345678")->rewrite, "8") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "123456789")->rewrite, "9") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1234567890")->rewrite, "10") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "13")->rewrite, "11") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "14")->rewrite, "12") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "15")->rewrite, "13") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "16")->rewrite, "14") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "823455")->rewrite, "15") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "82")->rewrite, "16") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "+49123445")->rewrite, "17") == 0); - - /* match a prefix */ - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "121")->rewrite, "2") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "1292323")->rewrite, "2") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345678901")->rewrite, "10") == 0); - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "160")->rewrite, "14") == 0); - - OSMO_ASSERT(strcmp(nat_rewrite_lookup(trie, "12345678901123452123123")->rewrite, "10") == 0); - - /* invalid input */ - OSMO_ASSERT(!nat_rewrite_lookup(trie, "12abc")); - - talloc_free(trie); - - trie = nat_rewrite_parse(NULL, "does_not_exist.csv"); - OSMO_ASSERT(!trie); - - printf("Done with the tests.\n"); - return 0; -} diff --git a/tests/bsc-nat-trie/bsc_nat_trie_test.ok b/tests/bsc-nat-trie/bsc_nat_trie_test.ok deleted file mode 100644 index 4d4cc9949..000000000 --- a/tests/bsc-nat-trie/bsc_nat_trie_test.ok +++ /dev/null @@ -1,20 +0,0 @@ -Testing the trie -Dumping the internal trie -1,1 -12,2 -123,3 -1234,4 -12345,5 -123456,6 -1234567,7 -12345678,8 -123456789,9 -1234567890,10 -13,11 -14,12 -15,13 -16,14 -82,16 -823455,15 -+49123,17 -Done with the tests. diff --git a/tests/bsc-nat-trie/prefixes.csv b/tests/bsc-nat-trie/prefixes.csv deleted file mode 100644 index 35485b1a3..000000000 --- a/tests/bsc-nat-trie/prefixes.csv +++ /dev/null @@ -1,25 +0,0 @@ -1,1 -12,2 -123,3 -1234,4 -12345,5 -123456,6 -1234567,7 -12345678,8 -123456789,9 -1234567890,10 -13,11 -14,12 -15,13 -16,14 -823455,15 -82,16 -+49123,17 -1ABC,18 -12345678901234567890,19 -,20 -14A,21 -124,324324324234 -1234567890,10 -no line -99, diff --git a/tests/bsc-nat/Makefile.am b/tests/bsc-nat/Makefile.am deleted file mode 100644 index c2ed6e44c..000000000 --- a/tests/bsc-nat/Makefile.am +++ /dev/null @@ -1,58 +0,0 @@ -AM_CPPFLAGS = \ - $(all_includes) \ - -I$(top_srcdir)/include \ - $(NULL) - -AM_CFLAGS = \ - -Wall \ - -ggdb3 \ - $(LIBOSMOCORE_CFLAGS) \ - $(LIBOSMOGSM_CFLAGS) \ - $(LIBOSMOCTRL_LIBS) \ - $(LIBOSMOSCCP_CFLAGS) \ - $(LIBOSMOABIS_CFLAGS) \ - $(LIBOSMONETIF_CFLAGS) \ - $(LIBOSMOLEGACYMGCP_CFLAGS) \ - $(COVERAGE_CFLAGS) \ - $(NULL) - -AM_LDFLAGS = \ - $(COVERAGE_LDFLAGS) \ - $(NULL) - -EXTRA_DIST = \ - bsc_nat_test.ok \ - bsc_data.c \ - barr.cfg \ - barr_dup.cfg \ - prefixes.csv \ - $(NULL) - -noinst_PROGRAMS = \ - bsc_nat_test \ - $(NULL) - -bsc_nat_test_SOURCES = \ - bsc_nat_test.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_filter.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_sccp.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_utils.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_rewrite_trie.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_mgcp_utils.c \ - $(top_srcdir)/src/osmo-bsc_nat/bsc_nat_filter.c - -bsc_nat_test_LDADD = \ - $(top_builddir)/src/libfilter/libfilter.a \ - $(top_builddir)/src/libbsc/libbsc.a \ - $(LIBOSMOCORE_LIBS) \ - $(LIBOSMOGSM_LIBS) \ - $(LIBOSMOSCCP_LIBS) \ - $(LIBOSMOVTY_LIBS) \ - $(LIBOSMOABIS_LIBS) \ - $(LIBOSMONETIF_LIBS) \ - $(LIBOSMOCTRL_LIBS) \ - $(LIBOSMOLEGACYMGCP_LIBS) \ - $(LIBRARY_GSM) \ - -lrt \ - $(NULL) diff --git a/tests/bsc-nat/barr.cfg b/tests/bsc-nat/barr.cfg deleted file mode 100644 index a9a4a2b31..000000000 --- a/tests/bsc-nat/barr.cfg +++ /dev/null @@ -1,12 +0,0 @@ -12123124:3:2: -12123123:3:1: -12123128:3:6: -12123125:3:3: -12123127:3:5: -12123126:3:4: -12123120:3:4: -12123119:3:4: -12123118:3:4: -12123117:3:4: -12123116:3:4: -12123115:3:4: diff --git a/tests/bsc-nat/barr_dup.cfg b/tests/bsc-nat/barr_dup.cfg deleted file mode 100644 index ea94631ce..000000000 --- a/tests/bsc-nat/barr_dup.cfg +++ /dev/null @@ -1,2 +0,0 @@ -12123124:3:2: -12123124:3:2: diff --git a/tests/bsc-nat/bsc_data.c b/tests/bsc-nat/bsc_data.c deleted file mode 100644 index 3a9f1da62..000000000 --- a/tests/bsc-nat/bsc_data.c +++ /dev/null @@ -1,275 +0,0 @@ -/* test data */ - -/* BSC -> MSC, CR */ -static const uint8_t bsc_cr[] = { -0x00, 0x2e, 0xfd, -0x01, 0x00, 0x00, 0x15, 0x02, 0x02, 0x04, 0x02, -0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05, -0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x1c, 0xc3, -0x51, 0x17, 0x12, 0x05, 0x08, 0x20, 0x72, 0xf4, -0x90, 0x20, 0x1d, 0x50, 0x08, 0x29, 0x47, 0x80, -0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }; - -static const uint8_t bsc_cr_patched[] = { -0x00, 0x2e, 0xfd, -0x01, 0x00, 0x00, 0x05, 0x02, 0x02, 0x04, 0x02, -0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05, -0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x1c, 0xc3, -0x51, 0x17, 0x12, 0x05, 0x08, 0x20, 0x72, 0xf4, -0x90, 0x20, 0x1d, 0x50, 0x08, 0x29, 0x47, 0x80, -0x00, 0x00, 0x00, 0x00, 0x80, 0x00 }; - -/* CC, MSC -> BSC */ -static const uint8_t msc_cc[] = { -0x00, 0x0a, 0xfd, -0x02, 0x00, 0x00, 0x05, 0x01, 0x1f, 0xe4, 0x02, -0x01, 0x00 }; -static const uint8_t msc_cc_patched[] = { -0x00, 0x0a, 0xfd, -0x02, 0x00, 0x00, 0x15, 0x01, 0x1f, 0xe4, 0x02, -0x01, 0x00 }; - -/* Classmark, BSC -> MSC */ -static const uint8_t bsc_dtap[] = { -0x00, 0x17, 0xfd, -0x06, 0x01, 0x1f, 0xe4, 0x00, 0x01, 0x10, 0x00, -0x0e, 0x54, 0x12, 0x03, 0x50, 0x18, 0x93, 0x13, -0x06, 0x60, 0x14, 0x45, 0x00, 0x81, 0x00 }; - -static const uint8_t bsc_dtap_patched[] = { -0x00, 0x17, 0xfd, -0x06, 0x01, 0x1f, 0xe4, 0x00, 0x01, 0x10, 0x00, -0x0e, 0x54, 0x12, 0x03, 0x50, 0x18, 0x93, 0x13, -0x06, 0x60, 0x14, 0x45, 0x00, 0x81, 0x00 }; - -/* Clear command, MSC -> BSC */ -static const uint8_t msc_dtap[] = { -0x00, 0x0d, 0xfd, -0x06, 0x00, 0x00, 0x05, 0x00, 0x01, 0x06, 0x00, -0x04, 0x20, 0x04, 0x01, 0x09 }; -static const uint8_t msc_dtap_patched[] = { -0x00, 0x0d, 0xfd, -0x06, 0x00, 0x00, 0x15, 0x00, 0x01, 0x06, 0x00, -0x04, 0x20, 0x04, 0x01, 0x09 }; - -/*RLSD, MSC -> BSC */ -static const uint8_t msc_rlsd[] = { -0x00, 0x0a, 0xfd, -0x04, 0x00, 0x00, 0x05, 0x01, 0x1f, 0xe4, 0x00, -0x01, 0x00 }; -static const uint8_t msc_rlsd_patched[] = { -0x00, 0x0a, 0xfd, -0x04, 0x00, 0x00, 0x15, 0x01, 0x1f, 0xe4, 0x00, -0x01, 0x00 }; - -/* RLC, BSC -> MSC */ -static const uint8_t bsc_rlc[] = { -0x00, 0x07, 0xfd, -0x05, 0x01, 0x1f, 0xe4, 0x00, 0x00, 0x15 }; - -static const uint8_t bsc_rlc_patched[] = { -0x00, 0x07, 0xfd, -0x05, 0x01, 0x1f, 0xe4, 0x00, 0x00, 0x05 }; - - -/* a paging command */ -static const uint8_t paging_by_lac_cmd[] = { -0x00, 0x22, 0xfd, 0x09, -0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x02, 0x00, -0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x12, 0x00, -0x10, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10, 0x02, -0x01, 0x50, 0x02, 0x30, 0x1a, 0x03, 0x05, 0x20, -0x15 }; - -/* an assignment command */ -static const uint8_t ass_cmd[] = { -0x00, 0x12, 0xfd, 0x06, -0x00, 0x00, 0x49, 0x00, 0x01, 0x0b, 0x00, 0x09, -0x01, 0x0b, 0x03, 0x01, 0x0a, 0x11, 0x01, 0x00, -0x01 }; - -/* identity response */ -static const uint8_t id_resp[] = { -0x00, 0x15, 0xfd, 0x06, 0x01, 0x1c, 0xdc, -0x00, 0x01, 0x0e, 0x01, 0x00, 0x0b, 0x05, 0x59, -0x08, 0x29, 0x40, 0x21, 0x03, 0x07, 0x48, 0x66, -0x31 -}; - -/* sms code msg */ -static const uint8_t smsc_rewrite[] = { -0x00, 0x30, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00, -0x01, 0x29, 0x01, 0x03, 0x26, 0x09, 0x01, 0x23, -0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08, -0x00, 0x10, 0x50, 0x17, 0x21, 0x0c, 0x0f, 0x81, -0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5, -0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca, -0xbf, 0xeb, 0x20 -}; - -static const uint8_t smsc_rewrite_patched[] = { -0x00, 0x31, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00, -0x01, 0x2a, 0x01, 0x03, 0x27, 0x09, 0x01, 0x24, -0x00, 0x0c, 0x00, 0x08, 0x91, 0x66, 0x66, 0x66, -0x66, 0x66, 0x66, 0xf7, 0x17, 0x01, 0x0c, 0x0f, -0x81, 0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46, -0xf5, 0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, -0xca, 0xbf, 0xeb, 0x20 -}; - -static const uint8_t smsc_rewrite_patched_hdr[] = { -0x00, 0x30, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00, -0x01, 0x29, 0x01, 0x03, 0x26, 0x09, 0x01, 0x23, -0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08, -0x00, 0x10, 0x50, 0x17, 0x01, 0x0c, 0x0f, 0x81, -0x00, 0x94, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5, -0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca, -0xbf, 0xeb, 0x20 -}; - -static const uint8_t smsc_rewrite_num_patched[] = { -0x00, 0x2f, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00, -0x01, 0x28, 0x01, 0x03, 0x25, 0x09, 0x01, 0x22, -0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08, -0x00, 0x10, 0x50, 0x16, 0x21, 0x0c, 0x0d, 0x91, - 0x23, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5, -0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca, -0xbf, 0xeb, 0x20 -}; - -static const uint8_t smsc_rewrite_num_patched_tp_srr[] = { -0x00, 0x2f, 0xfd, 0x06, 0x01, 0x13, 0x1e, 0x00, -0x01, 0x28, 0x01, 0x03, 0x25, 0x09, 0x01, 0x22, -0x00, 0x0c, 0x00, 0x07, 0x91, 0x36, 0x19, 0x08, -0x00, 0x10, 0x50, 0x16, 0x01, 0x0c, 0x0d, 0x91, - 0x23, 0x51, 0x87, 0x86, 0x78, 0x46, 0xf5, -0x00, 0x00, 0x09, 0xcc, 0xb7, 0xbd, 0x0c, 0xca, -0xbf, 0xeb, 0x20 -}; - -/* - * MGCP messages - */ - -/* nothing to patch */ -static const char crcx[] = "CRCX 23265295 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n"; -static const char crcx_patched[] = "CRCX 23265295 1e@mgw MGCP 1.0\r\nC: 394b0439fb\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n"; - - -/* patch the ip and port */ -static const char crcx_resp[] = "200 23265295\r\nI: 1\r\n\r\nv=0\r\nc=IN IP4 172.16.18.2\r\nm=audio 4002 RTP/AVP 98 3\r\na=rtpmap:98 AMR/8000\r\n"; -static const char crcx_resp_patched[] = "200 23265295\r\nI: 1\r\n\r\nv=0\r\nc=IN IP4 10.0.0.1\r\nm=audio 999 RTP/AVP 98 3\r\na=rtpmap:98 AMR/8000\r\na=fmtp:98 mode-set=2\r\n"; - -/* patch the ip and port */ -static const char mdcx[] = "MDCX 23330829 8@mgw MGCP 1.0\r\nC: 394b0439fb\r\nI: 1\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 1049380491 0 IN IP4 172.16.18.2\r\ns=-\r\nc=IN IP4 172.16.18.2\r\nt=0 0\r\nm=audio 4410 RTP/AVP 126\r\na=rtpmap:126 AMR/8000/1\r\na=fmtp:126 mode-set=2;start-mode=0\r\na=ptime:20\r\na=recvonly\r\nm=image 4412 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"; -static const char mdcx_patched[] = "MDCX 23330829 1e@mgw MGCP 1.0\r\nC: 394b0439fb\r\nI: 1\r\nL: p:20, a:AMR, nt:IN\r\nM: recvonly\r\n\r\nv=0\r\no=- 1049380491 0 IN IP4 172.16.18.2\r\ns=-\r\nc=IN IP4 10.0.0.23\r\nt=0 0\r\nm=audio 6666 RTP/AVP 126\r\na=rtpmap:126 AMR/8000/1\r\na=fmtp:126 mode-set=2;start-mode=0\r\na=ptime:20\r\na=recvonly\r\nm=image 4412 udptl t38\r\na=T38FaxVersion:0\r\na=T38MaxBitRate:14400\r\n"; - - -static const char mdcx_resp[] = "200 23330829\r\n\r\nv=0\r\nc=IN IP4 172.16.18.2\r\nm=audio 4002 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\n"; -static const char mdcx_resp_patched[] = "200 23330829\r\n\r\nv=0\r\nc=IN IP4 10.0.0.23\r\nm=audio 5555 RTP/AVP 98\r\na=rtpmap:98 AMR/8000\r\na=fmtp:98 mode-set=2\r\n"; - -/* different line ending */ -static const char mdcx_resp2[] = "200 33330829\n\nv=0\nc=IN IP4 172.16.18.2\nm=audio 4002 RTP/AVP 98\na=rtpmap:98 AMR/8000\n"; -static const char mdcx_resp_patched2[] = "200 33330829\n\nv=0\nc=IN IP4 10.0.0.23\nm=audio 5555 RTP/AVP 98\na=rtpmap:98 AMR/8000\na=fmtp:98 mode-set=2\n"; -static const char mdcx_resp_patched2_noamr[] = "200 33330829\n\nv=0\nc=IN IP4 10.0.0.23\nm=audio 5555 RTP/AVP 98\na=rtpmap:98 AMR/8000\n"; - -struct mgcp_patch_test { - const char *orig; - const char *patch; - const char *ip; - const int port; - const int payload_type; - const int ensure_mode_set; -}; - -static const struct mgcp_patch_test mgcp_messages[] = { - { - .orig = crcx, - .patch = crcx_patched, - .ip = "0.0.0.0", - .port = 2323, - .ensure_mode_set = 1, - }, - { - .orig = crcx_resp, - .patch = crcx_resp_patched, - .ip = "10.0.0.1", - .port = 999, - .payload_type = 98, - .ensure_mode_set = 1, - }, - { - .orig = mdcx, - .patch = mdcx_patched, - .ip = "10.0.0.23", - .port = 6666, - .payload_type = 126, - .ensure_mode_set = 1, - }, - { - .orig = mdcx_resp, - .patch = mdcx_resp_patched, - .ip = "10.0.0.23", - .port = 5555, - .payload_type = 98, - .ensure_mode_set = 1, - }, - { - .orig = mdcx_resp2, - .patch = mdcx_resp_patched2, - .ip = "10.0.0.23", - .port = 5555, - .payload_type = 98, - .ensure_mode_set = 1, - }, - { - .orig = mdcx_resp2, - .patch = mdcx_resp_patched2_noamr, - .ip = "10.0.0.23", - .port = 5555, - .payload_type = 98, - .ensure_mode_set = 0, - }, -}; - -/* CC Setup messages */ -static const uint8_t cc_setup_national[] = { - 0x00, 0x20, 0xfd, 0x06, 0x01, 0x12, - 0x6d, 0x00, 0x01, 0x19, 0x01, 0x00, 0x16, 0x03, - 0x05, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, - 0x81, 0x5e, 0x06, 0x81, 0x10, 0x27, 0x33, 0x63, - 0x66, 0x15, 0x02, 0x11, 0x01 -}; - -static const uint8_t cc_setup_national_patched[] = { - 0x00, 0x21, 0xfd, 0x06, 0x01, 0x12, - 0x6d, 0x00, 0x01, 0x1a, 0x01, 0x00, 0x17, 0x03, - 0x05, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, - 0x81, 0x5e, 0x07, 0x91, 0x94, 0x71, 0x32, 0x33, - 0x66, 0xf6, 0x15, 0x02, 0x11, 0x01 -}; - -/* patch the phone number of cc_setup_national_patched */ -static const uint8_t cc_setup_national_patched_patched[] = { - 0x00, 0x21, 0xfd, 0x06, 0x01, 0x12, - 0x6d, 0x00, 0x01, 0x1a, 0x01, 0x00, 0x17, 0x03, - 0x05, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, - 0x81, 0x5e, 0x07, 0x91, 0x63, 0x71, 0x32, 0x33, - 0x66, 0xf6, 0x15, 0x02, 0x11, 0x01 -}; - -static const uint8_t cc_setup_international[] = { - 0x00, 0x22, 0xfd, 0x06, 0x01, 0x13, - 0xe7, 0x00, 0x01, 0x1b, 0x01, 0x00, 0x18, 0x03, - 0x45, 0x04, 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, - 0x81, 0x5e, 0x08, 0x81, 0x00, 0x94, 0x71, 0x33, - 0x63, 0x66, 0x03, 0x15, 0x02, 0x11, 0x01 -}; - -static const uint8_t cc_setup_national_again[] = { - 0x00, 0x22, 0xfd, 0x06, 0x01, 0x12, 0x6d, 0x00, - 0x01, 0x1b, 0x01, 0x00, 0x18, 0x03, 0x05, 0x04, - 0x06, 0x60, 0x04, 0x02, 0x00, 0x05, 0x81, 0x5e, - 0x08, 0x81, 0x63, 0x94, 0x71, 0x32, 0x33, 0x66, - 0xf6, 0x15, 0x02, 0x11, 0x01 -}; diff --git a/tests/bsc-nat/bsc_nat_test.c b/tests/bsc-nat/bsc_nat_test.c deleted file mode 100644 index 7aa39ece7..000000000 --- a/tests/bsc-nat/bsc_nat_test.c +++ /dev/null @@ -1,1595 +0,0 @@ -/* - * BSC NAT Message filtering - * - * (C) 2010-2013 by Holger Hans Peter Freyther <zecke@selfish.org> - * (C) 2010-2013 by On-Waves - * - * All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - - -#include <osmocom/bsc/debug.h> -#include <osmocom/bsc/gsm_data.h> -#include <osmocom/bsc/bsc_nat.h> -#include <osmocom/bsc/bsc_nat_sccp.h> -#include <osmocom/bsc/bsc_msg_filter.h> -#include <osmocom/bsc/nat_rewrite_trie.h> - -#include <osmocom/core/application.h> -#include <osmocom/core/backtrace.h> -#include <osmocom/core/talloc.h> - -#include <osmocom/sccp/sccp.h> -#include <osmocom/gsm/protocol/gsm_08_08.h> - -#include <stdio.h> - -/* test messages for ipa */ -static uint8_t ipa_id[] = { - 0x00, 0x01, 0xfe, 0x06, -}; - -/* SCCP messages are below */ -static uint8_t gsm_reset[] = { - 0x00, 0x12, 0xfd, - 0x09, 0x00, 0x03, 0x05, 0x07, 0x02, 0x42, 0xfe, - 0x02, 0x42, 0xfe, 0x06, 0x00, 0x04, 0x30, 0x04, - 0x01, 0x20, -}; - -static const uint8_t gsm_reset_ack[] = { - 0x00, 0x13, 0xfd, - 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, - 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x03, - 0x00, 0x01, 0x31, -}; - -static const uint8_t gsm_paging[] = { - 0x00, 0x20, 0xfd, - 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x01, - 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10, - 0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x47, 0x10, - 0x02, 0x01, 0x31, 0x97, 0x61, 0x1a, 0x01, 0x06, -}; - -/* BSC -> MSC connection open */ -static const uint8_t bssmap_cr[] = { - 0x00, 0x2c, 0xfd, - 0x01, 0x01, 0x02, 0x03, 0x02, 0x02, 0x04, 0x02, - 0x42, 0xfe, 0x0f, 0x1f, 0x00, 0x1d, 0x57, 0x05, - 0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x12, 0xc3, - 0x50, 0x17, 0x10, 0x05, 0x24, 0x11, 0x03, 0x33, - 0x19, 0xa2, 0x08, 0x29, 0x47, 0x10, 0x02, 0x01, - 0x31, 0x97, 0x61, 0x00 -}; - -/* MSC -> BSC connection confirm */ -static const uint8_t bssmap_cc[] = { - 0x00, 0x0a, 0xfd, - 0x02, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, -}; - -/* MSC -> BSC released */ -static const uint8_t bssmap_released[] = { - 0x00, 0x0e, 0xfd, - 0x04, 0x00, 0x00, 0x03, 0x01, 0x02, 0x03, 0x00, 0x01, 0x0f, - 0x02, 0x23, 0x42, 0x00, -}; - -/* BSC -> MSC released */ -static const uint8_t bssmap_release_complete[] = { - 0x00, 0x07, 0xfd, - 0x05, 0x01, 0x02, 0x03, 0x00, 0x00, 0x03 -}; - -/* both directions IT timer */ -static const uint8_t connnection_it[] = { - 0x00, 0x0b, 0xfd, - 0x10, 0x01, 0x02, 0x03, 0x01, 0x02, 0x03, - 0x00, 0x00, 0x00, 0x00, -}; - -/* error in both directions */ -static const uint8_t proto_error[] = { - 0x00, 0x05, 0xfd, - 0x0f, 0x22, 0x33, 0x44, 0x00, -}; - -/* MGCP wrap... */ -static const uint8_t mgcp_msg[] = { - 0x00, 0x03, 0xfc, - 0x20, 0x20, 0x20, -}; - -/* location updating request */ -static const uint8_t bss_lu[] = { - 0x00, 0x2e, 0xfd, - 0x01, 0x91, 0x45, 0x14, 0x02, 0x02, 0x04, 0x02, - 0x42, 0xfe, 0x0f, 0x21, 0x00, 0x1f, 0x57, 0x05, - 0x08, 0x00, 0x72, 0xf4, 0x80, 0x20, 0x14, 0xc3, - 0x50, 0x17, 0x12, 0x05, 0x08, 0x70, 0x72, 0xf4, - 0x80, 0xff, 0xfe, 0x30, 0x08, 0x29, 0x44, 0x50, - 0x12, 0x03, 0x24, 0x01, 0x95, 0x00 -}; - -/* paging response */ -static const uint8_t pag_resp[] = { - 0x00, 0x2c, 0xfd, 0x01, 0xe5, 0x68, - 0x14, 0x02, 0x02, 0x04, 0x02, 0x42, 0xfe, 0x0f, - 0x1f, 0x00, 0x1d, 0x57, 0x05, 0x08, 0x00, 0x72, - 0xf4, 0x80, 0x20, 0x16, 0xc3, 0x50, 0x17, 0x10, - 0x06, 0x27, 0x01, 0x03, 0x30, 0x18, 0x96, 0x08, - 0x29, 0x26, 0x30, 0x32, 0x11, 0x42, 0x01, 0x19, - 0x00 -}; - -struct filter_result { - const uint8_t *data; - const uint16_t length; - const int dir; - const int result; -}; - -static const struct filter_result results[] = { - { - .data = ipa_id, - .length = ARRAY_SIZE(ipa_id), - .dir = DIR_MSC, - .result = 1, - }, - { - .data = gsm_reset, - .length = ARRAY_SIZE(gsm_reset), - .dir = DIR_MSC, - .result = 1, - }, - { - .data = gsm_reset_ack, - .length = ARRAY_SIZE(gsm_reset_ack), - .dir = DIR_BSC, - .result = 1, - }, - { - .data = gsm_paging, - .length = ARRAY_SIZE(gsm_paging), - .dir = DIR_BSC, - .result = 0, - }, - { - .data = bssmap_cr, - .length = ARRAY_SIZE(bssmap_cr), - .dir = DIR_MSC, - .result = 0, - }, - { - .data = bssmap_cc, - .length = ARRAY_SIZE(bssmap_cc), - .dir = DIR_BSC, - .result = 0, - }, - { - .data = bssmap_released, - .length = ARRAY_SIZE(bssmap_released), - .dir = DIR_MSC, - .result = 0, - }, - { - .data = bssmap_release_complete, - .length = ARRAY_SIZE(bssmap_release_complete), - .dir = DIR_BSC, - .result = 0, - }, - { - .data = mgcp_msg, - .length = ARRAY_SIZE(mgcp_msg), - .dir = DIR_MSC, - .result = 0, - }, - { - .data = connnection_it, - .length = ARRAY_SIZE(connnection_it), - .dir = DIR_BSC, - .result = 0, - }, - { - .data = connnection_it, - .length = ARRAY_SIZE(connnection_it), - .dir = DIR_MSC, - .result = 0, - }, - { - .data = proto_error, - .length = ARRAY_SIZE(proto_error), - .dir = DIR_BSC, - .result = 0, - }, - { - .data = proto_error, - .length = ARRAY_SIZE(proto_error), - .dir = DIR_MSC, - .result = 0, - }, - -}; - -static void test_filter(void) -{ - int i; - - - /* start testinh with proper messages */ - printf("Testing BSS Filtering.\n"); - for (i = 0; i < ARRAY_SIZE(results); ++i) { - int result; - struct bsc_nat_parsed *parsed; - struct msgb *msg = msgb_alloc(4096, "test-message"); - - printf("Going to test item: %d\n", i); - memcpy(msg->data, results[i].data, results[i].length); - msg->l2h = msgb_put(msg, results[i].length); - - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Failed to parse the message\n"); - continue; - } - - result = bsc_nat_filter_ipa(results[i].dir, msg, parsed); - if (result != results[i].result) { - printf("FAIL: Not the expected result got: %d wanted: %d\n", - result, results[i].result); - } - - msgb_free(msg); - } -} - -#include "bsc_data.c" - -static void copy_to_msg(struct msgb *msg, const uint8_t *data, unsigned int length) -{ - msgb_reset(msg); - msg->l2h = msgb_put(msg, length); - memcpy(msg->l2h, data, msgb_l2len(msg)); -} - -static void verify_msg(struct msgb *out, const uint8_t *ref, int ref_len) -{ - if (out->len != ref_len) { - printf("FAIL: The size should match: %d vs. %d\n", - out->len, ref_len); - printf("%s\n", osmo_hexdump(out->data, out->len)); - printf("Wanted\n"); - printf("%s\n", osmo_hexdump(ref, ref_len)); - abort(); - } - - if (memcmp(out->data, ref, out->len) != 0) { - printf("FAIL: the data should be changed.\n"); - printf("%s\n", osmo_hexdump(out->data, out->len)); - printf("Wanted\n"); - printf("%s\n", osmo_hexdump(ref, ref_len)); - abort(); - } -} - - -#define VERIFY(con_found, con, msg, ver, str) \ - if (!con_found) { \ - printf("Failed to find connection.\n"); \ - abort(); \ - } \ - if (con_found->bsc != con) { \ - printf("Got connection of the wrong BSC: %d\n", \ - con_found->bsc->cfg->nr); \ - abort(); \ - } \ - if (memcmp(msg->data, ver, sizeof(ver)) != 0) { \ - printf("Failed to patch the %s msg.\n", str); \ - abort(); \ - } - -/* test conn tracking once */ -static void test_contrack() -{ - struct bsc_nat *nat; - struct bsc_connection *con; - struct nat_sccp_connection *con_found; - struct nat_sccp_connection *rc_con; - struct bsc_nat_parsed *parsed; - struct msgb *msg; - - printf("Testing connection tracking.\n"); - nat = bsc_nat_alloc(); - con = bsc_connection_alloc(nat); - con->cfg = bsc_config_alloc(nat, "foo", 0); - bsc_config_add_lac(con->cfg, 23); - bsc_config_add_lac(con->cfg, 49); - bsc_config_add_lac(con->cfg, 42); - bsc_config_del_lac(con->cfg, 49); - bsc_config_add_lac(con->cfg, 1111); - msg = msgb_alloc(4096, "test"); - - /* 1.) create a connection */ - copy_to_msg(msg, bsc_cr, sizeof(bsc_cr)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_msc(msg, parsed, con); - if (con_found != NULL) { - printf("Con should not exist realref(%u)\n", - sccp_src_ref_to_int(&con_found->real_ref)); - abort(); - } - rc_con = create_sccp_src_ref(con, parsed); - if (!rc_con) { - printf("Failed to create a ref\n"); - abort(); - } - con_found = patch_sccp_src_ref_to_msc(msg, parsed, con); - if (!con_found) { - printf("Failed to find connection.\n"); - abort(); - } - if (con_found->bsc != con) { - printf("Got connection of the wrong BSC: %d\n", - con_found->bsc->cfg->nr); - abort(); - } - if (con_found != rc_con) { - printf("Failed to find the right connection.\n"); - abort(); - } - if (memcmp(msg->data, bsc_cr_patched, sizeof(bsc_cr_patched)) != 0) { - printf("Failed to patch the BSC CR msg.\n"); - abort(); - } - talloc_free(parsed); - - /* 2.) get the cc */ - copy_to_msg(msg, msc_cc, sizeof(msc_cc)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat); - VERIFY(con_found, con, msg, msc_cc_patched, "MSC CC"); - if (update_sccp_src_ref(con_found, parsed) != 0) { - printf("Failed to update the SCCP con.\n"); - abort(); - } - - /* 3.) send some data */ - copy_to_msg(msg, bsc_dtap, sizeof(bsc_dtap)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_msc(msg, parsed, con); - VERIFY(con_found, con, msg, bsc_dtap_patched, "BSC DTAP"); - - /* 4.) receive some data */ - copy_to_msg(msg, msc_dtap, sizeof(msc_dtap)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat); - VERIFY(con_found, con, msg, msc_dtap_patched, "MSC DTAP"); - - /* 5.) close the connection */ - copy_to_msg(msg, msc_rlsd, sizeof(msc_rlsd)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_bsc(msg, parsed, nat); - VERIFY(con_found, con, msg, msc_rlsd_patched, "MSC RLSD"); - - /* 6.) confirm the connection close */ - copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_msc(msg, parsed, con); - if (!con_found) { - printf("Failed to find connection.\n"); - abort(); - } - if (con_found->bsc != con) { - printf("Got connection of the wrong BSC: %d\n", - con_found->bsc->cfg->nr); - abort(); - } - if (memcmp(msg->data, bsc_rlc_patched, sizeof(bsc_rlc_patched)) != 0) { - printf("Failed to patch the BSC CR msg.\n"); - abort(); - } - remove_sccp_src_ref(con, msg, parsed); - talloc_free(parsed); - - copy_to_msg(msg, bsc_rlc, sizeof(bsc_rlc)); - parsed = bsc_nat_parse(msg); - con_found = patch_sccp_src_ref_to_msc(msg, parsed, con); - - /* verify that it is gone */ - if (con_found != NULL) { - printf("Con should not exist real_ref(%u)\n", - sccp_src_ref_to_int(&con_found->real_ref)); - abort(); - } - talloc_free(parsed); - - - bsc_config_free(con->cfg); - bsc_nat_free(nat); - msgb_free(msg); -} - -static void test_paging(void) -{ - struct bsc_nat *nat; - struct bsc_connection *con; - struct bsc_config *cfg; - - printf("Testing paging by lac.\n"); - - nat = bsc_nat_alloc(); - con = bsc_connection_alloc(nat); - cfg = bsc_config_alloc(nat, "unknown", 0); - con->cfg = cfg; - bsc_config_add_lac(cfg, 23); - con->authenticated = 1; - llist_add(&con->list_entry, &nat->bsc_connections); - - /* Test it by not finding it */ - if (bsc_config_handles_lac(cfg, 8213) != 0) { - printf("Should not be handled.\n"); - abort(); - } - - /* Test by finding it */ - bsc_config_del_lac(cfg, 23); - bsc_config_add_lac(cfg, 8213); - if (bsc_config_handles_lac(cfg, 8213) == 0) { - printf("Should have found it.\n"); - abort(); - } - - bsc_nat_free(nat); -} - -static void test_mgcp_allocations(void) -{ -#if 0 - struct bsc_connection *bsc; - struct bsc_nat *nat; - struct nat_sccp_connection con; - int i, j, multiplex; - - printf("Testing MGCP.\n"); - memset(&con, 0, sizeof(con)); - - nat = bsc_nat_alloc(); - nat->bsc_endpoints = talloc_zero_array(nat, - struct bsc_endpoint, - 65); - nat->mgcp_cfg = mgcp_config_alloc(); - nat->mgcp_cfg->trunk.number_endpoints = 64; - - bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo", 0); - bsc->cfg->max_endpoints = 60; - bsc_config_add_lac(bsc->cfg, 2323); - bsc->last_endpoint = 0x22; - con.bsc = bsc; - - bsc_init_endps_if_needed(bsc); - - i = 1; - do { - if (bsc_assign_endpoint(bsc, &con) != 0) { - printf("failed to allocate... on iteration %d\n", i); - break; - } - ++i; - } while(1); - - multiplex = bsc_mgcp_nr_multiplexes(bsc->cfg->max_endpoints); - for (i = 0; i < multiplex; ++i) { - for (j = 0; j < 32; ++j) - printf("%d", bsc->_endpoint_status[i*32 + j]); - printf(": %d of %d\n", i*32 + 32, 32 * 8); - } -#endif -} - -static void test_mgcp_ass_tracking(void) -{ - struct bsc_connection *bsc; - struct bsc_nat *nat; - struct nat_sccp_connection con; - struct bsc_nat_parsed *parsed; - struct msgb *msg; - - printf("Testing MGCP.\n"); - memset(&con, 0, sizeof(con)); - - nat = bsc_nat_alloc(); - nat->bsc_endpoints = talloc_zero_array(nat, - struct bsc_endpoint, - 33); - nat->mgcp_cfg = mgcp_config_alloc(); - nat->mgcp_cfg->trunk.number_endpoints = 64; - mgcp_endpoints_allocate(&nat->mgcp_cfg->trunk); - - bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo", 0); - bsc_config_add_lac(bsc->cfg, 2323); - bsc->last_endpoint = 0x1e; - con.bsc = bsc; - - msg = msgb_alloc(4096, "foo"); - copy_to_msg(msg, ass_cmd, sizeof(ass_cmd)); - parsed = bsc_nat_parse(msg); - - if (msg->l2h[16] != 0 || - msg->l2h[17] != 0x1) { - printf("Input is not as expected.. %s 0x%x\n", - osmo_hexdump(msg->l2h, msgb_l2len(msg)), - msg->l2h[17]); - abort(); - } - - if (bsc_mgcp_assign_patch(&con, msg) != 0) { - printf("Failed to handle assignment.\n"); - abort(); - } - - if (con.msc_endp != 1) { - printf("Timeslot should be 1.\n"); - abort(); - } - - if (con.bsc_endp != 0x1) { - printf("Assigned timeslot should have been 1.\n"); - abort(); - } - if (con.bsc->_endpoint_status[0x1] != 1) { - printf("The status on the BSC is wrong.\n"); - abort(); - } - - int multiplex, timeslot; - mgcp_endpoint_to_timeslot(0x1, &multiplex, ×lot); - - uint16_t cic = htons(timeslot & 0x1f); - if (memcmp(&cic, &msg->l2h[16], sizeof(cic)) != 0) { - printf("Message was not patched properly\n"); - printf("data cic: 0x%x %s\n", cic, osmo_hexdump(msg->l2h, msgb_l2len(msg))); - abort(); - } - - talloc_free(parsed); - - bsc_mgcp_dlcx(&con); - if (con.bsc_endp != -1 || con.msc_endp != -1 || - con.bsc->_endpoint_status[1] != 0 || con.bsc->last_endpoint != 0x1) { - printf("Clearing should remove the mapping.\n"); - abort(); - } - - bsc_config_free(bsc->cfg); - bsc_nat_free(nat); -} - -/* test the code to find a given connection */ -static void test_mgcp_find(void) -{ - struct bsc_nat *nat; - struct bsc_connection *con; - struct nat_sccp_connection *sccp_con; - - printf("Testing finding of a BSC Connection\n"); - - nat = bsc_nat_alloc(); - con = bsc_connection_alloc(nat); - llist_add(&con->list_entry, &nat->bsc_connections); - - sccp_con = talloc_zero(con, struct nat_sccp_connection); - sccp_con->msc_endp = 12; - sccp_con->bsc_endp = 12; - sccp_con->bsc = con; - llist_add(&sccp_con->list_entry, &nat->sccp_connections); - - if (bsc_mgcp_find_con(nat, 11) != NULL) { - printf("Found the wrong connection.\n"); - abort(); - } - - if (bsc_mgcp_find_con(nat, 12) != sccp_con) { - printf("Didn't find the connection\n"); - abort(); - } - - /* free everything */ - bsc_nat_free(nat); -} - -static void test_mgcp_rewrite(void) -{ - int i; - struct msgb *output; - printf("Testing rewriting MGCP messages.\n"); - - for (i = 0; i < ARRAY_SIZE(mgcp_messages); ++i) { - const char *orig = mgcp_messages[i].orig; - const char *patc = mgcp_messages[i].patch; - const char *ip = mgcp_messages[i].ip; - const int port = mgcp_messages[i].port; - const int expected_payload_type = mgcp_messages[i].payload_type; - const int ensure_mode_set = mgcp_messages[i].ensure_mode_set; - int payload_type = -1; - - char *input = strdup(orig); - - output = bsc_mgcp_rewrite(input, strlen(input), 0x1e, - ip, port, -1, &payload_type, ensure_mode_set); - - if (payload_type != -1) { - fprintf(stderr, "Found media payload type %d in SDP data\n", - payload_type); - if (payload_type != expected_payload_type) { - printf("Wrong payload type %d (expected %d)\n", - payload_type, expected_payload_type); - abort(); - } - } - - if (msgb_l2len(output) != strlen(patc)) { - printf("Wrong sizes for test: %d %u != %zu != %zu\n", i, msgb_l2len(output), strlen(patc), strlen(orig)); - printf("String '%s' vs '%s'\n", (const char *) output->l2h, patc); - abort(); - } - - if (memcmp(output->l2h, patc, msgb_l2len(output)) != 0) { - printf("Broken on %d msg: '%s'\n", i, (const char *) output->l2h); - abort(); - } - - msgb_free(output); - free(input); - } -} - -static void test_mgcp_parse(void) -{ - int code, ci; - char transaction[60]; - - printf("Testing MGCP response parsing.\n"); - - if (bsc_mgcp_parse_response(crcx_resp, &code, transaction) != 0) { - printf("Failed to parse CRCX resp.\n"); - abort(); - } - - if (code != 200) { - printf("Failed to parse the CODE properly. Got: %d\n", code); - abort(); - } - - if (strcmp(transaction, "23265295") != 0) { - printf("Failed to parse transaction id: '%s'\n", transaction); - abort(); - } - - ci = bsc_mgcp_extract_ci(crcx_resp); - if (ci != 1) { - printf("Failed to parse the CI. Got: %d\n", ci); - abort(); - } -} - -struct cr_filter { - const uint8_t *data; - int length; - int result; - int contype; - - const char *bsc_imsi_allow; - const char *bsc_imsi_deny; - const char *nat_imsi_deny; - int nat_cm_reject_cause; - int nat_lu_reject_cause; - int bsc_cm_reject_cause; - int bsc_lu_reject_cause; - int want_cm_reject_cause; - int want_lu_reject_cause; -}; - -static struct cr_filter cr_filter[] = { - { - .data = bssmap_cr, - .length = sizeof(bssmap_cr), - .result = 1, - .contype = FLT_CON_TYPE_CM_SERV_REQ, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - .data = bss_lu, - .length = sizeof(bss_lu), - .result = 1, - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - .data = pag_resp, - .length = sizeof(pag_resp), - .result = 1, - .contype = FLT_CON_TYPE_PAG_RESP, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* nat deny is before blank/null BSC */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = -3, - .nat_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* BSC allow is before NAT deny */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = 1, - .nat_imsi_deny = "[0-9]*", - .bsc_imsi_allow = "2440[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* BSC allow is before NAT deny */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = 1, - .bsc_imsi_allow = "[0-9]*", - .nat_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* filter as deny is first */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = 1, - .bsc_imsi_deny = "[0-9]*", - .bsc_imsi_allow = "[0-9]*", - .nat_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* deny by nat rule */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = -3, - .bsc_imsi_deny = "000[0-9]*", - .nat_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* deny by nat rule */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = -3, - .bsc_imsi_deny = "000[0-9]*", - .nat_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = 0x23, - .nat_lu_reject_cause = 0x42, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = 0x42, - .want_cm_reject_cause = 0x23, - }, - { - /* deny by bsc rule */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = -2, - .bsc_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .want_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - }, - { - /* deny by bsc rule */ - .data = bss_lu, - .length = sizeof(bss_lu), - .result = -2, - .bsc_imsi_deny = "[0-9]*", - .contype = FLT_CON_TYPE_LU, - .nat_cm_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .nat_lu_reject_cause = GSM48_REJECT_PLMN_NOT_ALLOWED, - .bsc_cm_reject_cause = 0x42, - .bsc_lu_reject_cause = 0x23, - .want_lu_reject_cause = 0x23, - .want_cm_reject_cause = 0x42, - }, -}; - -static void test_cr_filter() -{ - int i, res, contype; - struct msgb *msg = msgb_alloc(4096, "test_cr_filter"); - struct bsc_nat_parsed *parsed; - struct bsc_msg_acc_lst *nat_lst, *bsc_lst; - struct bsc_msg_acc_lst_entry *nat_entry, *bsc_entry; - struct bsc_filter_reject_cause cause; - - struct bsc_nat *nat = bsc_nat_alloc(); - struct bsc_connection *bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo", 0); - bsc_config_add_lac(bsc->cfg, 1234); - bsc->cfg->acc_lst_name = "bsc"; - nat->acc_lst_name = "nat"; - - nat_lst = bsc_msg_acc_lst_get(nat, &nat->access_lists, "nat"); - bsc_lst = bsc_msg_acc_lst_get(nat, &nat->access_lists, "bsc"); - - bsc_entry = bsc_msg_acc_lst_entry_create(bsc_lst); - nat_entry = bsc_msg_acc_lst_entry_create(nat_lst); - - /* test the default value as we are going to overwrite it */ - OSMO_ASSERT(bsc_entry->cm_reject_cause == GSM48_REJECT_PLMN_NOT_ALLOWED); - OSMO_ASSERT(bsc_entry->lu_reject_cause == GSM48_REJECT_PLMN_NOT_ALLOWED); - - for (i = 0; i < ARRAY_SIZE(cr_filter); ++i) { - char *imsi; - msgb_reset(msg); - copy_to_msg(msg, cr_filter[i].data, cr_filter[i].length); - - bsc_entry->cm_reject_cause = cr_filter[i].bsc_cm_reject_cause; - bsc_entry->lu_reject_cause = cr_filter[i].bsc_lu_reject_cause; - nat_entry->cm_reject_cause = cr_filter[i].nat_cm_reject_cause; - nat_entry->lu_reject_cause = cr_filter[i].nat_lu_reject_cause; - - if (gsm_parse_reg(nat_entry, &nat_entry->imsi_deny_re, &nat_entry->imsi_deny, - cr_filter[i].nat_imsi_deny ? 1 : 0, - &cr_filter[i].nat_imsi_deny) != 0) - abort(); - if (gsm_parse_reg(bsc_entry, &bsc_entry->imsi_allow_re, &bsc_entry->imsi_allow, - cr_filter[i].bsc_imsi_allow ? 1 : 0, - &cr_filter[i].bsc_imsi_allow) != 0) - abort(); - if (gsm_parse_reg(bsc_entry, &bsc_entry->imsi_deny_re, &bsc_entry->imsi_deny, - cr_filter[i].bsc_imsi_deny ? 1 : 0, - &cr_filter[i].bsc_imsi_deny) != 0) - abort(); - - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Failed to parse the message\n"); - abort(); - } - - memset(&cause, 0, sizeof(cause)); - res = bsc_nat_filter_sccp_cr(bsc, msg, parsed, &contype, &imsi, &cause); - if (res != cr_filter[i].result) { - printf("FAIL: Wrong result %d for test %d.\n", res, i); - abort(); - } - - - OSMO_ASSERT(cause.cm_reject_cause == cr_filter[i].want_cm_reject_cause); - OSMO_ASSERT(cause.lu_reject_cause == cr_filter[i].want_lu_reject_cause); - - if (contype != cr_filter[i].contype) { - printf("FAIL: Wrong contype %d for test %d.\n", res, contype); - abort(); - } - - talloc_steal(parsed, imsi); - talloc_free(parsed); - } - - msgb_free(msg); - bsc_nat_free(nat); -} - -static void test_dt_filter() -{ - int i; - struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); - struct bsc_nat_parsed *parsed; - struct bsc_filter_reject_cause cause; - - struct bsc_nat *nat = bsc_nat_alloc(); - struct bsc_connection *bsc = bsc_connection_alloc(nat); - struct nat_sccp_connection *con = talloc_zero(0, struct nat_sccp_connection); - - bsc->cfg = bsc_config_alloc(nat, "foo", 0); - bsc_config_add_lac(bsc->cfg, 23); - con->bsc = bsc; - - msgb_reset(msg); - copy_to_msg(msg, id_resp, ARRAY_SIZE(id_resp)); - - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - if (parsed->bssap != BSSAP_MSG_DTAP) { - printf("FAIL: It should be dtap\n"); - abort(); - } - - /* gsm_type is actually the size of the dtap */ - if (parsed->gsm_type < msgb_l3len(msg) - 3) { - printf("FAIL: Not enough space for the content\n"); - abort(); - } - - memset(&cause, 0, sizeof(cause)); - OSMO_ASSERT(!con->filter_state.imsi); - if (bsc_nat_filter_dt(bsc, msg, con, parsed, &cause) != 1) { - printf("FAIL: Should have passed..\n"); - abort(); - } - OSMO_ASSERT(con->filter_state.imsi); - OSMO_ASSERT(talloc_parent(con->filter_state.imsi) == con); - - /* just some basic length checking... */ - for (i = ARRAY_SIZE(id_resp); i >= 0; --i) { - msgb_reset(msg); - copy_to_msg(msg, id_resp, ARRAY_SIZE(id_resp)); - - parsed = bsc_nat_parse(msg); - if (!parsed) - continue; - - con->filter_state.imsi_checked = 0; - memset(&cause, 0, sizeof(cause)); - bsc_nat_filter_dt(bsc, msg, con, parsed, &cause); - } - - msgb_free(msg); - bsc_nat_free(nat); -} - -static void test_setup_rewrite() -{ - struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); - struct msgb *out; - struct bsc_nat_parsed *parsed; - const char *imsi = "27408000001234"; - - struct bsc_nat *nat = bsc_nat_alloc(); - - /* a fake list */ - struct osmo_config_list entries; - struct osmo_config_entry entry; - - INIT_LLIST_HEAD(&entries.entry); - entry.mcc = "274"; - entry.mnc = "08"; - entry.option = "^0([1-9])"; - entry.text = "0049"; - llist_add_tail(&entry.list, &entries.entry); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - - /* verify that nothing changed */ - msgb_reset(msg); - copy_to_msg(msg, cc_setup_international, ARRAY_SIZE(cc_setup_international)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (msg != out) { - printf("FAIL: The message should not have been changed\n"); - abort(); - } - - verify_msg(out, cc_setup_international, ARRAY_SIZE(cc_setup_international)); - talloc_free(parsed); - - /* verify that something in the message changes */ - msgb_reset(msg); - copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created.\n"); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed\n"); - abort(); - } - - verify_msg(out, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); - msgb_free(out); - - /* Make sure that a wildcard is matching */ - entry.mnc = "*"; - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - msg = msgb_alloc(4096, "test_dt_filter"); - copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created.\n"); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed\n"); - abort(); - } - - verify_msg(out, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); - msgb_free(out); - - /* Make sure that a wildcard is matching */ - entry.mnc = "09"; - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - msg = msgb_alloc(4096, "test_dt_filter"); - copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out != msg) { - printf("FAIL: The message should be unchanged.\n"); - abort(); - } - - verify_msg(out, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - msgb_free(out); - - /* Now see what happens to an international number */ - entry.mnc = "*"; - entry.option = "^\\+[0-9][0-9]([1-9])"; - entry.text = "0036"; - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - msg = msgb_alloc(4096, "test_dt_filter"); - copy_to_msg(msg, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp %d\n", __LINE__); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created %d.\n", __LINE__); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed %d\n", __LINE__); - abort(); - } - - verify_msg(out, cc_setup_national_patched_patched, - ARRAY_SIZE(cc_setup_national_patched_patched)); - msgb_free(out); - - /* go from international back to national */ - entry.mnc = "*"; - entry.option = "^\\+([0-9])"; - entry.text = "36"; - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - msg = msgb_alloc(4096, "test_dt_filter"); - copy_to_msg(msg, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp %d\n", __LINE__); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created %d.\n", __LINE__); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed %d\n", __LINE__); - abort(); - } - - verify_msg(out, cc_setup_national_again, - ARRAY_SIZE(cc_setup_national_again)); - msgb_free(out); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL); - bsc_nat_free(nat); -} - -static void test_setup_rewrite_prefix(void) -{ - struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); - struct msgb *out; - struct bsc_nat_parsed *parsed; - const char *imsi = "27408000001234"; - - struct bsc_nat *nat = bsc_nat_alloc(); - - /* a fake list */ - struct osmo_config_list entries; - struct osmo_config_entry entry; - - INIT_LLIST_HEAD(&entries.entry); - entry.mcc = "274"; - entry.mnc = "08"; - entry.option = "^0([1-9])"; - entry.text = "prefix_lookup"; - llist_add_tail(&entry.list, &entries.entry); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - - nat->num_rewr_trie = nat_rewrite_parse(nat, "prefixes.csv"); - - msgb_reset(msg); - copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created.\n"); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed\n"); - abort(); - } - - verify_msg(out, cc_setup_national_patched, ARRAY_SIZE(cc_setup_national_patched)); - msgb_free(out); - - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, NULL); - bsc_nat_free(nat); -} - -static void test_setup_rewrite_post(void) -{ - struct msgb *msg = msgb_alloc(4096, "test_dt_filter"); - struct msgb *out; - struct bsc_nat_parsed *parsed; - const char *imsi = "27408000001234"; - - struct bsc_nat *nat = bsc_nat_alloc(); - - /* a fake list */ - struct osmo_config_list entries; - struct osmo_config_entry entry; - struct osmo_config_list entries_post; - struct osmo_config_entry entry_post; - - INIT_LLIST_HEAD(&entries.entry); - entry.mcc = "274"; - entry.mnc = "08"; - entry.option = "^0([1-9])"; - entry.text = "0049"; - llist_add_tail(&entry.list, &entries.entry); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr, &entries); - - /* attempt to undo the previous one */ - INIT_LLIST_HEAD(&entries_post.entry); - entry_post.mcc = "274"; - entry_post.mnc = "08"; - entry_post.option = "^\\+49([1-9])"; - entry_post.text = "prefix_lookup"; - llist_add_tail(&entry_post.list, &entries_post.entry); - bsc_nat_num_rewr_entry_adapt(nat, &nat->num_rewr_post, &entries_post); - - nat->num_rewr_trie = nat_rewrite_parse(nat, "prefixes.csv"); - - msgb_reset(msg); - copy_to_msg(msg, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse ID resp\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (!out) { - printf("FAIL: A new message should be created.\n"); - abort(); - } - - if (msg == out) { - printf("FAIL: The message should have changed\n"); - abort(); - } - - verify_msg(out, cc_setup_national, ARRAY_SIZE(cc_setup_national)); - msgb_free(out); - - bsc_nat_free(nat); -} - -static void test_sms_smsc_rewrite() -{ - struct msgb *msg = msgb_alloc(4096, "SMSC rewrite"), *out; - struct bsc_nat_parsed *parsed; - const char *imsi = "515039900406700"; - - struct bsc_nat *nat = bsc_nat_alloc(); - - /* a fake list */ - struct osmo_config_list smsc_entries, dest_entries, clear_entries; - struct osmo_config_entry smsc_entry, dest_entry, clear_entry; - - INIT_LLIST_HEAD(&smsc_entries.entry); - INIT_LLIST_HEAD(&dest_entries.entry); - INIT_LLIST_HEAD(&clear_entries.entry); - smsc_entry.mcc = "^515039"; - smsc_entry.option = "639180000105()"; - smsc_entry.text = "6666666666667"; - llist_add_tail(&smsc_entry.list, &smsc_entries.entry); - dest_entry.mcc = "515"; - dest_entry.mnc = "03"; - dest_entry.option = "^0049"; - dest_entry.text = ""; - llist_add_tail(&dest_entry.list, &dest_entries.entry); - clear_entry.mcc = "^515039"; - clear_entry.option = "^0049"; - clear_entry.text = ""; - llist_add_tail(&clear_entry.list, &clear_entries.entry); - - bsc_nat_num_rewr_entry_adapt(nat, &nat->smsc_rewr, &smsc_entries); - bsc_nat_num_rewr_entry_adapt(nat, &nat->tpdest_match, &dest_entries); - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_clear_tp_srr, &clear_entries); - - printf("Testing SMSC rewriting.\n"); - - /* - * Check if the SMSC address is changed - */ - copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse SMS\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out == msg) { - printf("FAIL: This should have changed.\n"); - abort(); - } - - verify_msg(out, smsc_rewrite_patched, ARRAY_SIZE(smsc_rewrite_patched)); - msgb_free(out); - - /* clear out the filter for SMSC */ - printf("Attempting to only rewrite the HDR\n"); - bsc_nat_num_rewr_entry_adapt(nat, &nat->smsc_rewr, NULL); - msg = msgb_alloc(4096, "SMSC rewrite"); - copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse SMS\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out == msg) { - printf("FAIL: This should have changed.\n"); - abort(); - } - - verify_msg(out, smsc_rewrite_patched_hdr, ARRAY_SIZE(smsc_rewrite_patched_hdr)); - msgb_free(out); - - /* clear out the next filter */ - printf("Attempting to change nothing.\n"); - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_clear_tp_srr, NULL); - msg = msgb_alloc(4096, "SMSC rewrite"); - copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse SMS\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out != msg) { - printf("FAIL: This should not have changed.\n"); - abort(); - } - - verify_msg(out, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - msgb_free(out); - bsc_nat_free(nat); -} - -static void test_sms_number_rewrite(void) -{ - struct msgb *msg, *out; - struct bsc_nat_parsed *parsed; - const char *imsi = "515039900406700"; - - struct bsc_nat *nat = bsc_nat_alloc(); - - /* a fake list */ - struct osmo_config_list num_entries, clear_entries; - struct osmo_config_entry num_entry, clear_entry; - - INIT_LLIST_HEAD(&num_entries.entry); - num_entry.mcc = "^515039"; - num_entry.option = "^0049()"; - num_entry.text = "0032"; - llist_add_tail(&num_entry.list, &num_entries.entry); - - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_num_rewr, &num_entries); - - printf("Testing SMS TP-DA rewriting.\n"); - - /* - * Check if the SMSC address is changed - */ - msg = msgb_alloc(4096, "SMSC rewrite"); - copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse SMS\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out == msg) { - printf("FAIL: This should have changed.\n"); - abort(); - } - - verify_msg(out, smsc_rewrite_num_patched, - ARRAY_SIZE(smsc_rewrite_num_patched)); - msgb_free(out); - - /* - * Now with TP-SRR rewriting enabled - */ - INIT_LLIST_HEAD(&clear_entries.entry); - clear_entry.mcc = "^515039"; - clear_entry.option = ""; - clear_entry.text = ""; - llist_add_tail(&clear_entry.list, &clear_entries.entry); - bsc_nat_num_rewr_entry_adapt(nat, &nat->sms_clear_tp_srr, &clear_entries); - - msg = msgb_alloc(4096, "SMSC rewrite"); - copy_to_msg(msg, smsc_rewrite, ARRAY_SIZE(smsc_rewrite)); - parsed = bsc_nat_parse(msg); - if (!parsed) { - printf("FAIL: Could not parse SMS\n"); - abort(); - } - - out = bsc_nat_rewrite_msg(nat, msg, parsed, imsi); - if (out == msg) { - printf("FAIL: This should have changed.\n"); - abort(); - } - - verify_msg(out, smsc_rewrite_num_patched_tp_srr, - ARRAY_SIZE(smsc_rewrite_num_patched_tp_srr)); - msgb_free(out); - bsc_nat_free(nat); -} - -static void test_barr_list_parsing(void) -{ - int rc; - int cm, lu; - struct rb_node *node; - struct rb_root root = RB_ROOT; - struct osmo_config_list *lst = osmo_config_list_parse(NULL, "barr.cfg"); - if (lst == NULL) - abort(); - - rc = bsc_filter_barr_adapt(NULL, &root, lst); - if (rc != 0) - abort(); - talloc_free(lst); - - - for (node = rb_first(&root); node; node = rb_next(node)) { - struct bsc_filter_barr_entry *entry; - entry = rb_entry(node, struct bsc_filter_barr_entry, node); - printf("IMSI: %s CM: %d LU: %d\n", entry->imsi, - entry->cm_reject_cause, entry->lu_reject_cause); - } - - /* do the look up now.. */ - rc = bsc_filter_barr_find(&root, "12123119", &cm, &lu); - if (!rc) { - printf("Failed to find the IMSI.\n"); - abort(); - } - - if (cm != 3 || lu != 4) { - printf("Found CM(%d) and LU(%d)\n", cm, lu); - abort(); - } - - /* empty and check that it is empty */ - bsc_filter_barr_adapt(NULL, &root, NULL); - if (!RB_EMPTY_ROOT(&root)) { - printf("Failed to empty the list.\n"); - abort(); - } - - /* check that dup results in an error */ - lst = osmo_config_list_parse(NULL, "barr_dup.cfg"); - if (lst == NULL) { - printf("Failed to parse list with dups\n"); - abort(); - } - - rc = bsc_filter_barr_adapt(NULL, &root, lst); - if (rc != -1) { - printf("It should have failed due dup\n"); - abort(); - } - talloc_free(lst); - - /* dump for reference */ - for (node = rb_first(&root); node; node = rb_next(node)) { - struct bsc_filter_barr_entry *entry; - entry = rb_entry(node, struct bsc_filter_barr_entry, node); - printf("IMSI: %s CM: %d LU: %d\n", entry->imsi, - entry->cm_reject_cause, entry->lu_reject_cause); - - } - rc = bsc_filter_barr_adapt(NULL, &root, NULL); -} - -static void test_nat_extract_lac() -{ - int res; - struct bsc_connection *bsc; - struct bsc_nat *nat; - struct nat_sccp_connection con; - struct bsc_nat_parsed *parsed; - struct msgb *msg = msgb_alloc(4096, "test-message"); - - printf("Testing LAC extraction from SCCP CR\n"); - - /* initialize the testcase */ - nat = bsc_nat_alloc(); - bsc = bsc_connection_alloc(nat); - bsc->cfg = bsc_config_alloc(nat, "foo", 0); - - memset(&con, 0, sizeof(con)); - con.bsc = bsc; - - /* create the SCCP CR */ - msg->l2h = msgb_put(msg, ARRAY_SIZE(bssmap_cr)); - memcpy(msg->l2h, bssmap_cr, ARRAY_SIZE(bssmap_cr)); - - /* parse it and pass it on */ - parsed = bsc_nat_parse(msg); - res = bsc_nat_extract_lac(bsc, &con, parsed, msg); - OSMO_ASSERT(res == 0); - - /* verify the LAC */ - OSMO_ASSERT(con.lac == 8210); - OSMO_ASSERT(con.ci == 50000); - - bsc_nat_free(nat); -} - -static const struct log_info_cat log_categories[] = { -}; - -static const struct log_info log_info = { - .cat = log_categories, - .num_cat = ARRAY_SIZE(log_categories), -}; - -int main(int argc, char **argv) -{ - void *tall_ctx = talloc_named_const(NULL, 1, "bsc_nat_test"); - msgb_talloc_ctx_init(tall_ctx, 0); - sccp_set_log_area(DLSCCP); - osmo_init_logging2(tall_ctx, &log_info); - - test_filter(); - test_contrack(); - test_paging(); - test_mgcp_ass_tracking(); - test_mgcp_find(); - test_mgcp_rewrite(); - test_mgcp_parse(); - test_cr_filter(); - test_dt_filter(); - test_setup_rewrite(); - test_setup_rewrite_prefix(); - test_setup_rewrite_post(); - test_sms_smsc_rewrite(); - test_sms_number_rewrite(); - test_mgcp_allocations(); - test_barr_list_parsing(); - test_nat_extract_lac(); - - printf("Testing execution completed.\n"); - return 0; -} - -/* stub */ -void bsc_nat_send_mgcp_to_msc(struct bsc_nat *nat, struct msgb *msg) -{ - abort(); -} - -struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_network *network) { return NULL; } diff --git a/tests/bsc-nat/bsc_nat_test.ok b/tests/bsc-nat/bsc_nat_test.ok deleted file mode 100644 index ab04f4273..000000000 --- a/tests/bsc-nat/bsc_nat_test.ok +++ /dev/null @@ -1,39 +0,0 @@ -Testing BSS Filtering. -Going to test item: 0 -Going to test item: 1 -Going to test item: 2 -Going to test item: 3 -Going to test item: 4 -Going to test item: 5 -Going to test item: 6 -Going to test item: 7 -Going to test item: 8 -Going to test item: 9 -Going to test item: 10 -Going to test item: 11 -Going to test item: 12 -Testing connection tracking. -Testing paging by lac. -Testing MGCP. -Testing finding of a BSC Connection -Testing rewriting MGCP messages. -Testing MGCP response parsing. -Testing SMSC rewriting. -Attempting to only rewrite the HDR -Attempting to change nothing. -Testing SMS TP-DA rewriting. -IMSI: 12123115 CM: 3 LU: 4 -IMSI: 12123116 CM: 3 LU: 4 -IMSI: 12123117 CM: 3 LU: 4 -IMSI: 12123118 CM: 3 LU: 4 -IMSI: 12123119 CM: 3 LU: 4 -IMSI: 12123120 CM: 3 LU: 4 -IMSI: 12123123 CM: 3 LU: 1 -IMSI: 12123124 CM: 3 LU: 2 -IMSI: 12123125 CM: 3 LU: 3 -IMSI: 12123126 CM: 3 LU: 4 -IMSI: 12123127 CM: 3 LU: 5 -IMSI: 12123128 CM: 3 LU: 6 -IMSI: 12123124 CM: 3 LU: 2 -Testing LAC extraction from SCCP CR -Testing execution completed. diff --git a/tests/bsc-nat/prefixes.csv b/tests/bsc-nat/prefixes.csv deleted file mode 100644 index 0c7660f10..000000000 --- a/tests/bsc-nat/prefixes.csv +++ /dev/null @@ -1,2 +0,0 @@ -0172,0049 -+49,0 diff --git a/tests/testsuite.at b/tests/testsuite.at index f0f6fd137..07bd85f8a 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -20,13 +20,6 @@ cat $abs_srcdir/channel/channel_test.ok > expout AT_CHECK([$abs_top_builddir/tests/channel/channel_test], [], [expout], [ignore]) AT_CLEANUP -AT_SETUP([bsc-nat-trie]) -AT_KEYWORDS([bsc-nat-trie]) -cp $abs_srcdir/bsc-nat-trie/prefixes.csv . -cat $abs_srcdir/bsc-nat-trie/bsc_nat_trie_test.ok > expout -AT_CHECK([$abs_top_builddir/tests/bsc-nat-trie/bsc_nat_trie_test], [], [expout], [ignore]) -AT_CLEANUP - AT_SETUP([abis]) AT_KEYWORDS([abis]) cat $abs_srcdir/abis/abis_test.ok > expout diff --git a/tests/vty_test_runner.py b/tests/vty_test_runner.py index 3b73ce7db..d2b3da4ff 100755 --- a/tests/vty_test_runner.py +++ b/tests/vty_test_runner.py @@ -249,357 +249,6 @@ class TestVTYBSC(TestVTYGenericBSC): self.assert_(res.find("core-location-area-code 666") > 0) self.assert_(res.find("core-cell-identity 333") > 0) -class TestVTYNAT(TestVTYGenericBSC): - - def vty_command(self): - return ["./src/osmo-bsc_nat/osmo-bsc_nat", "-l", "127.0.0.1", "-c", - "doc/examples/osmo-bsc_nat/osmo-bsc_nat.cfg"] - - def vty_app(self): - return (4244, "src/osmo-bsc_nat/osmo-bsc_nat", "OsmoBSCNAT", "nat") - - def testBSCreload(self): - # Use different port for the mock msc to avoid clashing with - # the osmo-bsc_nat itself - ip = "127.0.0.1" - port = 5522 - self.vty.enable() - bscs1 = self.vty.command("show bscs-config") - nat_bsc_reload(self) - bscs2 = self.vty.command("show bscs-config") - # check that multiple calls to bscs-config-file give the same result - self.assertEquals(bscs1, bscs2) - - # add new bsc - self.vty.command("configure terminal") - self.vty.command("nat") - self.vty.command("bsc 5") - self.vty.command("token key") - self.vty.command("location_area_code 666") - self.vty.command("end") - - # update bsc token - self.vty.command("configure terminal") - self.vty.command("nat") - self.vty.command("bsc 1") - self.vty.command("token xyu") - self.vty.command("end") - - nat_msc_ip(self, ip, port) - msc_socket, msc = nat_msc_test(self, ip, port, verbose=True) - try: - b0 = nat_bsc_sock_test(0, "lol", verbose=True, proc=self.proc) - b1 = nat_bsc_sock_test(1, "xyu", verbose=True, proc=self.proc) - b2 = nat_bsc_sock_test(5, "key", verbose=True, proc=self.proc) - - self.assertEquals("3 BSCs configured", self.vty.command("show nat num-bscs-configured")) - self.assertTrue(3 == nat_bsc_num_con(self)) - self.assertEquals("MSC is connected: 1", self.vty.command("show msc connection")) - - nat_bsc_reload(self) - bscs2 = self.vty.command("show bscs-config") - # check that the reset to initial config succeeded - self.assertEquals(bscs1, bscs2) - - self.assertEquals("2 BSCs configured", self.vty.command("show nat num-bscs-configured")) - self.assertTrue(1 == nat_bsc_num_con(self)) - rem = self.vty.command("show bsc connections").split(' ') - # remaining connection is for BSC0 - self.assertEquals('0', rem[2]) - # remaining connection is authorized - self.assertEquals('1', rem[4]) - self.assertEquals("MSC is connected: 1", self.vty.command("show msc connection")) - finally: - msc.close() - msc_socket.close() - - def testVtyTree(self): - self.vty.enable() - self.assertTrue(self.vty.verify('configure terminal', [''])) - self.assertEquals(self.vty.node(), 'config') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('mgcp', [''])) - self.assertEquals(self.vty.node(), 'config-mgcp') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('exit', [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify('nat', [''])) - self.assertEquals(self.vty.node(), 'config-nat') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('bsc 0', [''])) - self.assertEquals(self.vty.node(), 'config-nat-bsc') - self.checkForEndAndExit() - self.assertTrue(self.vty.verify('exit', [''])) - self.assertEquals(self.vty.node(), 'config-nat') - self.assertTrue(self.vty.verify('exit', [''])) - self.assertEquals(self.vty.node(), 'config') - self.assertTrue(self.vty.verify('exit', [''])) - self.assertTrue(self.vty.node() is None) - - def testRewriteNoRewrite(self): - self.vty.enable() - res = self.vty.command("configure terminal") - res = self.vty.command("nat") - res = self.vty.command("number-rewrite rewrite.cfg") - res = self.vty.command("no number-rewrite") - - def testEnsureNoEnsureModeSet(self): - self.vty.enable() - res = self.vty.command("configure terminal") - res = self.vty.command("nat") - - # Ensure the default - res = self.vty.command("show running-config") - self.assert_(res.find('\n sdp-ensure-amr-mode-set') > 0) - - self.vty.command("sdp-ensure-amr-mode-set") - res = self.vty.command("show running-config") - self.assert_(res.find('\n sdp-ensure-amr-mode-set') > 0) - - self.vty.command("no sdp-ensure-amr-mode-set") - res = self.vty.command("show running-config") - self.assert_(res.find('\n no sdp-ensure-amr-mode-set') > 0) - - def testRewritePostNoRewrite(self): - self.vty.enable() - self.vty.command("configure terminal") - self.vty.command("nat") - self.vty.verify("number-rewrite-post rewrite.cfg", ['']) - self.vty.verify("no number-rewrite-post", ['']) - - - def testPrefixTreeLoading(self): - cfg = os.path.join(confpath, "tests/bsc-nat-trie/prefixes.csv") - - self.vty.enable() - self.vty.command("configure terminal") - self.vty.command("nat") - res = self.vty.command("prefix-tree %s" % cfg) - self.assertEqual(res, "% prefix-tree loaded 17 rules.") - self.vty.command("end") - - res = self.vty.command("show prefix-tree") - self.assertEqual(res, '1,1\r\n12,2\r\n123,3\r\n1234,4\r\n12345,5\r\n123456,6\r\n1234567,7\r\n12345678,8\r\n123456789,9\r\n1234567890,10\r\n13,11\r\n14,12\r\n15,13\r\n16,14\r\n82,16\r\n823455,15\r\n+49123,17') - - self.vty.command("configure terminal") - self.vty.command("nat") - self.vty.command("no prefix-tree") - self.vty.command("end") - - res = self.vty.command("show prefix-tree") - self.assertEqual(res, "% there is now prefix tree loaded.") - - def testUssdSideChannelProvider(self): - self.vty.command("end") - self.vty.enable() - self.vty.command("configure terminal") - self.vty.command("nat") - self.vty.command("ussd-token key") - self.vty.command("end") - - res = self.vty.verify("show ussd-connection", ['The USSD side channel provider is not connected and not authorized.']) - self.assertTrue(res) - - ussdSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - ussdSocket.connect(('127.0.0.1', 5001)) - ussdSocket.settimeout(2.0) - print "Connected to %s:%d" % ussdSocket.getpeername() - - print "Expecting ID_GET request" - data = ussdSocket.recv(4) - self.assertEqual(data, "\x00\x01\xfe\x04") - - print "Going to send ID_RESP response" - res = ussdSocket.send(IPA().id_resp(IPA().tag_name('key'))) - self.assertEqual(res, 10) - - # initiating PING/PONG cycle to know, that the ID_RESP message has been processed - - print "Going to send PING request" - res = ussdSocket.send(IPA().ping()) - self.assertEqual(res, 4) - - print "Expecting PONG response" - data = ussdSocket.recv(4) - self.assertEqual(data, "\x00\x01\xfe\x01") - - res = self.vty.verify("show ussd-connection", ['The USSD side channel provider is connected and authorized.']) - self.assertTrue(res) - - print "Going to shut down connection" - ussdSocket.shutdown(socket.SHUT_WR) - - print "Expecting EOF" - data = ussdSocket.recv(4) - self.assertEqual(data, "") - - ussdSocket.close() - - res = self.vty.verify("show ussd-connection", ['The USSD side channel provider is not connected and not authorized.']) - self.assertTrue(res) - - def testAccessList(self): - """ - Verify that the imsi-deny can have a reject cause or no reject cause - """ - self.vty.enable() - self.vty.command("configure terminal") - self.vty.command("nat") - - # Old default - self.vty.command("access-list test-default imsi-deny ^123[0-9]*$") - res = self.vty.command("show running-config").split("\r\n") - asserted = False - for line in res: - if line.startswith(" access-list test-default"): - self.assertEqual(line, " access-list test-default imsi-deny ^123[0-9]*$ 11 11") - asserted = True - self.assert_(asserted) - - # Check the optional CM Service Reject Cause - self.vty.command("access-list test-cm-deny imsi-deny ^123[0-9]*$ 42").split("\r\n") - res = self.vty.command("show running-config").split("\r\n") - asserted = False - for line in res: - if line.startswith(" access-list test-cm"): - self.assertEqual(line, " access-list test-cm-deny imsi-deny ^123[0-9]*$ 42 11") - asserted = True - self.assert_(asserted) - - # Check the optional LU Reject Cause - self.vty.command("access-list test-lu-deny imsi-deny ^123[0-9]*$ 23 42").split("\r\n") - res = self.vty.command("show running-config").split("\r\n") - asserted = False - for line in res: - if line.startswith(" access-list test-lu"): - self.assertEqual(line, " access-list test-lu-deny imsi-deny ^123[0-9]*$ 23 42") - asserted = True - self.assert_(asserted) - - -def add_nat_test(suite, workdir): - if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc_nat/osmo-bsc_nat")): - print("Skipping the NAT test") - return - test = unittest.TestLoader().loadTestsFromTestCase(TestVTYNAT) - suite.addTest(test) - -def nat_bsc_reload(x): - x.vty.command("configure terminal") - x.vty.command("nat") - x.vty.command("bscs-config-file bscs.cfg") - x.vty.command("end") - -def nat_msc_ip(x, ip, port): - x.vty.command("configure terminal") - x.vty.command("nat") - x.vty.command("msc ip " + ip) - x.vty.command("msc port " + str(port)) - x.vty.command("end") - -def data2str(d): - return d.encode('hex').lower() - -def nat_msc_test(x, ip, port, verbose = False): - msc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - msc.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - msc.settimeout(5) - msc.bind((ip, port)) - msc.listen(5) - if (verbose): - print "MSC is ready at " + ip - conn = None - while True: - vty_response = x.vty.command("show msc connection") - print "'show msc connection' says: %r" % vty_response - if vty_response == "MSC is connected: 1": - # success - break; - if vty_response != "MSC is connected: 0": - raise Exception("Unexpected response to 'show msc connection'" - " vty command: %r" % vty_response) - - timeout_retries = 6 - while timeout_retries > 0: - try: - conn, addr = msc.accept() - print "MSC got connection from ", addr - break - except socket.timeout: - print "socket timed out." - timeout_retries -= 1 - continue - - if not conn: - raise Exception("VTY reports MSC is connected, but I haven't" - " connected yet: %r %r" % (ip, port)) - return msc, conn - -def ipa_handle_small(x, verbose = False): - s = data2str(x.recv(4)) - if len(s) != 4*2: - raise Exception("expected to receive 4 bytes, but got %d (%r)" % (len(s)/2, s)) - if "0001fe00" == s: - if (verbose): - print "\tBSC <- NAT: PING?" - x.send(IPA().pong()) - elif "0001fe06" == s: - if (verbose): - print "\tBSC <- NAT: IPA ID ACK" - x.send(IPA().id_ack()) - elif "0001fe00" == s: - if (verbose): - print "\tBSC <- NAT: PONG!" - else: - if (verbose): - print "\tBSC <- NAT: ", s - -def ipa_handle_resp(x, tk, verbose = False, proc=None): - s = data2str(x.recv(38)) - if "0023fe040108010701020103010401050101010011" in s: - retries = 3 - while True: - print "\tsending IPA identity(%s) at %s" % (tk, time.strftime("%T")) - try: - x.send(IPA().id_resp(IPA().identity(name = tk.encode('utf-8')))) - print "\tdone sending IPA identity(%s) at %s" % (tk, - time.strftime("%T")) - break - except: - print "\tfailed sending IPA identity at", time.strftime("%T") - if proc: - print "\tproc.poll() = %r" % proc.poll() - if retries < 1: - print "\tgiving up" - raise - print "\tretrying (%d attempts left)" % retries - retries -= 1 - else: - if (verbose): - print "\tBSC <- NAT: ", s - -def nat_bsc_num_con(x): - return len(x.vty.command("show bsc connections").split('\n')) - -def nat_bsc_sock_test(nr, tk, verbose = False, proc=None): - bsc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - bsc.bind(('127.0.0.1', 0)) - bsc.connect(('127.0.0.1', 5000)) - if (verbose): - print "BSC%d " %nr - print "\tconnected to %s:%d" % bsc.getpeername() - if proc: - print "\tproc.poll() = %r" % proc.poll() - print "\tproc.pid = %r" % proc.pid - ipa_handle_small(bsc, verbose) - ipa_handle_resp(bsc, tk, verbose, proc=proc) - if proc: - print "\tproc.poll() = %r" % proc.poll() - bsc.recv(27) # MGCP msg - if proc: - print "\tproc.poll() = %r" % proc.poll() - ipa_handle_small(bsc, verbose) - return bsc def add_bsc_test(suite, workdir): if not os.path.isfile(os.path.join(workdir, "src/osmo-bsc/osmo-bsc")): @@ -639,7 +288,6 @@ if __name__ == '__main__': print "Running tests for specific VTY commands" suite = unittest.TestSuite() add_bsc_test(suite, workdir) - add_nat_test(suite, workdir) if args.test_name: osmoutil.pick_tests(suite, *args.test_name) |