From f62d3da86bf1b89c20755c1e82a3674bc6387d63 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Mon, 4 Sep 2017 15:13:25 +0200 Subject: move include/openbsc to include/osmocom/sgsn Change-Id: I281ef585fffc2644682c8282224fb1c2da5ca795 --- include/osmocom/sgsn/Makefile.am | 28 ++ include/osmocom/sgsn/common.h | 6 + include/osmocom/sgsn/crc24.h | 10 + include/osmocom/sgsn/debug.h | 47 +++ include/osmocom/sgsn/gb_proxy.h | 288 ++++++++++++++++++ include/osmocom/sgsn/gprs_gb_parse.h | 59 ++++ include/osmocom/sgsn/gprs_gmm.h | 35 +++ include/osmocom/sgsn/gprs_llc.h | 284 +++++++++++++++++ include/osmocom/sgsn/gprs_llc_xid.h | 57 ++++ include/osmocom/sgsn/gprs_sgsn.h | 484 +++++++++++++++++++++++++++++ include/osmocom/sgsn/gprs_sndcp.h | 79 +++++ include/osmocom/sgsn/gprs_sndcp_comp.h | 82 +++++ include/osmocom/sgsn/gprs_sndcp_dcomp.h | 53 ++++ include/osmocom/sgsn/gprs_sndcp_pcomp.h | 46 +++ include/osmocom/sgsn/gprs_sndcp_xid.h | 218 +++++++++++++ include/osmocom/sgsn/gprs_subscriber.h | 31 ++ include/osmocom/sgsn/gprs_utils.h | 55 ++++ include/osmocom/sgsn/gsup_client.h | 63 ++++ include/osmocom/sgsn/gtphub.h | 523 ++++++++++++++++++++++++++++++++ include/osmocom/sgsn/oap_client.h | 82 +++++ include/osmocom/sgsn/rest_octets.h | 139 +++++++++ include/osmocom/sgsn/sgsn.h | 191 ++++++++++++ include/osmocom/sgsn/signal.h | 52 ++++ include/osmocom/sgsn/slhc.h | 187 ++++++++++++ include/osmocom/sgsn/v42bis.h | 147 +++++++++ include/osmocom/sgsn/v42bis_private.h | 126 ++++++++ include/osmocom/sgsn/vty.h | 9 + 27 files changed, 3381 insertions(+) create mode 100644 include/osmocom/sgsn/Makefile.am create mode 100644 include/osmocom/sgsn/common.h create mode 100644 include/osmocom/sgsn/crc24.h create mode 100644 include/osmocom/sgsn/debug.h create mode 100644 include/osmocom/sgsn/gb_proxy.h create mode 100644 include/osmocom/sgsn/gprs_gb_parse.h create mode 100644 include/osmocom/sgsn/gprs_gmm.h create mode 100644 include/osmocom/sgsn/gprs_llc.h create mode 100644 include/osmocom/sgsn/gprs_llc_xid.h create mode 100644 include/osmocom/sgsn/gprs_sgsn.h create mode 100644 include/osmocom/sgsn/gprs_sndcp.h create mode 100644 include/osmocom/sgsn/gprs_sndcp_comp.h create mode 100644 include/osmocom/sgsn/gprs_sndcp_dcomp.h create mode 100644 include/osmocom/sgsn/gprs_sndcp_pcomp.h create mode 100644 include/osmocom/sgsn/gprs_sndcp_xid.h create mode 100644 include/osmocom/sgsn/gprs_subscriber.h create mode 100644 include/osmocom/sgsn/gprs_utils.h create mode 100644 include/osmocom/sgsn/gsup_client.h create mode 100644 include/osmocom/sgsn/gtphub.h create mode 100644 include/osmocom/sgsn/oap_client.h create mode 100644 include/osmocom/sgsn/rest_octets.h create mode 100644 include/osmocom/sgsn/sgsn.h create mode 100644 include/osmocom/sgsn/signal.h create mode 100644 include/osmocom/sgsn/slhc.h create mode 100644 include/osmocom/sgsn/v42bis.h create mode 100644 include/osmocom/sgsn/v42bis_private.h create mode 100644 include/osmocom/sgsn/vty.h (limited to 'include/osmocom/sgsn') diff --git a/include/osmocom/sgsn/Makefile.am b/include/osmocom/sgsn/Makefile.am new file mode 100644 index 000000000..150212971 --- /dev/null +++ b/include/osmocom/sgsn/Makefile.am @@ -0,0 +1,28 @@ +noinst_HEADERS = \ + common.h \ + crc24.h \ + debug.h \ + gb_proxy.h \ + gprs_gb_parse.h \ + gprs_gmm.h \ + gprs_llc.h \ + gprs_llc_xid.h \ + gprs_sgsn.h \ + gprs_sndcp_comp.h \ + gprs_sndcp_dcomp.h \ + gprs_sndcp.h \ + gprs_sndcp_pcomp.h \ + gprs_sndcp_xid.h \ + gprs_subscriber.h \ + gprs_utils.h \ + gsup_client.h \ + gtphub.h \ + oap_client.h \ + rest_octets.h \ + sgsn.h \ + signal.h \ + slhc.h \ + v42bis.h \ + v42bis_private.h \ + vty.h \ + $(NULL) diff --git a/include/osmocom/sgsn/common.h b/include/osmocom/sgsn/common.h new file mode 100644 index 000000000..d91b3d39e --- /dev/null +++ b/include/osmocom/sgsn/common.h @@ -0,0 +1,6 @@ +#pragma once + +enum nsap_addr_enc { + NSAP_ADDR_ENC_X213, + NSAP_ADDR_ENC_V4RAW, +}; diff --git a/include/osmocom/sgsn/crc24.h b/include/osmocom/sgsn/crc24.h new file mode 100644 index 000000000..756638c03 --- /dev/null +++ b/include/osmocom/sgsn/crc24.h @@ -0,0 +1,10 @@ +#ifndef _CRC24_H +#define _CRC24_H + +#include + +#define INIT_CRC24 0xffffff + +uint32_t crc24_calc(uint32_t fcs, uint8_t *cp, unsigned int len); + +#endif diff --git a/include/osmocom/sgsn/debug.h b/include/osmocom/sgsn/debug.h new file mode 100644 index 000000000..65e197d52 --- /dev/null +++ b/include/osmocom/sgsn/debug.h @@ -0,0 +1,47 @@ +#pragma once + +#include +#include + +#define DEBUG +#include + +/* Debug Areas of the code */ +enum { + DRLL, + DCC, + DMM, + DRR, + DRSL, + DNM, + DMNCC, + DPAG, + DMEAS, + DSCCP, + DMSC, + DMGCP, + DHO, + DDB, + DREF, + DGPRS, + DNS, + DBSSGP, + DLLC, + DSNDCP, + DSLHC, + DNAT, + DCTRL, + DSMPP, + DFILTER, + DGTPHUB, + DRANAP, + DSUA, + DV42BIS, + DPCU, + DVLR, + DIUCS, + DSIGTRAN, + Debug_LastEntry, +}; + +extern const struct log_info log_info; diff --git a/include/osmocom/sgsn/gb_proxy.h b/include/osmocom/sgsn/gb_proxy.h new file mode 100644 index 000000000..e10894fc3 --- /dev/null +++ b/include/osmocom/sgsn/gb_proxy.h @@ -0,0 +1,288 @@ +#ifndef _GB_PROXY_H +#define _GB_PROXY_H + + +#include + +#include +#include + +#include +#include + +#define GBPROXY_INIT_VU_GEN_TX 256 + +struct rate_ctr_group; +struct gprs_gb_parse_context; +struct tlv_parsed; + +enum gbproxy_global_ctr { + GBPROX_GLOB_CTR_INV_BVCI, + GBPROX_GLOB_CTR_INV_LAI, + GBPROX_GLOB_CTR_INV_RAI, + GBPROX_GLOB_CTR_INV_NSEI, + GBPROX_GLOB_CTR_PROTO_ERR_BSS, + GBPROX_GLOB_CTR_PROTO_ERR_SGSN, + GBPROX_GLOB_CTR_NOT_SUPPORTED_BSS, + GBPROX_GLOB_CTR_NOT_SUPPORTED_SGSN, + GBPROX_GLOB_CTR_RESTART_RESET_SGSN, + GBPROX_GLOB_CTR_TX_ERR_SGSN, + GBPROX_GLOB_CTR_OTHER_ERR, + GBPROX_GLOB_CTR_PATCH_PEER_ERR, +}; + +enum gbproxy_peer_ctr { + GBPROX_PEER_CTR_BLOCKED, + GBPROX_PEER_CTR_UNBLOCKED, + GBPROX_PEER_CTR_DROPPED, + GBPROX_PEER_CTR_INV_NSEI, + GBPROX_PEER_CTR_TX_ERR, + GBPROX_PEER_CTR_RAID_PATCHED_BSS, + GBPROX_PEER_CTR_RAID_PATCHED_SGSN, + GBPROX_PEER_CTR_APN_PATCHED, + GBPROX_PEER_CTR_TLLI_PATCHED_BSS, + GBPROX_PEER_CTR_TLLI_PATCHED_SGSN, + GBPROX_PEER_CTR_PTMSI_PATCHED_BSS, + GBPROX_PEER_CTR_PTMSI_PATCHED_SGSN, + GBPROX_PEER_CTR_PATCH_CRYPT_ERR, + GBPROX_PEER_CTR_PATCH_ERR, + GBPROX_PEER_CTR_ATTACH_REQS, + GBPROX_PEER_CTR_ATTACH_REJS, + GBPROX_PEER_CTR_ATTACH_ACKS, + GBPROX_PEER_CTR_ATTACH_COMPLS, + GBPROX_PEER_CTR_RA_UPD_REQS, + GBPROX_PEER_CTR_RA_UPD_REJS, + GBPROX_PEER_CTR_RA_UPD_ACKS, + GBPROX_PEER_CTR_RA_UPD_COMPLS, + GBPROX_PEER_CTR_GMM_STATUS_BSS, + GBPROX_PEER_CTR_GMM_STATUS_SGSN, + GBPROX_PEER_CTR_DETACH_REQS, + GBPROX_PEER_CTR_DETACH_ACKS, + GBPROX_PEER_CTR_PDP_ACT_REQS, + GBPROX_PEER_CTR_PDP_ACT_REJS, + GBPROX_PEER_CTR_PDP_ACT_ACKS, + GBPROX_PEER_CTR_PDP_DEACT_REQS, + GBPROX_PEER_CTR_PDP_DEACT_ACKS, + GBPROX_PEER_CTR_TLLI_UNKNOWN, + GBPROX_PEER_CTR_TLLI_CACHE_SIZE, + GBPROX_PEER_CTR_LAST, +}; + +enum gbproxy_keep_mode { + GBPROX_KEEP_NEVER, + GBPROX_KEEP_REATTACH, + GBPROX_KEEP_IDENTIFIED, + GBPROX_KEEP_ALWAYS, +}; + +enum gbproxy_match_id { + GBPROX_MATCH_PATCHING, + GBPROX_MATCH_ROUTING, + GBPROX_MATCH_LAST +}; + +struct gbproxy_match { + int enable; + char *re_str; + regex_t re_comp; +}; + +struct gbproxy_config { + /* parsed from config file */ + uint16_t nsip_sgsn_nsei; + + /* misc */ + struct gprs_ns_inst *nsi; + + /* Linked list of all Gb peers (except SGSN) */ + struct llist_head bts_peers; + + /* Counter */ + struct rate_ctr_group *ctrg; + + /* force mcc/mnc */ + int core_mnc; + int core_mcc; + uint8_t* core_apn; + size_t core_apn_size; + int tlli_max_age; + int tlli_max_len; + + /* Experimental config */ + int patch_ptmsi; + int acquire_imsi; + int route_to_sgsn2; + uint16_t nsip_sgsn2_nsei; + enum gbproxy_keep_mode keep_link_infos; + + /* IMSI checking/matching */ + struct gbproxy_match matches[GBPROX_MATCH_LAST]; +}; + +struct gbproxy_patch_state { + int local_mnc; + int local_mcc; + + /* List of TLLIs for which patching is enabled */ + struct llist_head logical_links; + int logical_link_count; +}; + +struct gbproxy_peer { + struct llist_head list; + + /* point back to the config */ + struct gbproxy_config *cfg; + + /* NSEI of the peer entity */ + uint16_t nsei; + + /* BVCI used for Point-to-Point to this peer */ + uint16_t bvci; + int blocked; + + /* Routeing Area that this peer is part of (raw 04.08 encoding) */ + uint8_t ra[6]; + + /* Counter */ + struct rate_ctr_group *ctrg; + + struct gbproxy_patch_state patch_state; +}; + +struct gbproxy_tlli_state { + uint32_t current; + uint32_t assigned; + int bss_validated; + int net_validated; + + uint32_t ptmsi; +}; + +struct gbproxy_link_info { + struct llist_head list; + + struct gbproxy_tlli_state tlli; + struct gbproxy_tlli_state sgsn_tlli; + uint32_t sgsn_nsei; + + time_t timestamp; + uint8_t *imsi; + size_t imsi_len; + + int imsi_acq_pending; + struct llist_head stored_msgs; + unsigned vu_gen_tx_bss; + + int is_deregistered; + + int is_matching[GBPROX_MATCH_LAST]; +}; + + +/* gb_proxy_vty .c */ + +int gbproxy_vty_init(void); +int gbproxy_parse_config(const char *config_file, struct gbproxy_config *cfg); + + +/* gb_proxy.c */ +int gbproxy_init_config(struct gbproxy_config *cfg); + +/* Main input function for Gb proxy */ +int gbprox_rcvmsg(struct gbproxy_config *cfg, struct msgb *msg, uint16_t nsei, uint16_t ns_bvci, uint16_t nsvci); + +int gbprox_signal(unsigned int subsys, unsigned int signal, + void *handler_data, void *signal_data); + +/* Reset all persistent NS-VC's */ +int gbprox_reset_persistent_nsvcs(struct gprs_ns_inst *nsi); + +void gbprox_reset(struct gbproxy_config *cfg); + +/* TLLI info handling */ +void gbproxy_delete_link_infos(struct gbproxy_peer *peer); +struct gbproxy_link_info *gbproxy_update_link_state_ul( + struct gbproxy_peer *peer, time_t now, + struct gprs_gb_parse_context *parse_ctx); +struct gbproxy_link_info *gbproxy_update_link_state_dl( + struct gbproxy_peer *peer, time_t now, + struct gprs_gb_parse_context *parse_ctx); +int gbproxy_update_link_state_after( + struct gbproxy_peer *peer, struct gbproxy_link_info *link_info, + time_t now, struct gprs_gb_parse_context *parse_ctx); +int gbproxy_remove_stale_link_infos(struct gbproxy_peer *peer, time_t now); +void gbproxy_delete_link_info(struct gbproxy_peer *peer, + struct gbproxy_link_info *link_info); +void gbproxy_link_info_discard_messages(struct gbproxy_link_info *link_info); + +void gbproxy_attach_link_info(struct gbproxy_peer *peer, time_t now, + struct gbproxy_link_info *link_info); +void gbproxy_update_link_info(struct gbproxy_link_info *link_info, + const uint8_t *imsi, size_t imsi_len); +void gbproxy_detach_link_info(struct gbproxy_peer *peer, + struct gbproxy_link_info *link_info); +struct gbproxy_link_info *gbproxy_link_info_alloc( struct gbproxy_peer *peer); + +struct gbproxy_link_info *gbproxy_link_info_by_tlli( + struct gbproxy_peer *peer, uint32_t tlli); +struct gbproxy_link_info *gbproxy_link_info_by_imsi( + struct gbproxy_peer *peer, const uint8_t *imsi, size_t imsi_len); +struct gbproxy_link_info *gbproxy_link_info_by_any_sgsn_tlli( + struct gbproxy_peer *peer, uint32_t tlli); +struct gbproxy_link_info *gbproxy_link_info_by_sgsn_tlli( + struct gbproxy_peer *peer, + uint32_t tlli, uint32_t sgsn_nsei); +struct gbproxy_link_info *gbproxy_link_info_by_ptmsi( + struct gbproxy_peer *peer, + uint32_t ptmsi); + +int gbproxy_imsi_matches( + struct gbproxy_config *cfg, + enum gbproxy_match_id match_id, + struct gbproxy_link_info *link_info); +uint32_t gbproxy_map_tlli( + uint32_t other_tlli, struct gbproxy_link_info *link_info, int to_bss); + +/* needed by gb_proxy_tlli.h */ +uint32_t gbproxy_make_bss_ptmsi(struct gbproxy_peer *peer, uint32_t sgsn_ptmsi); +uint32_t gbproxy_make_sgsn_tlli( + struct gbproxy_peer *peer, struct gbproxy_link_info *link_info, + uint32_t bss_tlli); +void gbproxy_reset_link(struct gbproxy_link_info *link_info); +int gbproxy_check_imsi( + struct gbproxy_match *match, const uint8_t *imsi, size_t imsi_len); + +/* Message patching */ +void gbproxy_patch_bssgp( + struct msgb *msg, uint8_t *bssgp, size_t bssgp_len, + struct gbproxy_peer *peer, struct gbproxy_link_info *link_info, + int *len_change, struct gprs_gb_parse_context *parse_ctx); + +int gbproxy_patch_llc( + struct msgb *msg, uint8_t *llc, size_t llc_len, + struct gbproxy_peer *peer, struct gbproxy_link_info *link_info, + int *len_change, struct gprs_gb_parse_context *parse_ctx); + +int gbproxy_set_patch_filter( + struct gbproxy_match *match, const char *filter, const char **err_msg); +void gbproxy_clear_patch_filter(struct gbproxy_match *match); + +/* Peer handling */ +struct gbproxy_peer *gbproxy_peer_by_bvci( + struct gbproxy_config *cfg, uint16_t bvci); +struct gbproxy_peer *gbproxy_peer_by_nsei( + struct gbproxy_config *cfg, uint16_t nsei); +struct gbproxy_peer *gbproxy_peer_by_rai( + struct gbproxy_config *cfg, const uint8_t *ra); +struct gbproxy_peer *gbproxy_peer_by_lai( + struct gbproxy_config *cfg, const uint8_t *la); +struct gbproxy_peer *gbproxy_peer_by_lac( + struct gbproxy_config *cfg, const uint8_t *la); +struct gbproxy_peer *gbproxy_peer_by_bssgp_tlv( + struct gbproxy_config *cfg, struct tlv_parsed *tp); +struct gbproxy_peer *gbproxy_peer_alloc(struct gbproxy_config *cfg, uint16_t bvci); +void gbproxy_peer_free(struct gbproxy_peer *peer); +int gbproxy_cleanup_peers(struct gbproxy_config *cfg, uint16_t nsei, uint16_t bvci); + +#endif diff --git a/include/osmocom/sgsn/gprs_gb_parse.h b/include/osmocom/sgsn/gprs_gb_parse.h new file mode 100644 index 000000000..9f43faed6 --- /dev/null +++ b/include/osmocom/sgsn/gprs_gb_parse.h @@ -0,0 +1,59 @@ +#pragma once + +#include + +#include + +struct gprs_gb_parse_context { + /* Pointer to protocol specific parts */ + struct gsm48_hdr *g48_hdr; + struct bssgp_normal_hdr *bgp_hdr; + struct bssgp_ud_hdr *bud_hdr; + uint8_t *bssgp_data; + size_t bssgp_data_len; + uint8_t *llc; + size_t llc_len; + + /* Extracted information */ + struct gprs_llc_hdr_parsed llc_hdr_parsed; + struct tlv_parsed bssgp_tp; + int to_bss; + uint8_t *tlli_enc; + uint8_t *old_tlli_enc; + uint8_t *imsi; + size_t imsi_len; + uint8_t *apn_ie; + size_t apn_ie_len; + uint8_t *ptmsi_enc; + uint8_t *new_ptmsi_enc; + uint8_t *raid_enc; + uint8_t *old_raid_enc; + uint8_t *bssgp_raid_enc; + uint8_t *bssgp_ptmsi_enc; + + /* General info */ + const char *llc_msg_name; + int invalidate_tlli; + int await_reattach; + int need_decryption; + uint32_t tlli; + int pdu_type; + int old_raid_is_foreign; + int peer_nsei; +}; + +int gprs_gb_parse_dtap(uint8_t *data, size_t data_len, + struct gprs_gb_parse_context *parse_ctx); + +int gprs_gb_parse_llc(uint8_t *llc, size_t llc_len, + struct gprs_gb_parse_context *parse_ctx); + +int gprs_gb_parse_bssgp(uint8_t *bssgp, size_t bssgp_len, + struct gprs_gb_parse_context *parse_ctx); + +const char *gprs_gb_message_name(const struct gprs_gb_parse_context *parse_ctx, + const char *default_msg_name); + +void gprs_gb_log_parse_context(int log_level, + struct gprs_gb_parse_context *parse_ctx, + const char *default_msg_name); diff --git a/include/osmocom/sgsn/gprs_gmm.h b/include/osmocom/sgsn/gprs_gmm.h new file mode 100644 index 000000000..6324c5da7 --- /dev/null +++ b/include/osmocom/sgsn/gprs_gmm.h @@ -0,0 +1,35 @@ +#ifndef _GPRS_GMM_H +#define _GPRS_GMM_H + +#include +#include + +#include + +int gsm48_tx_gsm_deact_pdp_req(struct sgsn_pdp_ctx *pdp, uint8_t sm_cause); +int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid, + uint8_t cause, uint8_t pco_len, uint8_t *pco_v); +int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp); +int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_pdp_ctx *pdp); + +int gsm0408_gprs_rcvmsg_gb(struct msgb *msg, struct gprs_llc_llme *llme, + bool drop_cipherable); +int gsm0408_gprs_rcvmsg_iu(struct msgb *msg, struct gprs_ra_id *ra_id, + uint16_t *sai); +int gsm0408_gprs_force_reattach(struct sgsn_mm_ctx *mmctx); +int gsm0408_gprs_force_reattach_oldmsg(struct msgb *msg, + struct gprs_llc_llme *llme); +void gsm0408_gprs_access_granted(struct sgsn_mm_ctx *mmctx); +void gsm0408_gprs_access_denied(struct sgsn_mm_ctx *mmctx, int gmm_cause); +void gsm0408_gprs_access_cancelled(struct sgsn_mm_ctx *mmctx, int gmm_cause); +void gsm0408_gprs_authenticate(struct sgsn_mm_ctx *mmctx); + +int gprs_gmm_rx_suspend(struct gprs_ra_id *raid, uint32_t tlli); +int gprs_gmm_rx_resume(struct gprs_ra_id *raid, uint32_t tlli, + uint8_t suspend_ref); + +time_t gprs_max_time_to_idle(void); + +int iu_rab_act_ps(uint8_t rab_id, struct sgsn_pdp_ctx *pdp); + +#endif /* _GPRS_GMM_H */ diff --git a/include/osmocom/sgsn/gprs_llc.h b/include/osmocom/sgsn/gprs_llc.h new file mode 100644 index 000000000..376ae9a1a --- /dev/null +++ b/include/osmocom/sgsn/gprs_llc.h @@ -0,0 +1,284 @@ +#ifndef _GPRS_LLC_H +#define _GPRS_LLC_H + +#include +#include +#include +#include + +/* Section 4.7 LLC Layer Structure */ +enum gprs_llc_sapi { + GPRS_SAPI_GMM = 1, + GPRS_SAPI_TOM2 = 2, + GPRS_SAPI_SNDCP3 = 3, + GPRS_SAPI_SNDCP5 = 5, + GPRS_SAPI_SMS = 7, + GPRS_SAPI_TOM8 = 8, + GPRS_SAPI_SNDCP9 = 9, + GPRS_SAPI_SNDCP11 = 11, +}; + +/* Section 6.4 Commands and Responses */ +enum gprs_llc_u_cmd { + GPRS_LLC_U_DM_RESP = 0x01, + GPRS_LLC_U_DISC_CMD = 0x04, + GPRS_LLC_U_UA_RESP = 0x06, + GPRS_LLC_U_SABM_CMD = 0x07, + GPRS_LLC_U_FRMR_RESP = 0x08, + GPRS_LLC_U_XID = 0x0b, + GPRS_LLC_U_NULL_CMD = 0x00, +}; + +/* Section 6.4.1.6 / Table 6 */ +enum gprs_llc_xid_type { + GPRS_LLC_XID_T_VERSION = 0, + GPRS_LLC_XID_T_IOV_UI = 1, + GPRS_LLC_XID_T_IOV_I = 2, + GPRS_LLC_XID_T_T200 = 3, + GPRS_LLC_XID_T_N200 = 4, + GPRS_LLC_XID_T_N201_U = 5, + GPRS_LLC_XID_T_N201_I = 6, + GPRS_LLC_XID_T_mD = 7, + GPRS_LLC_XID_T_mU = 8, + GPRS_LLC_XID_T_kD = 9, + GPRS_LLC_XID_T_kU = 10, + GPRS_LLC_XID_T_L3_PAR = 11, + GPRS_LLC_XID_T_RESET = 12, +}; + +extern const struct value_string gprs_llc_xid_type_names[]; + +/* TS 04.64 Section 7.1.2 Table 7: LLC layer primitives (GMM/SNDCP/SMS/TOM) */ +/* TS 04.65 Section 5.1.2 Table 2: Service primitives used by SNDCP */ +enum gprs_llc_primitive { + /* GMM <-> LLME */ + LLGMM_ASSIGN_REQ, /* GMM tells us new TLLI: TLLI old, TLLI new, Kc, CiphAlg */ + LLGMM_RESET_REQ, /* GMM tells us to perform XID negotiation: TLLI */ + LLGMM_RESET_CNF, /* LLC informs GMM that XID has completed: TLLI */ + LLGMM_SUSPEND_REQ, /* GMM tells us MS has suspended: TLLI, Page */ + LLGMM_RESUME_REQ, /* GMM tells us MS has resumed: TLLI */ + LLGMM_PAGE_IND, /* LLC asks GMM to page MS: TLLI */ + LLGMM_IOV_REQ, /* GMM tells us to perform XID: TLLI */ + LLGMM_STATUS_IND, /* LLC informs GMM about error: TLLI, Cause */ + /* LLE <-> (GMM/SNDCP/SMS/TOM) */ + LL_RESET_IND, /* TLLI */ + LL_ESTABLISH_REQ, /* TLLI, XID Req */ + LL_ESTABLISH_IND, /* TLLI, XID Req, N201-I, N201-U */ + LL_ESTABLISH_RESP, /* TLLI, XID Negotiated */ + LL_ESTABLISH_CONF, /* TLLI, XID Neg, N201-i, N201-U */ + LL_RELEASE_REQ, /* TLLI, Local */ + LL_RELEASE_IND, /* TLLI, Cause */ + LL_RELEASE_CONF, /* TLLI */ + LL_XID_REQ, /* TLLI, XID Requested */ + LL_XID_IND, /* TLLI, XID Req, N201-I, N201-U */ + LL_XID_RESP, /* TLLI, XID Negotiated */ + LL_XID_CONF, /* TLLI, XID Neg, N201-I, N201-U */ + LL_DATA_REQ, /* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */ + LL_DATA_IND, /* TLLI, SN-PDU */ + LL_DATA_CONF, /* TLLI, Ref */ + LL_UNITDATA_REQ, /* TLLI, SN-PDU, Ref, QoS, Radio Prio, Ciph */ + LL_UNITDATA_IND, /* TLLI, SN-PDU */ + LL_STATUS_IND, /* TLLI, Cause */ +}; + +/* Section 4.5.2 Logical Link States + Annex C.2 */ +enum gprs_llc_lle_state { + GPRS_LLES_UNASSIGNED = 1, /* No TLLI yet */ + GPRS_LLES_ASSIGNED_ADM = 2, /* TLLI assigned */ + GPRS_LLES_LOCAL_EST = 3, /* Local Establishment */ + GPRS_LLES_REMOTE_EST = 4, /* Remote Establishment */ + GPRS_LLES_ABM = 5, + GPRS_LLES_LOCAL_REL = 6, /* Local Release */ + GPRS_LLES_TIMER_REC = 7, /* Timer Recovery */ +}; + +enum gprs_llc_llme_state { + GPRS_LLMS_UNASSIGNED = 1, /* No TLLI yet */ + GPRS_LLMS_ASSIGNED = 2, /* TLLI assigned */ +}; + +/* Section 8.9.9 LLC layer parameter default values */ +struct gprs_llc_params { + uint16_t iov_i_exp; + uint16_t t200_201; + uint16_t n200; + uint16_t n201_u; + uint16_t n201_i; + uint16_t mD; + uint16_t mU; + uint16_t kD; + uint16_t kU; +}; + +/* Section 4.7.1: Logical Link Entity: One per DLCI (TLLI + SAPI) */ +struct gprs_llc_lle { + struct llist_head list; + + uint32_t sapi; + + struct gprs_llc_llme *llme; + + enum gprs_llc_lle_state state; + + struct osmo_timer_list t200; + struct osmo_timer_list t201; /* wait for acknowledgement */ + + uint16_t v_sent; + uint16_t v_ack; + uint16_t v_recv; + + uint16_t vu_send; + uint16_t vu_recv; + + /* non-standard LLC state */ + uint16_t vu_recv_last; + uint16_t vu_recv_duplicates; + + /* Overflow Counter for ABM */ + uint32_t oc_i_send; + uint32_t oc_i_recv; + + /* Overflow Counter for unconfirmed transfer */ + uint32_t oc_ui_send; + uint32_t oc_ui_recv; + + unsigned int retrans_ctr; + + struct gprs_llc_params params; +}; + +#define NUM_SAPIS 16 + +struct gprs_llc_llme { + struct llist_head list; + + enum gprs_llc_llme_state state; + + uint32_t tlli; + uint32_t old_tlli; + + /* Crypto parameters */ + enum gprs_ciph_algo algo; + uint8_t kc[16]; + uint8_t cksn; + /* 3GPP TS 44.064 § 8.9.2: */ + uint32_t iov_ui; + + /* over which BSSGP BTS ctx do we need to transmit */ + uint16_t bvci; + uint16_t nsei; + struct gprs_llc_lle lle[NUM_SAPIS]; + + /* Copy of the XID fields we have sent with the last + * network originated XID-Request. Since the phone + * may strip the optional fields in the confirmation + * we need to remeber those fields in order to be + * able to create the compression entity. */ + struct llist_head *xid; + + /* Compression entities */ + struct { + /* In these two list_heads we will store the + * data and protocol compression entities, + * together with their compression states */ + struct llist_head *proto; + struct llist_head *data; + } comp; + + /* Internal management */ + uint32_t age_timestamp; +}; + +#define GPRS_LLME_RESET_AGE (0) + +extern struct llist_head gprs_llc_llmes; + +/* LLC low level types */ + +enum gprs_llc_cmd { + GPRS_LLC_NULL, + GPRS_LLC_RR, + GPRS_LLC_ACK, + GPRS_LLC_RNR, + GPRS_LLC_SACK, + GPRS_LLC_DM, + GPRS_LLC_DISC, + GPRS_LLC_UA, + GPRS_LLC_SABM, + GPRS_LLC_FRMR, + GPRS_LLC_XID, + GPRS_LLC_UI, +}; + +struct gprs_llc_hdr_parsed { + uint8_t sapi; + uint8_t is_cmd:1, + ack_req:1, + is_encrypted:1; + uint32_t seq_rx; + uint32_t seq_tx; + uint32_t fcs; + uint32_t fcs_calc; + uint8_t *data; + uint16_t data_len; + uint16_t crc_length; + enum gprs_llc_cmd cmd; +}; + + +/* BSSGP-UL-UNITDATA.ind */ +int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv); + +/* LL-UNITDATA.req */ +int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command, + struct sgsn_mm_ctx *mmctx, bool encryptable); + +/* Chapter 7.2.1.2 LLGMM-RESET.req */ +int gprs_llgmm_reset(struct gprs_llc_llme *llme); +int gprs_llgmm_reset_oldmsg(struct msgb* oldmsg, uint8_t sapi, + struct gprs_llc_llme *llme); + +/* Set of LL-XID negotiation (See also: TS 101 351, Section 7.2.2.4) */ +int gprs_ll_xid_req(struct gprs_llc_lle *lle, + struct gprs_llc_xid_field *l3_xid_field); + +/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ +int gprs_llgmm_assign(struct gprs_llc_llme *llme, + uint32_t old_tlli, uint32_t new_tlli); +int gprs_llgmm_unassign(struct gprs_llc_llme *llme); + +int gprs_llc_init(const char *cipher_plugin_path); +int gprs_llc_vty_init(void); + +/** + * \short Check if N(U) should be considered a retransmit + * + * Implements the range check as of GSM 04.64 8.4.2 + * Receipt of unacknowledged information. + * + * @returns Returns 1 if (V(UR)-32) <= N(U) < V(UR) + * @param nu N(U) unconfirmed sequence number of the UI frame + * @param vur V(UR) unconfirmend received state variable + */ +static inline int gprs_llc_is_retransmit(uint16_t nu, uint16_t vur) +{ + int delta = (vur - nu) & 0x1ff; + return 0 < delta && delta < 32; +} + +/* LLC low level functions */ +void gprs_llme_copy_key(struct sgsn_mm_ctx *mm, struct gprs_llc_llme *llme); + +/* parse a GPRS LLC header, also check for invalid frames */ +int gprs_llc_hdr_parse(struct gprs_llc_hdr_parsed *ghp, + uint8_t *llc_hdr, int len); +void gprs_llc_hdr_dump(struct gprs_llc_hdr_parsed *gph, struct gprs_llc_lle *lle); +int gprs_llc_fcs(uint8_t *data, unsigned int len); + + +/* LLME handling routines */ +struct llist_head *gprs_llme_list(void); +struct gprs_llc_lle *gprs_lle_get_or_create(const uint32_t tlli, uint8_t sapi); + + +#endif diff --git a/include/osmocom/sgsn/gprs_llc_xid.h b/include/osmocom/sgsn/gprs_llc_xid.h new file mode 100644 index 000000000..d340d40b7 --- /dev/null +++ b/include/osmocom/sgsn/gprs_llc_xid.h @@ -0,0 +1,57 @@ +/* GPRS LLC XID field encoding/decoding as per 3GPP TS 44.064 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * 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 . + */ + +#pragma once + +#include +#include + +/* 3GPP TS 44.064 6.4.1.6 Exchange Identification (XID) + command/response parameter field */ +struct gprs_llc_xid_field { + struct llist_head list; + uint8_t type; /* See also Table 6: LLC layer parameter + negotiation */ + uint8_t *data; /* Payload data (memory is owned by the + * creator of the struct) */ + unsigned int data_len; /* Payload length */ +}; + +/* Transform a list with XID fields into a XID message (dst) */ +int gprs_llc_compile_xid(uint8_t *dst, int dst_maxlen, + const struct llist_head *xid_fields); + +/* Transform a XID message (dst) into a list of XID fields */ +struct llist_head *gprs_llc_parse_xid(const void *ctx, const uint8_t *src, + int src_len); + +/* Create a duplicate of an XID-Field */ +struct gprs_llc_xid_field *gprs_llc_dup_xid_field(const void *ctx, + const struct gprs_llc_xid_field *xid_field); + +/* Copy an llist with xid fields */ +struct llist_head *gprs_llc_copy_xid(const void *ctx, + const struct llist_head *xid_fields); + +/* Dump a list with XID fields (Debug) */ +void gprs_llc_dump_xid_fields(const struct llist_head *xid_fields, + unsigned int logl); + diff --git a/include/osmocom/sgsn/gprs_sgsn.h b/include/osmocom/sgsn/gprs_sgsn.h new file mode 100644 index 000000000..c47fb0905 --- /dev/null +++ b/include/osmocom/sgsn/gprs_sgsn.h @@ -0,0 +1,484 @@ +#ifndef _GPRS_SGSN_H +#define _GPRS_SGSN_H + +#include +#include + +#include + +#include + +#include +#include +#include + +#define GSM_EXTENSION_LENGTH 15 +#define GSM_APN_LENGTH 102 + +struct gprs_llc_lle; +struct ctrl_handle; +struct gprs_subscr; + +enum gsm48_gsm_cause; + +/* TS 04.08 4.1.3.3 GMM mobility management states on the network side */ +enum gprs_gmm_state { + GMM_DEREGISTERED, /* 4.1.3.3.1.1 */ + GMM_COMMON_PROC_INIT, /* 4.1.3.3.1.2 */ + GMM_REGISTERED_NORMAL, /* 4.1.3.3.2.1 */ + GMM_REGISTERED_SUSPENDED, /* 4.1.3.3.2.2 */ + GMM_DEREGISTERED_INIT, /* 4.1.3.3.1.4 */ +}; + +/* TS 23.060 6.1.1 and 6.1.2 Mobility management states A/Gb and Iu mode */ +enum gprs_pmm_state { + PMM_DETACHED, + PMM_CONNECTED, + PMM_IDLE, + MM_IDLE, + MM_READY, + MM_STANDBY, +}; + +enum gprs_mm_ctr { + GMM_CTR_PKTS_SIG_IN, + GMM_CTR_PKTS_SIG_OUT, + GMM_CTR_PKTS_UDATA_IN, + GMM_CTR_PKTS_UDATA_OUT, + GMM_CTR_BYTES_UDATA_IN, + GMM_CTR_BYTES_UDATA_OUT, + GMM_CTR_PDP_CTX_ACT, + GMM_CTR_SUSPEND, + GMM_CTR_PAGING_PS, + GMM_CTR_PAGING_CS, + GMM_CTR_RA_UPDATE, +}; + +enum gprs_pdp_ctx { + PDP_CTR_PKTS_UDATA_IN, + PDP_CTR_PKTS_UDATA_OUT, + PDP_CTR_BYTES_UDATA_IN, + PDP_CTR_BYTES_UDATA_OUT, +}; + +enum gprs_t3350_mode { + GMM_T3350_MODE_NONE, + GMM_T3350_MODE_ATT, + GMM_T3350_MODE_RAU, + GMM_T3350_MODE_PTMSI_REALL, +}; + +/* Authorization/ACL handling */ +enum sgsn_auth_state { + SGSN_AUTH_UNKNOWN, + SGSN_AUTH_AUTHENTICATE, + SGSN_AUTH_UMTS_RESYNC, + SGSN_AUTH_ACCEPTED, + SGSN_AUTH_REJECTED +}; + +#define MS_RADIO_ACCESS_CAPA + +enum sgsn_ggsn_lookup_state { + SGSN_GGSN_2DIGIT, + SGSN_GGSN_3DIGIT, +}; + +struct sgsn_ggsn_lookup { + int state; + + struct sgsn_mm_ctx *mmctx; + + /* APN string */ + char apn_str[GSM_APN_LENGTH]; + + /* the original data */ + struct msgb *orig_msg; + struct tlv_parsed tp; + + /* for dealing with re-transmissions */ + uint8_t nsapi; + uint8_t sapi; + uint8_t ti; +}; + +enum sgsn_ran_type { + /* GPRS/EDGE via Gb */ + MM_CTX_T_GERAN_Gb, + /* UMTS via Iu */ + MM_CTX_T_UTRAN_Iu, + /* GPRS/EDGE via Iu */ + MM_CTX_T_GERAN_Iu, +}; + +struct service_info { + uint8_t type; + uint16_t pdp_status; +}; + +struct ranap_ue_conn_ctx; + +struct gsm_auth_tuple { + int use_count; + int key_seq; + struct osmo_auth_vector vec; +}; +#define GSM_KEY_SEQ_INVAL 7 /* GSM 04.08 - 10.5.1.2 */ + +/* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */ +/* Extended by 3GPP TS 23.060, Table 6: SGSN MM and PDP Contexts */ +struct sgsn_mm_ctx { + struct llist_head list; + + enum sgsn_ran_type ran_type; + + char imsi[GSM23003_IMSI_MAX_DIGITS+1]; + enum gprs_gmm_state gmm_state; + enum gprs_pmm_state pmm_state; /* Iu: page when in PMM-IDLE mode */ + uint32_t p_tmsi; + uint32_t p_tmsi_old; /* old P-TMSI before new is confirmed */ + uint32_t p_tmsi_sig; + char imei[GSM23003_IMEISV_NUM_DIGITS+1]; + /* Opt: Software Version Numbber / TS 23.195 */ + char msisdn[GSM_EXTENSION_LENGTH]; + struct gprs_ra_id ra; + struct { + uint16_t cell_id; /* Gb only */ + uint32_t cell_id_age; /* Gb only */ + uint8_t radio_prio_sms; + + /* Additional bits not present in the GSM TS */ + uint16_t nsei; + uint16_t bvci; + struct gprs_llc_llme *llme; + uint32_t tlli; + uint32_t tlli_new; + } gb; + struct { + int new_key; + uint16_t sac; /* Iu: Service Area Code */ + uint32_t sac_age; /* Iu: Service Area Code age */ + /* CSG ID */ + /* CSG Membership */ + /* Access Mode */ + /* Seelected CN Operator ID (TS 23.251) */ + /* CSG Subscription Data */ + /* LIPA Allowed */ + /* Voice Support Match Indicator */ + struct ranap_ue_conn_ctx *ue_ctx; + struct service_info service; + } iu; + /* VLR number */ + uint32_t new_sgsn_addr; + /* Authentication Triplet */ + struct gsm_auth_tuple auth_triplet; + /* Kc */ + /* Iu: CK, IK, KSI */ + /* CKSN */ + enum gprs_ciph_algo ciph_algo; + /* Auth & Ciphering Request reference from 3GPP TS 24.008 § 10.5.5.19: */ + uint8_t ac_ref_nr_used; + + struct { + uint8_t len; + uint8_t buf[50]; /* GSM 04.08 10.5.5.12a, extended in TS 24.008 */ + } ms_radio_access_capa; + /* Supported Codecs (SRVCC) */ + struct { + uint8_t len; + uint8_t buf[8]; /* GSM 04.08 10.5.5.12, extended in TS 24.008 */ + } ms_network_capa; + /* UE Netowrk Capability (E-UTRAN) */ + uint16_t drx_parms; + /* Active Time value for PSM */ + int mnrg; /* MS reported to HLR? */ + int ngaf; /* MS reported to MSC/VLR? */ + int ppf; /* paging for GPRS + non-GPRS? */ + /* Subscribed Charging Characteristics */ + /* Trace Reference */ + /* Trace Type */ + /* Trigger ID */ + /* OMC Identity */ + /* SMS Parameters */ + int recovery; + /* Access Restriction */ + /* GPRS CSI (CAMEL) */ + /* MG-CSI (CAMEL) */ + /* Subscribed UE-AMBR */ + /* UE-AMBR */ + /* APN Subscribed */ + + struct llist_head pdp_list; + + struct rate_ctr_group *ctrg; + struct osmo_timer_list timer; + unsigned int T; /* Txxxx number */ + unsigned int num_T_exp; /* number of consecutive T expirations */ + + enum gprs_t3350_mode t3350_mode; + uint8_t t3370_id_type; + uint8_t pending_req; /* the request's message type */ + /* TODO: There isn't much semantic difference between t3350_mode + * (refers to the timer) and pending_req (refers to the procedure), + * where mm->T == 3350 => mm->t3350_mode == f(mm->pending_req). Check + * whether one of them can be dropped. */ + + enum sgsn_auth_state auth_state; + int is_authenticated; + + /* the string representation of the current hlr */ + char hlr[GSM_EXTENSION_LENGTH]; + + /* the current GGSN look-up operation */ + struct sgsn_ggsn_lookup *ggsn_lookup; + + struct gprs_subscr *subscr; +}; + +#define LOGMMCTXP(level, mm, fmt, args...) \ + LOGP(DMM, level, "MM(%s/%08x) " fmt, (mm) ? (mm)->imsi : "---", \ + (mm) ? (mm)->p_tmsi : GSM_RESERVED_TMSI, ## args) + +/* look-up a SGSN MM context based on TLLI + RAI */ +struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, + const struct gprs_ra_id *raid); +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(uint32_t tmsi); +struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi); +struct sgsn_mm_ctx *sgsn_mm_ctx_by_ue_ctx(const void *uectx); + +/* look-up by matching TLLI and P-TMSI (think twice before using this) */ +struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli_and_ptmsi(uint32_t tlli, + const struct gprs_ra_id *raid); + +/* Allocate a new SGSN MM context */ +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_gb(uint32_t tlli, + const struct gprs_ra_id *raid); +struct sgsn_mm_ctx *sgsn_mm_ctx_alloc_iu(void *uectx); + +void sgsn_mm_ctx_cleanup_free(struct sgsn_mm_ctx *ctx); + +struct sgsn_ggsn_ctx *sgsn_mm_ctx_find_ggsn_ctx(struct sgsn_mm_ctx *mmctx, + struct tlv_parsed *tp, + enum gsm48_gsm_cause *gsm_cause, + char *apn_str); + +enum pdp_ctx_state { + PDP_STATE_NONE, + PDP_STATE_CR_REQ, + PDP_STATE_CR_CONF, + + /* 04.08 / Figure 6.2 / 6.1.2.2 */ + PDP_STATE_INACT_PEND, + PDP_STATE_INACTIVE = PDP_STATE_NONE, +}; + +enum pdp_type { + PDP_TYPE_NONE, + PDP_TYPE_ETSI_PPP, + PDP_TYPE_IANA_IPv4, + PDP_TYPE_IANA_IPv6, +}; + +struct sgsn_pdp_ctx { + struct llist_head list; /* list_head for mmctx->pdp_list */ + struct llist_head g_list; /* list_head for global list */ + struct sgsn_mm_ctx *mm; /* back pointer to MM CTX */ + int destroy_ggsn; /* destroy it on destruction */ + struct sgsn_ggsn_ctx *ggsn; /* which GGSN serves this PDP */ + struct rate_ctr_group *ctrg; + + //unsigned int id; + struct pdp_t *lib; /* pointer to libgtp PDP ctx */ + enum pdp_ctx_state state; + enum pdp_type type; + uint32_t address; + char *apn_subscribed; + //char *apn_used; + uint16_t nsapi; /* SNDCP */ + uint16_t sapi; /* LLC */ + uint8_t ti; /* transaction identifier */ + int vplmn_allowed; + uint32_t qos_profile_subscr; + //uint32_t qos_profile_req; + //uint32_t qos_profile_neg; + uint8_t radio_prio; + //uint32_t charging_id; + + struct osmo_timer_list timer; + unsigned int T; /* Txxxx number */ + unsigned int num_T_exp; /* number of consecutive T expirations */ + + struct osmo_timer_list cdr_timer; /* CDR record wird timer */ + struct timespec cdr_start; /* The start of the CDR */ + uint64_t cdr_bytes_in; + uint64_t cdr_bytes_out; + uint32_t cdr_charging_id; +}; + +#define LOGPDPCTXP(level, pdp, fmt, args...) \ + LOGP(DGPRS, level, "PDP(%s/%u) " \ + fmt, (pdp)->mm ? (pdp)->mm->imsi : "---", (pdp)->ti, ## args) + +/* look up PDP context by MM context and NSAPI */ +struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm, + uint8_t nsapi); +/* look up PDP context by MM context and transaction ID */ +struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_tid(const struct sgsn_mm_ctx *mm, + uint8_t tid); + +struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm, + uint8_t nsapi); +void sgsn_pdp_ctx_terminate(struct sgsn_pdp_ctx *pdp); +void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp); + + +struct sgsn_ggsn_ctx { + struct llist_head list; + uint32_t id; + unsigned int gtp_version; + struct in_addr remote_addr; + int remote_restart_ctr; + struct gsn_t *gsn; +}; +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_alloc(uint32_t id); +void sgsn_ggsn_ctx_free(struct sgsn_ggsn_ctx *ggc); +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_id(uint32_t id); +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_by_addr(struct in_addr *addr); +struct sgsn_ggsn_ctx *sgsn_ggsn_ctx_find_alloc(uint32_t id); + +struct apn_ctx { + struct llist_head list; + struct sgsn_ggsn_ctx *ggsn; + char *name; + char *imsi_prefix; + char *description; +}; + +struct apn_ctx *sgsn_apn_ctx_find_alloc(const char *name, const char *imsi_prefix); +void sgsn_apn_ctx_free(struct apn_ctx *actx); +struct apn_ctx *sgsn_apn_ctx_by_name(const char *name, const char *imsi_prefix); +struct apn_ctx *sgsn_apn_ctx_match(const char *name, const char *imsi_prefix); + +extern struct llist_head sgsn_mm_ctxts; +extern struct llist_head sgsn_ggsn_ctxts; +extern struct llist_head sgsn_apn_ctxts; +extern struct llist_head sgsn_pdp_ctxts; + +uint32_t sgsn_alloc_ptmsi(void); +void sgsn_inst_init(void); + +/* High-level function to be called in case a GGSN has disappeared or + * ottherwise lost state (recovery procedure) */ +int drop_all_pdp_for_ggsn(struct sgsn_ggsn_ctx *ggsn); + +char *gprs_pdpaddr2str(uint8_t *pdpa, uint8_t len); + +/* + * ctrl interface related work + */ +struct gsm_network; +struct ctrl_handle *sgsn_controlif_setup(struct gsm_network *, + const char *bind_addr, uint16_t port); +int sgsn_ctrl_cmds_install(void); + +/* + * Authorization/ACL handling + */ +struct imsi_acl_entry { + struct llist_head list; + char imsi[16+1]; +}; + +/* see GSM 09.02, 17.7.1, PDP-Context and GPRSSubscriptionData */ +/* see GSM 09.02, B.1, gprsSubscriptionData */ +struct sgsn_subscriber_pdp_data { + struct llist_head list; + + unsigned int context_id; + uint16_t pdp_type; + char apn_str[GSM_APN_LENGTH]; + uint8_t qos_subscribed[20]; + size_t qos_subscribed_len; + uint8_t pdp_charg[2]; + bool has_pdp_charg; +}; + +struct sgsn_subscriber_data { + struct sgsn_mm_ctx *mm; + struct gsm_auth_tuple auth_triplets[5]; + int auth_triplets_updated; + struct llist_head pdp_list; + int error_cause; + + uint8_t msisdn[9]; + size_t msisdn_len; + + uint8_t hlr[9]; + size_t hlr_len; + + uint8_t pdp_charg[2]; + bool has_pdp_charg; +}; + +#define SGSN_ERROR_CAUSE_NONE (-1) + +#define LOGGSUBSCRP(level, subscr, fmt, args...) \ + LOGP(DGPRS, level, "SUBSCR(%s) " fmt, \ + (subscr) ? (subscr)->imsi : "---", \ + ## args) + +struct sgsn_config; +struct sgsn_instance; +extern const struct value_string *sgsn_auth_state_names; + +void sgsn_auth_init(void); +struct imsi_acl_entry *sgsn_acl_lookup(const char *imsi, struct sgsn_config *cfg); +int sgsn_acl_add(const char *imsi, struct sgsn_config *cfg); +int sgsn_acl_del(const char *imsi, struct sgsn_config *cfg); +/* Request authorization */ +int sgsn_auth_request(struct sgsn_mm_ctx *mm); +enum sgsn_auth_state sgsn_auth_state(struct sgsn_mm_ctx *mm); +void sgsn_auth_update(struct sgsn_mm_ctx *mm); +struct gsm_auth_tuple *sgsn_auth_get_tuple(struct sgsn_mm_ctx *mmctx, + unsigned key_seq); + +/* + * GPRS subscriber data + */ +#define GPRS_SUBSCRIBER_FIRST_CONTACT 0x00000001 +#define GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING (1 << 16) +#define GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING (1 << 17) +#define GPRS_SUBSCRIBER_CANCELLED (1 << 18) +#define GPRS_SUBSCRIBER_ENABLE_PURGE (1 << 19) + +#define GPRS_SUBSCRIBER_UPDATE_PENDING_MASK ( \ + GPRS_SUBSCRIBER_UPDATE_LOCATION_PENDING | \ + GPRS_SUBSCRIBER_UPDATE_AUTH_INFO_PENDING \ +) + +int gprs_subscr_init(struct sgsn_instance *sgi); +int gprs_subscr_request_update_location(struct sgsn_mm_ctx *mmctx); +int gprs_subscr_request_auth_info(struct sgsn_mm_ctx *mmctx, + const uint8_t *auts, + const uint8_t *auts_rand); +int gprs_subscr_auth_sync(struct gprs_subscr *subscr, + const uint8_t *auts, const uint8_t *auts_rand); +void gprs_subscr_cleanup(struct gprs_subscr *subscr); +struct gprs_subscr *gprs_subscr_get_or_create(const char *imsi); +struct gprs_subscr *gprs_subscr_get_or_create_by_mmctx( struct sgsn_mm_ctx *mmctx); +struct gprs_subscr *gprs_subscr_get_by_imsi(const char *imsi); +void gprs_subscr_cancel(struct gprs_subscr *subscr); +void gprs_subscr_update(struct gprs_subscr *subscr); +void gprs_subscr_update_auth_info(struct gprs_subscr *subscr); +int gprs_subscr_rx_gsup_message(struct msgb *msg); + +/* Called on subscriber data updates */ +void sgsn_update_subscriber_data(struct sgsn_mm_ctx *mmctx); + +int gprs_sndcp_vty_init(void); +struct sgsn_instance; +int sgsn_gtp_init(struct sgsn_instance *sgi); + +void sgsn_rate_ctr_init(); + +#endif /* _GPRS_SGSN_H */ diff --git a/include/osmocom/sgsn/gprs_sndcp.h b/include/osmocom/sgsn/gprs_sndcp.h new file mode 100644 index 000000000..d970240e4 --- /dev/null +++ b/include/osmocom/sgsn/gprs_sndcp.h @@ -0,0 +1,79 @@ +#ifndef _INT_SNDCP_H +#define _INT_SNDCP_H + +#include +#include + +/* A fragment queue header, maintaining list of fragments for one N-PDU */ +struct defrag_state { + /* PDU number for which the defragmentation state applies */ + uint16_t npdu; + /* highest segment number we have received so far */ + uint8_t highest_seg; + /* bitmask of the segments we already have */ + uint32_t seg_have; + /* do we still expect more segments? */ + unsigned int no_more; + /* total length of all segments together */ + unsigned int tot_len; + + /* linked list of defrag_queue_entry: one for each fragment */ + struct llist_head frag_list; + + struct osmo_timer_list timer; + + /* Holds state to know which compression mode is used + * when the packet is re-assembled */ + uint8_t pcomp; + uint8_t dcomp; + + /* Holds the pointers to the compression entity list + * that is used when the re-assembled packet is decompressed */ + struct llist_head *proto; + struct llist_head *data; +}; + +/* See 6.7.1.2 Reassembly */ +enum sndcp_rx_state { + SNDCP_RX_S_FIRST, + SNDCP_RX_S_SUBSEQ, + SNDCP_RX_S_DISCARD, +}; + +struct gprs_sndcp_entity { + struct llist_head list; + + /* FIXME: move this RA_ID up to the LLME or even higher */ + struct gprs_ra_id ra_id; + /* reference to the LLC Entity below this SNDCP entity */ + struct gprs_llc_lle *lle; + /* The NSAPI we shall use on top of LLC */ + uint8_t nsapi; + + /* NPDU number for the GTP->SNDCP side */ + uint16_t tx_npdu_nr; + /* SNDCP eeceiver state */ + enum sndcp_rx_state rx_state; + /* The defragmentation queue */ + struct defrag_state defrag; +}; + +extern struct llist_head gprs_sndcp_entities; + +/* Set of SNDCP-XID negotiation (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_req(struct gprs_llc_lle *lle, uint8_t nsapi); + +/* Process SNDCP-XID indication (See also: TS 144 065, + * Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_ind(struct gprs_llc_xid_field *xid_field_indication, + struct gprs_llc_xid_field *xid_field_response, + struct gprs_llc_lle *lle); + +/* Process SNDCP-XID indication + * (See also: TS 144 065, Section 6.8 XID parameter negotiation) */ +int sndcp_sn_xid_conf(struct gprs_llc_xid_field *xid_field_conf, + struct gprs_llc_xid_field *xid_field_request, + struct gprs_llc_lle *lle); + +#endif /* INT_SNDCP_H */ diff --git a/include/osmocom/sgsn/gprs_sndcp_comp.h b/include/osmocom/sgsn/gprs_sndcp_comp.h new file mode 100644 index 000000000..c04f7d49a --- /dev/null +++ b/include/osmocom/sgsn/gprs_sndcp_comp.h @@ -0,0 +1,82 @@ +/* GPRS SNDCP header compression entity management tools */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * 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 . + */ + +#pragma once + +#include +#include +#include + +/* Header / Data compression entity */ +struct gprs_sndcp_comp { + struct llist_head list; + + /* Serves as an ID in case we want to delete this entity later */ + unsigned int entity; /* see also: 6.5.1.1.3 and 6.6.1.1.3 */ + + /* Specifies to which NSAPIs the compression entity is assigned */ + uint8_t nsapi_len; /* Number of applicable NSAPIs (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + + /* Assigned pcomp values */ + uint8_t comp_len; /* Number of contained PCOMP / DCOMP values */ + uint8_t comp[MAX_COMP]; /* see also: 6.5.1.1.5 and 6.6.1.1.5 */ + + /* Algorithm parameters */ + int algo; /* Algorithm type (see gprs_sndcp_xid.h) */ + int compclass; /* See gprs_sndcp_xid.h/c */ + void *state; /* Algorithm status and parameters */ +}; + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ + +/* Allocate a compression enitiy list */ +struct llist_head *gprs_sndcp_comp_alloc(const void *ctx); + +/* Free a compression entitiy list */ +void gprs_sndcp_comp_free(struct llist_head *comp_entities); + +/* Delete a compression entity */ +void gprs_sndcp_comp_delete(struct llist_head *comp_entities, unsigned int entity); + +/* Create and Add a new compression entity + * (returns a pointer to the compression entity that has just been created) */ +struct gprs_sndcp_comp *gprs_sndcp_comp_add(const void *ctx, + struct llist_head *comp_entities, + const struct gprs_sndcp_comp_field + *comp_field); + +/* Find which compression entity handles the specified pcomp/dcomp */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_comp(const struct llist_head + *comp_entities, uint8_t comp); + +/* Find which compression entity handles the specified nsapi */ +struct gprs_sndcp_comp *gprs_sndcp_comp_by_nsapi(const struct llist_head + *comp_entities, uint8_t nsapi); + +/* Find a comp_index for a given pcomp/dcomp value */ +uint8_t gprs_sndcp_comp_get_idx(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp); + +/* Find a pcomp/dcomp value for a given comp_index */ +uint8_t gprs_sndcp_comp_get_comp(const struct gprs_sndcp_comp *comp_entity, + uint8_t comp_index); diff --git a/include/osmocom/sgsn/gprs_sndcp_dcomp.h b/include/osmocom/sgsn/gprs_sndcp_dcomp.h new file mode 100644 index 000000000..3e851421c --- /dev/null +++ b/include/osmocom/sgsn/gprs_sndcp_dcomp.h @@ -0,0 +1,53 @@ +/* GPRS SNDCP data compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * 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 . + */ + +#pragma once + +#include +#include +#include + +/* Note: The decompressed packet may have a maximum size of: + * Return value * MAX_DATADECOMPR_FAC */ +#define MAX_DATADECOMPR_FAC 10 + +/* Note: In unacknowledged mode (SN_UNITDATA), the comression state is reset + * for every NPDU. The compressor needs a reasonably large payload to operate + * effectively (yield positive compression gain). For packets shorter than 100 + * byte, no positive compression gain can be expected so we will skip the + * compression for short packets. */ +#define MIN_COMPR_PAYLOAD 100 + +/* Initalize data compression */ +int gprs_sndcp_dcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate data compression */ +void gprs_sndcp_dcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet */ +int gprs_sndcp_dcomp_expand(uint8_t *data, unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet */ +int gprs_sndcp_dcomp_compress(uint8_t *data, unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi); diff --git a/include/osmocom/sgsn/gprs_sndcp_pcomp.h b/include/osmocom/sgsn/gprs_sndcp_pcomp.h new file mode 100644 index 000000000..3e3131b52 --- /dev/null +++ b/include/osmocom/sgsn/gprs_sndcp_pcomp.h @@ -0,0 +1,46 @@ +/* GPRS SNDCP header compression handler */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * 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 . + */ + +#pragma once + +#include +#include +#include + +/* Note: The decompressed packet may have a maximum size of: + * Return value + MAX_DECOMPR_INCR */ +#define MAX_HDRDECOMPR_INCR 64 + +/* Initalize header compression */ +int gprs_sndcp_pcomp_init(const void *ctx, struct gprs_sndcp_comp *comp_entity, + const struct gprs_sndcp_comp_field *comp_field); + +/* Terminate header compression */ +void gprs_sndcp_pcomp_term(struct gprs_sndcp_comp *comp_entity); + +/* Expand packet header */ +int gprs_sndcp_pcomp_expand(uint8_t *data, unsigned int len, uint8_t pcomp, + const struct llist_head *comp_entities); + +/* Compress packet header */ +int gprs_sndcp_pcomp_compress(uint8_t *data, unsigned int len, uint8_t *pcomp, + const struct llist_head *comp_entities, + uint8_t nsapi); diff --git a/include/osmocom/sgsn/gprs_sndcp_xid.h b/include/osmocom/sgsn/gprs_sndcp_xid.h new file mode 100644 index 000000000..e64bc5237 --- /dev/null +++ b/include/osmocom/sgsn/gprs_sndcp_xid.h @@ -0,0 +1,218 @@ +/* GPRS SNDCP XID field encoding/decoding as per 3GPP TS 44.065 */ + +/* (C) 2016 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * 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 . + */ + +#pragma once + +#include +#include + +#define DEFAULT_SNDCP_VERSION 0 /* See 3GPP TS 44.065, clause 8 */ +#define MAX_ENTITIES 32 /* 3GPP TS 44.065 reserves 5 bit + * for compression enitity number */ + +#define MAX_COMP 16 /* Maximum number of possible pcomp/dcomp values */ +#define MAX_NSAPI 11 /* Maximum number usable NSAPIs */ +#define MAX_ROHC 16 /* Maximum number of ROHC compression profiles */ + +/* According to: 3GPP TS 44.065, 6.5.1.1 Format of the protocol control + * information compression field (Figure 7) and 3GPP TS 44.065, + * 6.6.1.1 Format of the data compression field (Figure 9) */ +struct gprs_sndcp_comp_field { + struct llist_head list; + + /* Propose bit (P), see also: 6.5.1.1.2 and 6.6.1.1.2 */ + unsigned int p; + + /* Entity number, see also: 6.5.1.1.3 and 6.6.1.1.3 */ + unsigned int entity; + + /* Algorithm identifier, see also: 6.5.1.1.4 and 6.6.1.1.4 */ + int algo; + + /* Number of contained PCOMP / DCOMP values */ + uint8_t comp_len; + + /* PCOMP / DCOMP values, see also: 6.5.1.1.5 and 6.6.1.1.5 */ + uint8_t comp[MAX_COMP]; + + /* Note: Only one of the following struct pointers may, + be used. Unused pointers must be set to NULL! */ + struct gprs_sndcp_pcomp_rfc1144_params *rfc1144_params; + struct gprs_sndcp_pcomp_rfc2507_params *rfc2507_params; + struct gprs_sndcp_pcomp_rohc_params *rohc_params; + struct gprs_sndcp_dcomp_v42bis_params *v42bis_params; + struct gprs_sndcp_dcomp_v44_params *v44_params; +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_hdr_comp_algo { + RFC_1144, /* TCP/IP header compression, see also 6.5.2 */ + RFC_2507, /* TCP/UDP/IP header compression, see also: 6.5.3 */ + ROHC /* Robust Header Compression, see also 6.5.4 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.1.1.4 Algorithm identifier */ +enum gprs_sndcp_data_comp_algo { + V42BIS, /* V.42bis data compression, see also 6.6.2 */ + V44 /* V44 data compression, see also: 6.6.3 */ +}; + +/* According to: 3GPP TS 44.065, 8 SNDCP XID parameters */ +enum gprs_sndcp_xid_param_types { + SNDCP_XID_VERSION_NUMBER, + SNDCP_XID_DATA_COMPRESSION, /* See also: subclause 6.6.1 */ + SNDCP_XID_PROTOCOL_COMPRESSION, /* See also: subclause 6.5.1 */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.1 Parameters (Table 5) */ +struct gprs_sndcp_pcomp_rfc1144_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int s01; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.2.2 Assignment of PCOMP values */ +enum gprs_sndcp_pcomp_rfc1144_pcomp { + RFC1144_PCOMP1, /* Uncompressed TCP */ + RFC1144_PCOMP2, /* Compressed TCP */ + RFC1144_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.1 Parameters (Table 6) */ +struct gprs_sndcp_pcomp_rfc2507_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int f_max_period; /* (default 256) */ + int f_max_time; /* (default 5) */ + int max_header; /* (default 168) */ + int tcp_space; /* (default 15) */ + int non_tcp_space; /* (default 15) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.3.2 Assignment of PCOMP values for RFC2507 */ +enum gprs_sndcp_pcomp_rfc2507_pcomp { + RFC2507_PCOMP1, /* Full Header */ + RFC2507_PCOMP2, /* Compressed TCP */ + RFC2507_PCOMP3, /* Compressed TCP non delta */ + RFC2507_PCOMP4, /* Compressed non TCP */ + RFC2507_PCOMP5, /* Context state */ + RFC2507_PCOMP_NUM /* Number of pcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.1 Parameter (Table 10) */ +struct gprs_sndcp_pcomp_rohc_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int max_cid; /* (default 15) */ + int max_header; /* (default 168) */ + uint8_t profile_len; /* (default 1) */ + uint16_t profile[MAX_ROHC]; /* (default 0, ROHC uncompressed) */ +}; + +/* According to: 3GPP TS 44.065, 6.5.4.2 Assignment of PCOMP values for ROHC */ +enum gprs_sndcp_pcomp_rohc_pcomp { + ROHC_PCOMP1, /* ROHC small CIDs */ + ROHC_PCOMP2, /* ROHC large CIDs */ + ROHC_PCOMP_NUM /* Number of pcomp values */ +}; + +/* ROHC compression profiles, see also: + http://www.iana.org/assignments/rohc-pro-ids/rohc-pro-ids.xhtml */ +enum gprs_sndcp_xid_rohc_profiles { + ROHC_UNCOMPRESSED = 0x0000, /* ROHC uncompressed [RFC5795] */ + ROHC_RTP = 0x0001, /* ROHC RTP [RFC3095] */ + ROHCV2_RTP = 0x0101, /* ROHCv2 RTP [RFC5225] */ + ROHC_UDP = 0x0002, /* ROHC UDP [RFC3095] */ + ROHCv2_UDP = 0x0102, /* ROHCv2 UDP [RFC5225] */ + ROHC_ESP = 0x0003, /* ROHC ESP [RFC3095] */ + ROHCV2_ESP = 0x0103, /* ROHCv2 ESP [RFC5225] */ + ROHC_IP = 0x0004, /* ROHC IP [RFC3843] */ + ROHCV2_IP = 0x0104, /* ROHCv2 IP [RFC5225] */ + ROHC_LLA = 0x0005, /* ROHC LLA [RFC4362] */ + ROHC_LLA_WITH_R_MODE = 0x0105, /* ROHC LLA with R-mode [RFC3408] */ + ROHC_TCP = 0x0006, /* ROHC TCP [RFC6846] */ + ROHC_RTP_UDP_LITE = 0x0007, /* ROHC RTP/UDP-Lite [RFC4019] */ + ROHCV2_RTP_UDP_LITE = 0x0107, /* ROHCv2 RTP/UDP-Lite [RFC5225] */ + ROHC_UDP_LITE = 0x0008, /* ROHC UDP-Lite [RFC4019] */ + ROHCV2_UDP_LITE = 0x0108, /* ROHCv2 UDP-Lite [RFC5225] */ +}; + +/* According to: 3GPP TS 44.065, 6.6.2.1 Parameters (Table 7a) */ +struct gprs_sndcp_dcomp_v42bis_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int p0; /* (default 3) */ + int p1; /* (default 2048) */ + int p2; /* (default 20) */ + +}; + +/* According to: 3GPP TS 44.065, 6.6.2.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v42bis_dcomp { + V42BIS_DCOMP1, /* V.42bis enabled */ + V42BIS_DCOMP_NUM /* Number of dcomp values */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.1 Parameters (Table 7c) */ +struct gprs_sndcp_dcomp_v44_params { + uint8_t nsapi_len; /* Number of applicable NSAPIs + * (default 0) */ + uint8_t nsapi[MAX_NSAPI]; /* Applicable NSAPIs (default 0) */ + int c0; /* (default 10000000) */ + int p0; /* (default 3) */ + int p1t; /* Refer to subclause 6.6.3.1.4 */ + int p1r; /* Refer to subclause 6.6.3.1.5 */ + int p3t; /* (default 3 x p1t) */ + int p3r; /* (default 3 x p1r) */ +}; + +/* According to: 3GPP TS 44.065, 6.6.3.2 Assignment of DCOMP values */ +enum gprs_sndcp_dcomp_v44_dcomp { + V44_DCOMP1, /* Packet method compressed */ + V44_DCOMP2, /* Multi packet method compressed */ + V44_DCOMP_NUM /* Number of dcomp values */ +}; + +/* Transform a list with compression fields into an SNDCP-XID message (dst) */ +int gprs_sndcp_compile_xid(uint8_t *dst, unsigned int dst_maxlen, + const struct llist_head *comp_fields, int version); + +/* Transform an SNDCP-XID message (src) into a list of SNDCP-XID fields */ +struct llist_head *gprs_sndcp_parse_xid(int *version, + const void *ctx, + const uint8_t *src, + unsigned int src_len, + const struct llist_head + *comp_fields_req); + +/* Find out to which compression class the specified comp-field belongs + * (header compression or data compression?) */ +int gprs_sndcp_get_compression_class( + const struct gprs_sndcp_comp_field *comp_field); + +/* Dump a list with SNDCP-XID fields (Debug) */ +void gprs_sndcp_dump_comp_fields(const struct llist_head *comp_fields, + unsigned int logl); + diff --git a/include/osmocom/sgsn/gprs_subscriber.h b/include/osmocom/sgsn/gprs_subscriber.h new file mode 100644 index 000000000..be78febff --- /dev/null +++ b/include/osmocom/sgsn/gprs_subscriber.h @@ -0,0 +1,31 @@ +/* GPRS subscriber details for use in SGSN land */ +#pragma once + +#include + +#include +#include + +extern struct llist_head * const gprs_subscribers; + +struct gprs_subscr { + struct llist_head entry; + int use_count; + + char imsi[GSM23003_IMSI_MAX_DIGITS+1]; + uint32_t tmsi; + char imei[GSM23003_IMEISV_NUM_DIGITS+1]; + bool authorized; + bool keep_in_ram; + uint32_t flags; + uint16_t lac; + + struct sgsn_subscriber_data *sgsn_data; +}; + +struct gprs_subscr *_gprs_subscr_get(struct gprs_subscr *gsub, + const char *file, int line); +struct gprs_subscr *_gprs_subscr_put(struct gprs_subscr *gsub, + const char *file, int line); +#define gprs_subscr_get(gsub) _gprs_subscr_get(gsub, __BASE_FILE__, __LINE__) +#define gprs_subscr_put(gsub) _gprs_subscr_put(gsub, __BASE_FILE__, __LINE__) diff --git a/include/osmocom/sgsn/gprs_utils.h b/include/osmocom/sgsn/gprs_utils.h new file mode 100644 index 000000000..e06364dad --- /dev/null +++ b/include/osmocom/sgsn/gprs_utils.h @@ -0,0 +1,55 @@ +/* GPRS utility functions */ + +/* (C) 2010 by Harald Welte + * (C) 2010-2014 by On-Waves + * (C) 2013 by Holger Hans Peter Freyther + * 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 . + * + */ +#pragma once + +#include +#include + +#include + +struct msgb; +struct gprs_ra_id; + +struct msgb *gprs_msgb_copy(const struct msgb *msg, const char *name); +int gprs_msgb_resize_area(struct msgb *msg, uint8_t *area, + size_t old_size, size_t new_size); +int gprs_str_to_apn(uint8_t *apn_enc, size_t max_len, const char *str); + +/* GSM 04.08, 10.5.7.3 GPRS Timer */ +int gprs_tmr_to_secs(uint8_t tmr); +uint8_t gprs_secs_to_tmr_floor(int secs); + +int gprs_is_mi_tmsi(const uint8_t *value, size_t value_len); +int gprs_is_mi_imsi(const uint8_t *value, size_t value_len); +int gprs_parse_mi_tmsi(const uint8_t *value, size_t value_len, uint32_t *tmsi); +void gprs_parse_tmsi(const uint8_t *value, uint32_t *tmsi); + +int gprs_ra_id_equals(const struct gprs_ra_id *id1, const struct gprs_ra_id *id2); + +#define GSM48_ALLOC_SIZE 2048 +#define GSM48_ALLOC_HEADROOM 256 + +static inline struct msgb *gsm48_msgb_alloc_name(const char *name) +{ + return msgb_alloc_headroom(GSM48_ALLOC_SIZE, GSM48_ALLOC_HEADROOM, + name); +} diff --git a/include/osmocom/sgsn/gsup_client.h b/include/osmocom/sgsn/gsup_client.h new file mode 100644 index 000000000..29092ad5b --- /dev/null +++ b/include/osmocom/sgsn/gsup_client.h @@ -0,0 +1,63 @@ +/* GPRS Subscriber Update Protocol client */ + +/* (C) 2014 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Jacob Erlbeck + * + * 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 . + * + */ +#pragma once + +#include + +#include + +#define GSUP_CLIENT_RECONNECT_INTERVAL 10 +#define GSUP_CLIENT_PING_INTERVAL 20 + +struct msgb; +struct ipa_client_conn; +struct gsup_client; + +/* Expects message in msg->l2h */ +typedef int (*gsup_client_read_cb_t)(struct gsup_client *gsupc, + struct msgb *msg); + +struct gsup_client { + const char *unit_name; + + struct ipa_client_conn *link; + gsup_client_read_cb_t read_cb; + void *data; + + struct oap_client_state oap_state; + + struct osmo_timer_list ping_timer; + struct osmo_timer_list connect_timer; + int is_connected; + int got_ipa_pong; +}; + +struct gsup_client *gsup_client_create(const char *unit_name, + const char *ip_addr, + unsigned int tcp_port, + gsup_client_read_cb_t read_cb, + struct oap_client_config *oapc_config); + +void gsup_client_destroy(struct gsup_client *gsupc); +int gsup_client_send(struct gsup_client *gsupc, struct msgb *msg); +struct msgb *gsup_client_msgb_alloc(void); + diff --git a/include/osmocom/sgsn/gtphub.h b/include/osmocom/sgsn/gtphub.h new file mode 100644 index 000000000..8fd9f38cf --- /dev/null +++ b/include/osmocom/sgsn/gtphub.h @@ -0,0 +1,523 @@ +/* GTP Hub Implementation */ + +/* (C) 2015 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Neels Hofmeyr + * + * 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 . + */ + +#pragma once + +#include +#include + +#include +#include +#include + +#include + + +/* support */ + +/* TODO move to osmocom/core/socket.c ? */ +#include /* for IPPROTO_* etc */ +struct osmo_sockaddr { + struct sockaddr_storage a; + socklen_t l; +}; + +/* TODO move to osmocom/core/socket.c ? */ +/*! \brief Initialize a sockaddr + * \param[out] addr Valid osmo_sockaddr pointer to write result to + * \param[in] family Address Family like AF_INET, AF_INET6, AF_UNSPEC + * \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM + * \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP + * \param[in] host Remote host name or IP address in string form + * \param[in] port Remote port number in host byte order + * \returns 0 on success, otherwise an error code (from getaddrinfo()). + * + * Copy the first result from a getaddrinfo() call with the given parameters to + * *addr and *addr_len. On error, do not change *addr and return nonzero. + */ +int osmo_sockaddr_init(struct osmo_sockaddr *addr, + uint16_t family, uint16_t type, uint8_t proto, + const char *host, uint16_t port); + +/* Conveniently pass AF_UNSPEC, SOCK_DGRAM and IPPROTO_UDP to + * osmo_sockaddr_init(). */ +static inline int osmo_sockaddr_init_udp(struct osmo_sockaddr *addr, + const char *host, uint16_t port) +{ + return osmo_sockaddr_init(addr, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, + host, port); +} + +/*! \brief convert sockaddr to human readable string. + * \param[out] addr_str Valid pointer to a buffer of length addr_str_len. + * \param[in] addr_str_len Size of buffer addr_str points at. + * \param[out] port_str Valid pointer to a buffer of length port_str_len. + * \param[in] port_str_len Size of buffer port_str points at. + * \param[in] addr Binary representation as returned by osmo_sockaddr_init(). + * \param[in] flags flags as passed to getnameinfo(). + * \returns 0 on success, an error code on error. + * + * Return the IPv4 or IPv6 address string and the port (a.k.a. service) string + * representations of the given struct osmo_sockaddr in two caller provided + * char buffers. Flags of (NI_NUMERICHOST | NI_NUMERICSERV) return numeric + * address and port. Either one of addr_str or port_str may be NULL, in which + * case nothing is returned there. + * + * See also osmo_sockaddr_to_str() (less flexible, but much more convenient). */ +int osmo_sockaddr_to_strs(char *addr_str, size_t addr_str_len, + char *port_str, size_t port_str_len, + const struct osmo_sockaddr *addr, + int flags); + + +/*! \brief concatenate the parts returned by osmo_sockaddr_to_strs(). + * \param[in] addr Binary representation as returned by osmo_sockaddr_init(). + * \param[in] buf A buffer to use for string operations. + * \param[in] buf_len Length of the buffer. + * \returns Address string (in buffer). + * + * Compose a string of the numeric IP-address and port represented by *addr of + * the form " port ". The returned string is valid until the + * next invocation of this function. + */ +const char *osmo_sockaddr_to_strb(const struct osmo_sockaddr *addr, + char *buf, size_t buf_len); + +/*! \brief conveniently return osmo_sockaddr_to_strb() in a static buffer. + * \param[in] addr Binary representation as returned by osmo_sockaddr_init(). + * \returns Address string in static buffer. + * + * See osmo_sockaddr_to_strb(). + * + * Note: only one osmo_sockaddr_to_str() call will work per print/log + * statement. For two or more, use osmo_sockaddr_to_strb() with a separate + * buffer each. + */ +const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *addr); + +/*! \brief compare two osmo_sockaddr. + * \param[in] a The first address to compare. + * \param[in] b The other address to compare. + * \returns 0 if equal, otherwise -1 or 1. + */ +int osmo_sockaddr_cmp(const struct osmo_sockaddr *a, + const struct osmo_sockaddr *b); + +/*! \brief Overwrite *dst with *src. + * Like memcpy(), but copy only the valid bytes. */ +void osmo_sockaddr_copy(struct osmo_sockaddr *dst, + const struct osmo_sockaddr *src); + + +/* general */ + +enum gtphub_plane_idx { + GTPH_PLANE_CTRL = 0, + GTPH_PLANE_USER = 1, + GTPH_PLANE_N +}; + +enum gtphub_side_idx { + GTPH_SIDE_SGSN = 0, + GTPH_SIDE_GGSN = 1, + GTPH_SIDE_N +}; + +#define for_each_side(I) for (I = 0; I < GTPH_SIDE_N; I++) +#define for_each_plane(I) for (I = 0; I < GTPH_PLANE_N; I++) +#define for_each_side_and_plane(I,J) for_each_side(I) for_each_plane(J) + +static inline int other_side_idx(int side_idx) +{ + return (side_idx + 1) & 1; +} + +extern const char* const gtphub_plane_idx_names[GTPH_PLANE_N]; +extern const uint16_t gtphub_plane_idx_default_port[GTPH_PLANE_N]; + +extern const char* const gtphub_side_idx_names[GTPH_SIDE_N]; + +/* A host address in the form that is expected in the 7.7.32 GSN Address IE. + * len is either 4 (IPv4) or 16 (IPv6), any other value is invalid. If no + * address is set, len shall be 0. */ +struct gsn_addr { + uint16_t len; + uint8_t buf[16]; +}; + +void gsn_addr_copy(struct gsn_addr *gsna, const struct gsn_addr *src); +int gsn_addr_from_str(struct gsn_addr *gsna, const char *numeric_addr_str); + +/* Return gsna in numeric string form, in a static buffer. */ +const char *gsn_addr_to_str(const struct gsn_addr *gsna); + +/* note: strbuf_len doesn't need to be larger than INET6_ADDRSTRLEN + 1. */ +const char *gsn_addr_to_strb(const struct gsn_addr *gsna, + char *strbuf, int strbuf_len); + +/* Return 1 on match, zero otherwise. */ +int gsn_addr_same(const struct gsn_addr *a, const struct gsn_addr *b); + +/* Decode sa to gsna. Return 0 on success. If port is non-NULL, the port number + * from sa is also returned. */ +int gsn_addr_from_sockaddr(struct gsn_addr *gsna, uint16_t *port, + const struct osmo_sockaddr *sa); + +/* expiry */ + +struct expiring_item; +typedef void (*del_cb_t)(struct expiring_item *); + +struct expiring_item { + struct llist_head entry; + time_t expiry; + del_cb_t del_cb; +}; + +struct expiry { + int expiry_in_seconds; + struct llist_head items; +}; + +/* Initialize an expiry queue. */ +void expiry_init(struct expiry *exq, int expiry_in_seconds); + +/* Add a new mapping, or restart the expiry timeout for an already listed + * mapping. */ +void expiry_add(struct expiry *exq, struct expiring_item *item, time_t now); + +/* Initialize to all-empty; must be called before using the item in any way. */ +void expiring_item_init(struct expiring_item *item); + +/* Remove the given item from its expiry queue, and call item->del_cb, if set. + * This sets item->del_cb to NULL and is harmless when run a second time on the + * same item, so the del_cb may choose to call this function, too, to allow + * deleting items from several code paths. */ +void expiring_item_del(struct expiring_item *item); + +/* Carry out due expiry of mappings. Must be invoked regularly. + * 'now' is the current clock count in seconds and must correspond to the clock + * count passed to nr_map_add(). A monotonous clock counter should be used. */ +int expiry_tick(struct expiry *exq, time_t now); + +/* Expire all items. */ +void expiry_clear(struct expiry *exq); + + +/* number map */ + +/* A number map assigns a "random" mapped number to each user provided number. + * If the same number is requested multiple times, the same mapped number is + * returned. + * + * Number maps plug into possibly shared pools and expiry queues, for example: + * + * mapA -----------+-> pool1 <-+-- mapB + * {10->1, 11->5} | {1, 2, 3, ...} | {10->2, 11->3} + * | | + * | | + * /-> \-> expiry1 <-/ + * | (30 seconds) + * | + * mapC -------+-----> pool2 <-+-- mapD + * {10->1, 11->3} {1, 2, 3, ...} | {10->2, 11->5} + * | + * expiry2 <-/ + * (60 seconds) + * + * A map contains mappings ("10->1"). Each map needs a number pool, which can + * be shared with other maps. Each new mapping receives a number from the pool, + * which is then unavailable to any other map using the same pool. + * + * A map may point at an expiry queue, in which case all mappings added to it + * are also appended to the expiry queue (using a separate llist entry in the + * mapping). Any number of maps may submit to the same expiry queue, if they + * desire the same expiry timeout. An expiry queue stores the mappings in + * chronological order, so that expiry checking is needed only from the start + * of the queue; hence only mappings with identical expiry timeout can be added + * to the same expiry queue. Upon expiry, a mapping is dropped from the map it + * was submitted at. expiry_tick() needs to be called regularly for each expiry + * queue. + * + * A nr_mapping can be embedded in a larger struct: each mapping can have a + * distinct destructor (del_cb), and each del_cb can figure out the container + * struct's address and free that upon expiry or manual deletion. So in expiry + * queues (and even maps), mappings of different container types can be mixed. + * This can help to drastically reduce the amount of unnecessary visits during + * expiry checking, for the case that no expiry is pending. An expiry queue + * always knows which mappings to expire next, because they are right at the + * start of its list. + * + * Mapping allocation and a del_cb are provided by the caller. If del_cb is + * NULL, no deallocation will be done (allowing statically allocated entries). + */ + +typedef unsigned int nr_t; + +/* Generator for unused numbers. So far this counts upwards from zero, but the + * implementation may change in the future. Treat this like an opaque struct. + * If this becomes random, the tests need to be fixed. */ +struct nr_pool { + nr_t last_nr; + nr_t nr_min; + nr_t nr_max; +}; + +struct nr_mapping { + struct llist_head entry; + struct expiring_item expiry_entry; + + void *origin; + nr_t orig; + nr_t repl; +}; + +struct nr_map { + struct nr_pool *pool; /* multiple nr_maps can share a nr_pool. */ + struct expiry *add_items_to_expiry; + struct llist_head mappings; +}; + + +void nr_pool_init(struct nr_pool *pool, nr_t nr_min, nr_t nr_max); + +/* Return the next unused number from the nr_pool. */ +nr_t nr_pool_next(struct nr_pool *pool); + +/* Initialize the nr_mapping to zero/empty values. */ +void nr_mapping_init(struct nr_mapping *mapping); + +/* Remove the given mapping from its parent map and expiry queue, and call + * mapping->del_cb, if set. */ +void nr_mapping_del(struct nr_mapping *mapping); + +/* Initialize an (already allocated) nr_map, and set the map's number pool. + * Multiple nr_map instances may use the same nr_pool. Set the nr_map's expiry + * queue to exq, so that all added mappings are automatically expired after the + * time configured in exq. exq may be NULL to disable automatic expiry. */ +void nr_map_init(struct nr_map *map, struct nr_pool *pool, + struct expiry *exq); + +/* Add a new entry to the map. mapping->orig, mapping->origin and + * mapping->del_cb must be set before calling this function. The remaining + * fields of *mapping will be overwritten. mapping->repl is set to the next + * available mapped number from map->pool. 'now' is the current clock count in + * seconds; if no map->expiry is used, just pass 0 for 'now'. */ +void nr_map_add(struct nr_map *map, struct nr_mapping *mapping, + time_t now); + +/* Restart the timeout for the given mapping. mapping must be a member of map. + */ +void nr_map_refresh(struct nr_map *map, struct nr_mapping *mapping, + time_t now); + +/* Return a known mapping from nr_orig and the given origin. If nr_orig is + * unknown, return NULL. */ +struct nr_mapping *nr_map_get(const struct nr_map *map, + void *origin, nr_t nr_orig); + +/* Return a known mapping to nr_repl. If nr_repl is unknown, return NULL. */ +struct nr_mapping *nr_map_get_inv(const struct nr_map *map, nr_t nr_repl); + +/* Remove all mappings from map. */ +void nr_map_clear(struct nr_map *map); + +/* Return 1 if map has no entries, 0 otherwise. */ +int nr_map_empty(const struct nr_map *map); + + +/* config */ + +static const int GTPH_EXPIRE_QUICKLY_SECS = 30; /* TODO is there a spec for this? */ +static const int GTPH_EXPIRE_SLOWLY_MINUTES = 6 * 60; /* TODO is there a spec for this? */ + +struct gtphub_cfg_addr { + const char *addr_str; + uint16_t port; +}; + +struct gtphub_cfg_bind { + struct gtphub_cfg_addr bind; +}; + +struct gtphub_cfg { + struct gtphub_cfg_bind to_gsns[GTPH_SIDE_N][GTPH_PLANE_N]; + struct gtphub_cfg_addr proxy[GTPH_SIDE_N][GTPH_PLANE_N]; + int sgsn_use_sender; /* Use sender, not GSN addr IE with std ports */ +}; + + +/* state */ + +struct gtphub_peer { + struct llist_head entry; + + struct llist_head addresses; /* Alternatives, not load balancing. */ + struct nr_pool seq_pool; + struct nr_map seq_map; +}; + +struct gtphub_peer_addr { + struct llist_head entry; + + struct gtphub_peer *peer; + struct gsn_addr addr; + struct llist_head ports; +}; + +struct gtphub_peer_port { + struct llist_head entry; + + struct gtphub_peer_addr *peer_addr; + uint16_t port; + unsigned int ref_count; /* references from other peers' seq_maps */ + struct osmo_sockaddr sa; /* a "cache" for (peer_addr->addr, port) */ + int last_restart_count; /* 0..255 = valid, all else means unknown */ + + struct rate_ctr_group *counters_io; +}; + +struct gtphub_tunnel_endpoint { + struct gtphub_peer_port *peer; + uint32_t tei_orig; /* from/to peer */ + + struct rate_ctr_group *counters_io; +}; + +struct gtphub_tunnel { + struct llist_head entry; + struct expiring_item expiry_entry; + + uint32_t tei_repl; /* unique TEI to replace peers' TEIs */ + struct gtphub_tunnel_endpoint endpoint[GTPH_SIDE_N][GTPH_PLANE_N]; +}; + +struct gtphub_bind { + struct gsn_addr local_addr; + uint16_t local_port; + struct osmo_fd ofd; + + /* list of struct gtphub_peer */ + struct llist_head peers; + + const char *label; /* For logging */ + struct rate_ctr_group *counters_io; +}; + +struct gtphub_resolved_ggsn { + struct llist_head entry; + struct expiring_item expiry_entry; + + /* The APN OI, the Operator Identifier, is the combined address, + * including parts of the IMSI and APN NI, and ending with ".gprs". */ + char apn_oi_str[GSM_APN_LENGTH]; + + /* Which address and port we resolved that to. */ + struct gtphub_peer_port *peer; +}; + +struct gtphub { + struct gtphub_bind to_gsns[GTPH_SIDE_N][GTPH_PLANE_N]; + + /* pointers to an entry of to_gsns[s][p].peers */ + struct gtphub_peer_port *proxy[GTPH_SIDE_N][GTPH_PLANE_N]; + + /* The TEI numbers will simply wrap and be reused, which will work out + * in practice. Problems would arise if one given peer maintained the + * same TEI for a time long enough for the TEI nr map to wrap an entire + * uint32_t; if a new TEI were mapped every second, this would take + * more than 100 years (in which a single given TEI must not time out) + * to cause a problem. */ + struct nr_pool tei_pool; + + struct llist_head tunnels; /* struct gtphub_tunnel */ + struct llist_head pending_deletes; /* opaque (gtphub.c) */ + + struct llist_head ggsn_lookups; /* opaque (gtphub_ares.c) */ + struct llist_head resolved_ggsns; /* struct gtphub_resolved_ggsn */ + + struct osmo_timer_list gc_timer; + struct expiry expire_quickly; + struct expiry expire_slowly; + + uint8_t restart_counter; + + int sgsn_use_sender; +}; + +struct gtp_packet_desc; + + +/* api */ + +int gtphub_vty_init(struct gtphub *global_hub, struct gtphub_cfg *global_cfg); +int gtphub_cfg_read(struct gtphub_cfg *cfg, const char *config_file); + +/* Initialize and start gtphub: bind to ports, run expiry timers. */ +int gtphub_start(struct gtphub *hub, struct gtphub_cfg *cfg, + uint8_t restart_counter); + +/* Close all sockets, expire all maps and peers and free all allocations. The + * struct is then unusable, unless gtphub_start() is run on it again. */ +void gtphub_stop(struct gtphub *hub); + +time_t gtphub_now(void); + +/* Remove expired items, empty peers, ... */ +void gtphub_gc(struct gtphub *hub, time_t now); + +/* Return the string of the first address for this peer. */ +const char *gtphub_peer_str(struct gtphub_peer *peer); + +/* Return a human readable description of tun in a static buffer. */ +const char *gtphub_tunnel_str(struct gtphub_tunnel *tun); + +/* Return 1 if all of tun's endpoints are fully established, 0 otherwise. */ +int gtphub_tunnel_complete(struct gtphub_tunnel *tun); + +int gtphub_handle_buf(struct gtphub *hub, + unsigned int side_idx, + unsigned int port_idx, + const struct osmo_sockaddr *from_addr, + uint8_t *buf, + size_t received, + time_t now, + uint8_t **reply_buf, + struct osmo_fd **to_ofd, + struct osmo_sockaddr *to_addr); + +struct gtphub_peer_port *gtphub_port_have(struct gtphub *hub, + struct gtphub_bind *bind, + const struct gsn_addr *addr, + uint16_t port); + +struct gtphub_peer_port *gtphub_port_find_sa(const struct gtphub_bind *bind, + const struct osmo_sockaddr *addr); + +void gtphub_resolved_ggsn(struct gtphub *hub, const char *apn_oi_str, + struct gsn_addr *resolved_addr, + time_t now); + +const char *gtphub_port_str(struct gtphub_peer_port *port); + +int gtphub_write(const struct osmo_fd *to, + const struct osmo_sockaddr *to_addr, + const uint8_t *buf, size_t buf_len); diff --git a/include/osmocom/sgsn/oap_client.h b/include/osmocom/sgsn/oap_client.h new file mode 100644 index 000000000..80c86d5d6 --- /dev/null +++ b/include/osmocom/sgsn/oap_client.h @@ -0,0 +1,82 @@ +/* Osmocom Authentication Protocol API */ + +/* (C) 2015 by Sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Neels Hofmeyr + * + * 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 . + * + */ + +#pragma once + +#include + +struct msgb; +struct osmo_oap_message; + +/* This is the config part for vty. It is essentially copied in + * oap_client_state, where values are copied over once the config is + * considered valid. */ +struct oap_client_config { + uint16_t client_id; + int secret_k_present; + uint8_t secret_k[16]; + int secret_opc_present; + uint8_t secret_opc[16]; +}; + +/* The runtime state of the OAP client. client_id and the secrets are in fact + * duplicated from oap_client_config, so that a separate validation of the + * config data is possible, and so that only a struct oap_client_state* is + * passed around. */ +struct oap_client_state { + enum { + OAP_UNINITIALIZED = 0, /* just allocated. */ + OAP_DISABLED, /* disabled by config. */ + OAP_INITIALIZED, /* enabled, config is valid. */ + OAP_REQUESTED_CHALLENGE, + OAP_SENT_CHALLENGE_RESULT, + OAP_REGISTERED + } state; + uint16_t client_id; + uint8_t secret_k[16]; + uint8_t secret_opc[16]; + int registration_failures; +}; + +/* From config, initialize state. Return 0 on success. */ +int oap_client_init(struct oap_client_config *config, + struct oap_client_state *state); + +/* Construct an OAP registration message and return in *msg_tx. Use + * state->client_id and update state->state. + * Return 0 on success, or a negative value on error. + * If an error is returned, *msg_tx is guaranteed to be NULL. */ +int oap_client_register(struct oap_client_state *state, struct msgb **msg_tx); + +/* Decode and act on a received OAP message msg_rx. Update state->state. If a + * non-NULL pointer is returned in *msg_tx, that msgb should be sent to the OAP + * server (and freed) by the caller. The received msg_rx is not freed. + * Return 0 on success, or a negative value on error. + * If an error is returned, *msg_tx is guaranteed to be NULL. */ +int oap_client_handle(struct oap_client_state *state, + const struct msgb *msg_rx, struct msgb **msg_tx); + +/* Allocate a msgb and in it, return the encoded oap_client_msg. Return + * NULL on error. (Like oap_client_encode(), but also allocates a msgb.) + * About the name: the idea is do_something(oap_client_encoded(my_struct)) + */ +struct msgb *oap_client_encoded(const struct osmo_oap_message *oap_client_msg); diff --git a/include/osmocom/sgsn/rest_octets.h b/include/osmocom/sgsn/rest_octets.h new file mode 100644 index 000000000..0dbe7ae13 --- /dev/null +++ b/include/osmocom/sgsn/rest_octets.h @@ -0,0 +1,139 @@ +#ifndef _REST_OCTETS_H +#define _REST_OCTETS_H + +#include +#include +#include + +/* generate SI1 rest octets */ +int rest_octets_si1(uint8_t *data, uint8_t *nch_pos, int is1800_net); +int rest_octets_si2quater(uint8_t *data, struct gsm_bts *bts); +int rest_octets_si6(uint8_t *data, bool is1800_net); + +struct gsm48_si_selection_params { + uint16_t penalty_time:5, + temp_offs:3, + cell_resel_off:6, + cbq:1, + present:1; +}; + +struct gsm48_si_power_offset { + uint8_t power_offset:2, + present:1; +}; + +struct gsm48_si3_gprs_ind { + uint8_t si13_position:1, + ra_colour:3, + present:1; +}; + +struct gsm48_lsa_params { + uint32_t prio_thr:3, + lsa_offset:3, + mcc:12, + mnc:12; + unsigned int present; +}; + +struct gsm48_si_ro_info { + struct gsm48_si_selection_params selection_params; + struct gsm48_si_power_offset power_offset; + uint8_t si2ter_indicator; + uint8_t early_cm_ctrl; + struct { + uint8_t where:3, + present:1; + } scheduling; + struct gsm48_si3_gprs_ind gprs_ind; + /* SI 3 specific */ + uint8_t si2quater_indicator; + /* SI 4 specific */ + struct gsm48_lsa_params lsa_params; + uint16_t cell_id; + uint8_t break_ind; /* do we have SI7 + SI8 ? */ +}; + + +/* Generate SI3 Rest Octests (Chapter 10.5.2.34 / Table 10.4.72) */ +int rest_octets_si3(uint8_t *data, const struct gsm48_si_ro_info *si3); + +/* Generate SI4 Rest Octets (Chapter 10.5.2.35) */ +int rest_octets_si4(uint8_t *data, const struct gsm48_si_ro_info *si4, int len); + +enum pbcch_carrier_type { + PBCCH_BCCH, + PBCCH_ARFCN, + PBCCH_MAIO +}; + +/* TS 03.60 Chapter 6.3.3.1: Network Mode of Operation */ +enum gprs_nmo { + GPRS_NMO_I = 0, /* CS pagin on GPRS paging or traffic channel */ + GPRS_NMO_II = 1, /* all paging on CCCH */ + GPRS_NMO_III = 2, /* no paging coordination */ +}; + +/* TS 04.60 12.24 */ +struct gprs_cell_options { + enum gprs_nmo nmo; + /* T3168: wait for packet uplink assignment message */ + uint32_t t3168; /* in milliseconds */ + /* T3192: wait for release of the TBF after reception of the final block */ + uint32_t t3192; /* in milliseconds */ + uint32_t drx_timer_max;/* in seconds */ + uint32_t bs_cv_max; + uint8_t supports_egprs_11bit_rach; + bool ctrl_ack_type_use_block; /* use PACKET CONTROL ACKNOWLEDGMENT */ + + uint8_t ext_info_present; + struct { + uint8_t egprs_supported; + uint8_t use_egprs_p_ch_req; + uint8_t bep_period; + uint8_t pfc_supported; + uint8_t dtm_supported; + uint8_t bss_paging_coordination; + } ext_info; +}; + +/* TS 04.60 Table 12.9.2 */ +struct gprs_power_ctrl_pars { + uint8_t alpha; + uint8_t t_avg_w; + uint8_t t_avg_t; + uint8_t pc_meas_chan; + uint8_t n_avg_i; +}; + +struct gsm48_si13_info { + struct gprs_cell_options cell_opts; + struct gprs_power_ctrl_pars pwr_ctrl_pars; + uint8_t bcch_change_mark; + uint8_t si_change_field; + uint8_t pbcch_present; + + union { + struct { + uint8_t rac; + uint8_t spgc_ccch_sup; + uint8_t net_ctrl_ord; + uint8_t prio_acc_thr; + } no_pbcch; + struct { + uint8_t psi1_rep_per; + uint8_t pb; + uint8_t tsc; + uint8_t tn; + enum pbcch_carrier_type carrier_type; + uint16_t arfcn; + uint8_t maio; + } pbcch; + }; +}; + +/* Generate SI13 Rest Octests (Chapter 10.5.2.37b) */ +int rest_octets_si13(uint8_t *data, const struct gsm48_si13_info *si13); + +#endif /* _REST_OCTETS_H */ diff --git a/include/osmocom/sgsn/sgsn.h b/include/osmocom/sgsn/sgsn.h new file mode 100644 index 000000000..e4eda17d2 --- /dev/null +++ b/include/osmocom/sgsn/sgsn.h @@ -0,0 +1,191 @@ +#ifndef _SGSN_H +#define _SGSN_H + + +#include +#include +#include +#include +#include +#include + +#include + +struct gprs_gsup_client; +struct hostent; + +enum sgsn_auth_policy { + SGSN_AUTH_POLICY_OPEN, + SGSN_AUTH_POLICY_CLOSED, + SGSN_AUTH_POLICY_ACL_ONLY, + SGSN_AUTH_POLICY_REMOTE +}; + + +enum sgsn_rate_ctr_keys { + CTR_LLC_DL_BYTES, + CTR_LLC_UL_BYTES, + CTR_LLC_DL_PACKETS, + CTR_LLC_UL_PACKETS, + CTR_GPRS_ATTACH_REQUEST, + CTR_GPRS_ATTACH_ACKED, + CTR_GPRS_ATTACH_REJECTED, + CTR_GPRS_DETACH_REQUEST, + CTR_GPRS_DETACH_ACKED, + CTR_GPRS_ROUTING_AREA_REQUEST, + CTR_GPRS_ROUTING_AREA_ACKED, + CTR_GPRS_ROUTING_AREA_REJECT, + /* PDP single packet counter / GSM 04.08 9.5.1 - 9.5.9 */ + CTR_PDP_ACTIVATE_REQUEST, + CTR_PDP_ACTIVATE_REJECT, + CTR_PDP_ACTIVATE_ACCEPT, + CTR_PDP_REQUEST_ACTIVATE, /* unused */ + CTR_PDP_REQUEST_ACTIVATE_REJ, /* unused */ + CTR_PDP_MODIFY_REQUEST, /* unsued */ + CTR_PDP_MODIFY_ACCEPT, /* unused */ + CTR_PDP_DL_DEACTIVATE_REQUEST, + CTR_PDP_DL_DEACTIVATE_ACCEPT, + CTR_PDP_UL_DEACTIVATE_REQUEST, + CTR_PDP_UL_DEACTIVATE_ACCEPT, +}; + +struct sgsn_cdr { + char *filename; + int interval; +}; + +struct sgsn_config { + /* parsed from config file */ + + char *gtp_statedir; + struct sockaddr_in gtp_listenaddr; + + /* misc */ + struct gprs_ns_inst *nsi; + + enum sgsn_auth_policy auth_policy; + enum gprs_ciph_algo cipher; + struct llist_head imsi_acl; + + struct sockaddr_in gsup_server_addr; + int gsup_server_port; + + int require_authentication; + int require_update_location; + + /* CDR configuration */ + struct sgsn_cdr cdr; + + struct { + int T3312; + int T3322; + int T3350; + int T3360; + int T3370; + int T3313; + int T3314; + int T3316; + int T3385; + int T3386; + int T3395; + int T3397; + } timers; + + int dynamic_lookup; + + struct oap_client_config oap; + + /* RFC1144 TCP/IP header compression */ + struct { + int active; + int passive; + int s01; + } pcomp_rfc1144; + + /* V.42vis data compression */ + struct { + int active; + int passive; + int p0; + int p1; + int p2; + } dcomp_v42bis; + + struct { + int rab_assign_addr_enc; + } iu; +}; + +struct sgsn_instance { + char *config_file; + struct sgsn_config cfg; + /* File descriptor wrappers for LibGTP */ + struct osmo_fd gtp_fd0; + struct osmo_fd gtp_fd1c; + struct osmo_fd gtp_fd1u; + /* Timer for libGTP */ + struct osmo_timer_list gtp_timer; + /* GSN instance for libgtp */ + struct gsn_t *gsn; + /* Subscriber */ + struct gsup_client *gsup_client; + /* LLME inactivity timer */ + struct osmo_timer_list llme_timer; + + /* c-ares event loop integration */ + struct osmo_timer_list ares_timer; + struct llist_head ares_fds; + ares_channel ares_channel; + struct ares_addr_node *ares_servers; + + struct rate_ctr_group *rate_ctrs; +}; + +extern struct sgsn_instance *sgsn; + +/* sgsn_vty.c */ + +int sgsn_vty_init(struct sgsn_config *cfg); +int sgsn_parse_config(const char *config_file); + +/* sgsn.c */ + +/* Main input function for Gb proxy */ +int sgsn_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci); + + +struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct sgsn_ggsn_ctx *ggsn, + struct sgsn_mm_ctx *mmctx, + uint16_t nsapi, + struct tlv_parsed *tp); +int sgsn_delete_pdp_ctx(struct sgsn_pdp_ctx *pctx); +void sgsn_pdp_upd_gtp_u(struct sgsn_pdp_ctx *pdp, void *addr, size_t alen); + +/* gprs_sndcp.c */ + +/* Entry point for the SNSM-ACTIVATE.indication */ +int sndcp_sm_activate_ind(struct gprs_llc_lle *lle, uint8_t nsapi); +/* Entry point for the SNSM-DEACTIVATE.indication */ +int sndcp_sm_deactivate_ind(struct gprs_llc_lle *lle, uint8_t nsapi); +/* Called by SNDCP when it has received/re-assembled a N-PDU */ +int sgsn_rx_sndcp_ud_ind(struct gprs_ra_id *ra_id, int32_t tlli, uint8_t nsapi, + struct msgb *msg, uint32_t npdu_len, uint8_t *npdu); +int sndcp_unitdata_req(struct msgb *msg, struct gprs_llc_lle *lle, uint8_t nsapi, + void *mmcontext); +int sndcp_llunitdata_ind(struct msgb *msg, struct gprs_llc_lle *lle, + uint8_t *hdr, uint16_t len); + + +/* + * CDR related functionality + */ +int sgsn_cdr_init(struct sgsn_instance *sgsn); + + +/* + * C-ARES related functionality + */ +int sgsn_ares_init(struct sgsn_instance *sgsn); +int sgsn_ares_query(struct sgsn_instance *sgsm, const char *name, ares_host_callback cb, void *data); + +#endif diff --git a/include/osmocom/sgsn/signal.h b/include/osmocom/sgsn/signal.h new file mode 100644 index 000000000..4b6ba56f6 --- /dev/null +++ b/include/osmocom/sgsn/signal.h @@ -0,0 +1,52 @@ +/* Generic signalling/notification infrastructure */ +/* (C) 2009-2010, 2015 by Holger Hans Peter Freyther + * (C) 2009 by Harald Welte + * (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 . + * + */ + +#ifndef OPENBSC_SIGNAL_H +#define OPENBSC_SIGNAL_H + +#include +#include + +#include + +enum signal_subsystems { + SS_SGSN, +}; + +/* GPRS SGSN signals SS_SGSN */ +enum signal_sgsn { + S_SGSN_ATTACH, + S_SGSN_DETACH, + S_SGSN_UPDATE, + S_SGSN_PDP_ACT, + S_SGSN_PDP_DEACT, + S_SGSN_PDP_TERMINATE, + S_SGSN_PDP_FREE, + S_SGSN_MM_FREE, +}; + +struct sgsn_mm_ctx; +struct sgsn_signal_data { + struct sgsn_mm_ctx *mm; + struct sgsn_pdp_ctx *pdp; /* non-NULL for PDP_ACT, PDP_DEACT, PDP_FREE */ +}; + +#endif diff --git a/include/osmocom/sgsn/slhc.h b/include/osmocom/sgsn/slhc.h new file mode 100644 index 000000000..cd5a47cf4 --- /dev/null +++ b/include/osmocom/sgsn/slhc.h @@ -0,0 +1,187 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens@ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson@um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowledgment, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + + +#include +#include + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef __u8 byte_t; +typedef __u32 int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +/* In slhc.c: */ +struct slcompress *slhc_init(const void *ctx, int rslots, int tslots); + +void slhc_free(struct slcompress *comp); + +int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid); +int slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize); +int slhc_toss(struct slcompress *comp); + +void slhc_i_status(struct slcompress *comp); +void slhc_o_status(struct slcompress *comp); + +#endif /* _SLHC_H */ diff --git a/include/osmocom/sgsn/v42bis.h b/include/osmocom/sgsn/v42bis.h new file mode 100644 index 000000000..607a58e51 --- /dev/null +++ b/include/osmocom/sgsn/v42bis.h @@ -0,0 +1,147 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005, 2011 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*! \page v42bis_page V.42bis modem data compression +\section v42bis_page_sec_1 What does it do? +The v.42bis specification defines a data compression scheme, to work in +conjunction with the error correction scheme defined in V.42. + +\section v42bis_page_sec_2 How does it work? +*/ + +#include + +#if !defined(_SPANDSP_V42BIS_H_) +#define _SPANDSP_V42BIS_H_ + +#define SPAN_DECLARE(x) x + +#define V42BIS_MIN_STRING_SIZE 6 +#define V42BIS_MAX_STRING_SIZE 250 +#define V42BIS_MIN_DICTIONARY_SIZE 512 +#define V42BIS_MAX_BITS 12 +#define V42BIS_MAX_CODEWORDS 4096 /* 2^V42BIS_MAX_BITS */ +#define V42BIS_MAX_OUTPUT_LENGTH 1024 + +enum +{ + V42BIS_P0_NEITHER_DIRECTION = 0, + V42BIS_P0_INITIATOR_RESPONDER, + V42BIS_P0_RESPONDER_INITIATOR, + V42BIS_P0_BOTH_DIRECTIONS +}; + +enum +{ + V42BIS_COMPRESSION_MODE_DYNAMIC = 0, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER +}; + +typedef void (*put_msg_func_t)(void *user_data, const uint8_t *msg, int len); + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +typedef struct v42bis_state_s v42bis_state_t; + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/*! Compress a block of octets. + \param s The V.42bis context. + \param buf The data to be compressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress(v42bis_state_t *s, const uint8_t buf[], int len); + +/*! Flush out any data remaining in a compression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_compress_flush(v42bis_state_t *s); + +/*! Decompress a block of octets. + \param s The V.42bis context. + \param buf The data to be decompressed. + \param len The length of the data buffer. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress(v42bis_state_t *s, const uint8_t buf[], int len); + +/*! Flush out any data remaining in the decompression buffer. + \param s The V.42bis context. + \return 0 */ +SPAN_DECLARE(int) v42bis_decompress_flush(v42bis_state_t *s); + +/*! Set the compression mode. + \param s The V.42bis context. + \param mode One of the V.42bis compression modes - + V42BIS_COMPRESSION_MODE_DYNAMIC, + V42BIS_COMPRESSION_MODE_ALWAYS, + V42BIS_COMPRESSION_MODE_NEVER */ +SPAN_DECLARE(void) v42bis_compression_control(v42bis_state_t *s, int mode); + +/*! Initialise a V.42bis context. + \param s The V.42bis context. + \param negotiated_p0 The negotiated P0 parameter, from the V.42bis spec. + \param negotiated_p1 The negotiated P1 parameter, from the V.42bis spec. + \param negotiated_p2 The negotiated P2 parameter, from the V.42bis spec. + \param encode_handler Encode callback handler. + \param encode_user_data An opaque pointer passed to the encode callback handler. + \param max_encode_len The maximum length that should be passed to the encode handler. + \param decode_handler Decode callback handler. + \param decode_user_data An opaque pointer passed to the decode callback handler. + \param max_decode_len The maximum length that should be passed to the decode handler. + \return The V.42bis context. */ +SPAN_DECLARE(v42bis_state_t *) v42bis_init(const void *ctx, + v42bis_state_t *s, + int negotiated_p0, + int negotiated_p1, + int negotiated_p2, + put_msg_func_t encode_handler, + void *encode_user_data, + int max_encode_len, + put_msg_func_t decode_handler, + void *decode_user_data, + int max_decode_len); + +/*! Release a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_release(v42bis_state_t *s); + +/*! Free a V.42bis context. + \param s The V.42bis context. + \return 0 if OK */ +SPAN_DECLARE(int) v42bis_free(v42bis_state_t *s); + +#if defined(__cplusplus) +} +#endif + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/include/osmocom/sgsn/v42bis_private.h b/include/osmocom/sgsn/v42bis_private.h new file mode 100644 index 000000000..daa5ea315 --- /dev/null +++ b/include/osmocom/sgsn/v42bis_private.h @@ -0,0 +1,126 @@ +/* + * SpanDSP - a series of DSP components for telephony + * + * private/v42bis.h + * + * Written by Steve Underwood + * + * Copyright (C) 2005 Steve Underwood + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1, + * as published by the Free Software Foundation. + * + * 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#if !defined(_SPANDSP_PRIVATE_V42BIS_H_) +#define _SPANDSP_PRIVATE_V42BIS_H_ + +/*! + V.42bis dictionary node. + Note that 0 is not a valid node to point to (0 is always a control code), so 0 is used + as a "no such value" marker in this structure. +*/ +typedef struct +{ + /*! \brief The value of the octet represented by the current dictionary node */ + uint8_t node_octet; + /*! \brief The parent of this node */ + uint16_t parent; + /*! \brief The first child of this node */ + uint16_t child; + /*! \brief The next node at the same depth */ + uint16_t next; +} v42bis_dict_node_t; + +/*! + V.42bis compression or decompression. This defines the working state for a single instance + of V.42bis compression or decompression. +*/ +typedef struct +{ + /*! \brief Compression enabled. */ + int v42bis_parm_p0; + /*! \brief Compression mode. */ + int compression_mode; + /*! \brief Callback function to handle output data. */ + put_msg_func_t handler; + /*! \brief An opaque pointer passed in calls to the data handler. */ + void *user_data; + /*! \brief The maximum amount to be passed to the data handler. */ + int max_output_len; + + /*! \brief TRUE if we are in transparent (i.e. uncompressable) mode */ + int transparent; + /*! \brief Next empty dictionary entry */ + uint16_t v42bis_parm_c1; + /*! \brief Current codeword size */ + uint16_t v42bis_parm_c2; + /*! \brief Threshold for codeword size change */ + uint16_t v42bis_parm_c3; + /*! \brief The current update point in the dictionary */ + uint16_t update_at; + /*! \brief The last entry matched in the dictionary */ + uint16_t last_matched; + /*! \brief The last entry added to the dictionary */ + uint16_t last_added; + /*! \brief Total number of codewords in the dictionary */ + int v42bis_parm_n2; + /*! \brief Maximum permitted string length */ + int v42bis_parm_n7; + /*! \brief The dictionary */ + v42bis_dict_node_t dict[V42BIS_MAX_CODEWORDS]; + + /*! \brief The octet string in progress */ + uint8_t string[V42BIS_MAX_STRING_SIZE]; + /*! \brief The current length of the octet string in progress */ + int string_length; + /*! \brief The amount of the octet string in progress which has already + been flushed out of the buffer */ + int flushed_length; + + /*! \brief Compression performance metric */ + uint16_t compression_performance; + + /*! \brief Outgoing bit buffer (compression), or incoming bit buffer (decompression) */ + uint32_t bit_buffer; + /*! \brief Outgoing bit count (compression), or incoming bit count (decompression) */ + int bit_count; + + /*! \brief The output composition buffer */ + uint8_t output_buf[V42BIS_MAX_OUTPUT_LENGTH]; + /*! \brief The length of the contents of the output composition buffer */ + int output_octet_count; + + /*! \brief The current value of the escape code */ + uint8_t escape_code; + /*! \brief TRUE if we just hit an escape code, and are waiting for the following octet */ + int escaped; +} v42bis_comp_state_t; + +/*! + V.42bis compression/decompression descriptor. This defines the working state for a + single instance of V.42bis compress/decompression. +*/ +struct v42bis_state_s +{ + /*! \brief Compression state. */ + v42bis_comp_state_t compress; + /*! \brief Decompression state. */ + v42bis_comp_state_t decompress; + + /*! \brief Error and flow logging control */ +}; + +#endif +/*- End of file ------------------------------------------------------------*/ diff --git a/include/osmocom/sgsn/vty.h b/include/osmocom/sgsn/vty.h new file mode 100644 index 000000000..d2e3d9a73 --- /dev/null +++ b/include/osmocom/sgsn/vty.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +enum bsc_vty_node { + GBPROXY_NODE = _LAST_OSMOVTY_NODE + 1, + SGSN_NODE, + GTPHUB_NODE, +}; -- cgit v1.2.3