summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2012-06-17 14:06:05 +0800
committerHarald Welte <laforge@gnumonks.org>2012-06-17 14:06:05 +0800
commitaa0c796158c5f394eadf2aaa6070253a34992829 (patch)
treee06db7a10f6c14a39487dab9a7afbdf8ec3ccf7c
parent2d52d10a52b40910427786c6f5cb314cce1ceccf (diff)
parent8648e49a1c10ec2f6d1560aa3f6c70b059eb52c7 (diff)
Import libgb from openbsc.git
-rw-r--r--openbsc/include/osmocom/gprs/Makefile.am5
-rw-r--r--openbsc/include/osmocom/gprs/gprs_bssgp.h166
-rw-r--r--openbsc/include/osmocom/gprs/gprs_msgb.h37
-rw-r--r--openbsc/include/osmocom/gprs/gprs_ns.h189
-rw-r--r--openbsc/include/osmocom/gprs/gprs_ns_frgre.h6
-rw-r--r--openbsc/include/osmocom/gprs/protocol/Makefile.am3
-rw-r--r--openbsc/include/osmocom/gprs/protocol/gsm_08_16.h85
-rw-r--r--openbsc/include/osmocom/gprs/protocol/gsm_08_18.h144
-rw-r--r--openbsc/src/libgb/Makefile.am9
-rw-r--r--openbsc/src/libgb/common_vty.c90
-rw-r--r--openbsc/src/libgb/common_vty.h14
-rw-r--r--openbsc/src/libgb/gprs_bssgp.c919
-rw-r--r--openbsc/src/libgb/gprs_bssgp_bss.c425
-rw-r--r--openbsc/src/libgb/gprs_bssgp_util.c117
-rw-r--r--openbsc/src/libgb/gprs_bssgp_vty.c187
-rw-r--r--openbsc/src/libgb/gprs_ns.c1103
-rw-r--r--openbsc/src/libgb/gprs_ns_frgre.c310
-rw-r--r--openbsc/src/libgb/gprs_ns_vty.c581
-rw-r--r--openbsc/src/libgb/libosmo-gb.map59
19 files changed, 4449 insertions, 0 deletions
diff --git a/openbsc/include/osmocom/gprs/Makefile.am b/openbsc/include/osmocom/gprs/Makefile.am
new file mode 100644
index 00000000..d39592c1
--- /dev/null
+++ b/openbsc/include/osmocom/gprs/Makefile.am
@@ -0,0 +1,5 @@
+libgb_HEADERS = gprs_bssgp.h gprs_ns.h gprs_ns_frgre.h gprs_msgb.h
+
+libgbdir = $(includedir)/osmocom/gprs
+
+SUBDIRS = protocol
diff --git a/openbsc/include/osmocom/gprs/gprs_bssgp.h b/openbsc/include/osmocom/gprs/gprs_bssgp.h
new file mode 100644
index 00000000..949dbdc8
--- /dev/null
+++ b/openbsc/include/osmocom/gprs/gprs_bssgp.h
@@ -0,0 +1,166 @@
+#ifndef _GPRS_BSSGP_H
+#define _GPRS_BSSGP_H
+
+#include <stdint.h>
+
+#include <osmocom/gsm/gsm48.h>
+#include <osmocom/gsm/prim.h>
+
+#include <osmocom/gprs/protocol/gsm_08_18.h>
+
+/* gprs_bssgp_util.c */
+extern struct gprs_ns_inst *bssgp_nsi;
+struct msgb *bssgp_msgb_alloc(void);
+const char *bssgp_cause_str(enum gprs_bssgp_cause cause);
+/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */
+int bssgp_tx_simple_bvci(uint8_t pdu_type, uint16_t nsei,
+ uint16_t bvci, uint16_t ns_bvci);
+/* Chapter 10.4.14: Status */
+int bssgp_tx_status(uint8_t cause, uint16_t *bvci, struct msgb *orig_msg);
+
+enum bssgp_prim {
+ PRIM_BSSGP_DL_UD,
+ PRIM_BSSGP_UL_UD,
+ PRIM_BSSGP_PTM_UD,
+
+ PRIM_BSSGP_GMM_SUSPEND,
+ PRIM_BSSGP_GMM_RESUME,
+ PRIM_BSSGP_GMM_PAGING,
+
+ PRIM_NM_FLUSH_LL,
+ PRIM_NM_LLC_DISCARDED,
+ PRIM_NM_BVC_RESET,
+ PRIM_NM_BVC_BLOCK,
+ PRIM_NM_BVC_UNBLOCK,
+};
+
+struct osmo_bssgp_prim {
+ struct osmo_prim_hdr oph;
+
+ /* common fields */
+ uint16_t nsei;
+ uint16_t bvci;
+ uint32_t tlli;
+ struct tlv_parsed *tp;
+ struct gprs_ra_id *ra_id;
+
+ /* specific fields */
+ union {
+ struct {
+ uint8_t *suspend_ref;
+ } resume;
+ } u;
+};
+
+/* gprs_bssgp.c */
+
+#define BVC_S_BLOCKED 0x0001
+
+/* The per-BTS context that we keep on the SGSN side of the BSSGP link */
+struct bssgp_bvc_ctx {
+ struct llist_head list;
+
+ struct gprs_ra_id ra_id; /*!< parsed RA ID of the remote BTS */
+ uint16_t cell_id; /*!< Cell ID of the remote BTS */
+
+ /* NSEI and BVCI of underlying Gb link. Together they
+ * uniquely identify a link to a BTS (5.4.4) */
+ uint16_t bvci;
+ uint16_t nsei;
+
+ uint32_t state;
+
+ struct rate_ctr_group *ctrg;
+
+ /* we might want to add this as a shortcut later, avoiding the NSVC
+ * lookup for every packet, similar to a routing cache */
+ //struct gprs_nsvc *nsvc;
+};
+extern struct llist_head bssgp_bvc_ctxts;
+/* Find a BTS Context based on parsed RA ID and Cell ID */
+struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid);
+/* Find a BTS context based on BVCI+NSEI tuple */
+struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei);
+
+#define BVC_F_BLOCKED 0x0001
+
+enum bssgp_ctr {
+ BSSGP_CTR_PKTS_IN,
+ BSSGP_CTR_PKTS_OUT,
+ BSSGP_CTR_BYTES_IN,
+ BSSGP_CTR_BYTES_OUT,
+ BSSGP_CTR_BLOCKED,
+ BSSGP_CTR_DISCARDED,
+};
+
+
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/gprs/gprs_msgb.h>
+
+/* BSSGP-UL-UNITDATA.ind */
+int bssgp_rcvmsg(struct msgb *msg);
+
+/* BSSGP-DL-UNITDATA.req */
+struct bssgp_lv {
+ uint16_t len;
+ uint8_t *v;
+};
+/* parameters for BSSGP downlink userdata transmission */
+struct bssgp_dl_ud_par {
+ uint32_t *tlli;
+ char *imsi;
+ uint16_t drx_parms;
+ /* FIXME: priority */
+ struct bssgp_lv ms_ra_cap;
+ uint8_t qos_profile[3];
+};
+int bssgp_tx_dl_ud(struct msgb *msg, uint16_t pdu_lifetime,
+ struct bssgp_dl_ud_par *dup);
+
+uint16_t bssgp_parse_cell_id(struct gprs_ra_id *raid, const uint8_t *buf);
+int bssgp_create_cell_id(uint8_t *buf, const struct gprs_ra_id *raid,
+ uint16_t cid);
+
+/* Wrapper around TLV parser to parse BSSGP IEs */
+static inline int bssgp_tlv_parse(struct tlv_parsed *tp, uint8_t *buf, int len)
+{
+ return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0);
+}
+
+/*! \brief BSSGP Paging mode */
+enum bssgp_paging_mode {
+ BSSGP_PAGING_PS,
+ BSSGP_PAGING_CS,
+};
+
+/*! \brief BSSGP Paging scope */
+enum bssgp_paging_scope {
+ BSSGP_PAGING_BSS_AREA, /*!< all cells in BSS */
+ BSSGP_PAGING_LOCATION_AREA, /*!< all cells in LA */
+ BSSGP_PAGING_ROUTEING_AREA, /*!< all cells in RA */
+ BSSGP_PAGING_BVCI, /*!< one cell */
+};
+
+/*! \brief BSSGP paging information */
+struct bssgp_paging_info {
+ enum bssgp_paging_mode mode; /*!< CS or PS paging */
+ enum bssgp_paging_scope scope; /*!< bssgp_paging_scope */
+ struct gprs_ra_id raid; /*!< RA Identifier */
+ uint16_t bvci; /*!< BVCI */
+ char *imsi; /*!< IMSI, if any */
+ uint32_t *ptmsi; /*!< P-TMSI, if any */
+ uint16_t drx_params; /*!< DRX parameters */
+ uint8_t qos[3]; /*!< QoS parameters */
+};
+
+/* Send a single GMM-PAGING.req to a given NSEI/NS-BVCI */
+int bssgp_tx_paging(uint16_t nsei, uint16_t ns_bvci,
+ struct bssgp_paging_info *pinfo);
+
+/* gprs_bssgp_vty.c */
+int bssgp_vty_init(void);
+void bssgp_set_log_ss(int ss);
+
+int bssgp_prim_cb(struct osmo_prim_hdr *oph, void *ctx);
+
+#endif /* _GPRS_BSSGP_H */
diff --git a/openbsc/include/osmocom/gprs/gprs_msgb.h b/openbsc/include/osmocom/gprs/gprs_msgb.h
new file mode 100644
index 00000000..f4c85547
--- /dev/null
+++ b/openbsc/include/osmocom/gprs/gprs_msgb.h
@@ -0,0 +1,37 @@
+#ifndef _LIBGB_MSGB_H
+#define _LIBGB_MSGB_H
+
+#include <stdint.h>
+/* the data structure stored in msgb->cb for libgb apps */
+struct libgb_msgb_cb {
+ unsigned char *bssgph;
+ unsigned char *llch;
+
+ /* Cell Identifier */
+ unsigned char *bssgp_cell_id;
+
+ /* Identifiers of a BTS, equal to 'struct bssgp_bts_ctx' */
+ uint16_t nsei;
+ uint16_t bvci;
+
+ /* Identifier of a MS (inside BTS), equal to 'struct sgsn_mm_ctx' */
+ uint32_t tlli;
+} __attribute__((packed));
+#define LIBGB_MSGB_CB(__msgb) ((struct libgb_msgb_cb *)&((__msgb)->cb[0]))
+#define msgb_tlli(__x) LIBGB_MSGB_CB(__x)->tlli
+#define msgb_nsei(__x) LIBGB_MSGB_CB(__x)->nsei
+#define msgb_bvci(__x) LIBGB_MSGB_CB(__x)->bvci
+#define msgb_gmmh(__x) (__x)->l3h
+#define msgb_bssgph(__x) LIBGB_MSGB_CB(__x)->bssgph
+#define msgb_bssgp_len(__x) ((__x)->tail - (uint8_t *)msgb_bssgph(__x))
+#define msgb_bcid(__x) LIBGB_MSGB_CB(__x)->bssgp_cell_id
+#define msgb_llch(__x) LIBGB_MSGB_CB(__x)->llch
+
+/* logging contexts */
+#define GPRS_CTX_NSVC 0
+#define GPRS_CTX_BVC 1
+
+#include <osmocom/core/logging.h>
+int gprs_log_filter_fn(const struct log_context *ctx,
+ struct log_target *tar);
+#endif
diff --git a/openbsc/include/osmocom/gprs/gprs_ns.h b/openbsc/include/osmocom/gprs/gprs_ns.h
new file mode 100644
index 00000000..a7f32b25
--- /dev/null
+++ b/openbsc/include/osmocom/gprs/gprs_ns.h
@@ -0,0 +1,189 @@
+#ifndef _GPRS_NS_H
+#define _GPRS_NS_H
+
+#include <stdint.h>
+
+/* Our Implementation */
+#include <netinet/in.h>
+#include <osmocom/core/linuxlist.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/select.h>
+#include <osmocom/gprs/gprs_msgb.h>
+
+#include <osmocom/gprs/protocol/gsm_08_16.h>
+
+#define NS_TIMERS_COUNT 7
+#define NS_TIMERS "(tns-block|tns-block-retries|tns-reset|tns-reset-retries|tns-test|tns-alive|tns-alive-retries)"
+#define NS_TIMERS_HELP \
+ "(un)blocking Timer (Tns-block) timeout\n" \
+ "(un)blocking Timer (Tns-block) number of retries\n" \
+ "Reset Timer (Tns-reset) timeout\n" \
+ "Reset Timer (Tns-reset) number of retries\n" \
+ "Test Timer (Tns-test) timeout\n" \
+ "Alive Timer (Tns-alive) timeout\n" \
+ "Alive Timer (Tns-alive) number of retries\n"
+
+enum ns_timeout {
+ NS_TOUT_TNS_BLOCK,
+ NS_TOUT_TNS_BLOCK_RETRIES,
+ NS_TOUT_TNS_RESET,
+ NS_TOUT_TNS_RESET_RETRIES,
+ NS_TOUT_TNS_TEST,
+ NS_TOUT_TNS_ALIVE,
+ NS_TOUT_TNS_ALIVE_RETRIES,
+};
+
+#define NSE_S_BLOCKED 0x0001
+#define NSE_S_ALIVE 0x0002
+
+/*! \brief Osmocom NS link layer types */
+enum gprs_ns_ll {
+ GPRS_NS_LL_UDP, /*!< NS/UDP/IP */
+ GPRS_NS_LL_E1, /*!< NS/E1 */
+ GPRS_NS_LL_FR_GRE, /*!< NS/FR/GRE/IP */
+};
+
+/*! \brief Osmoco NS events */
+enum gprs_ns_evt {
+ GPRS_NS_EVT_UNIT_DATA,
+};
+
+struct gprs_nsvc;
+/*! \brief Osmocom GPRS callback function type */
+typedef int gprs_ns_cb_t(enum gprs_ns_evt event, struct gprs_nsvc *nsvc,
+ struct msgb *msg, uint16_t bvci);
+
+/*! \brief An instance of the NS protocol stack */
+struct gprs_ns_inst {
+ /*! \brief callback to the user for incoming UNIT DATA IND */
+ gprs_ns_cb_t *cb;
+
+ /*! \brief linked lists of all NSVC in this instance */
+ struct llist_head gprs_nsvcs;
+
+ /*! \brief a NSVC object that's needed to deal with packets for
+ * unknown NSVC */
+ struct gprs_nsvc *unknown_nsvc;
+
+ uint16_t timeout[NS_TIMERS_COUNT];
+
+ /*! \brief NS-over-IP specific bits */
+ struct {
+ struct osmo_fd fd;
+ uint32_t local_ip;
+ uint16_t local_port;
+ } nsip;
+ /*! \brief NS-over-FR-over-GRE-over-IP specific bits */
+ struct {
+ struct osmo_fd fd;
+ uint32_t local_ip;
+ unsigned int enabled:1;
+ } frgre;
+};
+
+enum nsvc_timer_mode {
+ /* standard timers */
+ NSVC_TIMER_TNS_TEST,
+ NSVC_TIMER_TNS_ALIVE,
+ NSVC_TIMER_TNS_RESET,
+ _NSVC_TIMER_NR,
+};
+
+/*! \brief Structure representing a single NS-VC */
+struct gprs_nsvc {
+ /*! \brief list of NS-VCs within NS Instance */
+ struct llist_head list;
+ /*! \brief pointer to NS Instance */
+ struct gprs_ns_inst *nsi;
+
+ uint16_t nsei; /*! \brief end-to-end significance */
+ uint16_t nsvci; /*! \brief uniquely identifies NS-VC at SGSN */
+
+ uint32_t state;
+ uint32_t remote_state;
+
+ struct osmo_timer_list timer;
+ enum nsvc_timer_mode timer_mode;
+ int alive_retries;
+
+ unsigned int remote_end_is_sgsn:1;
+ unsigned int persistent:1;
+
+ struct rate_ctr_group *ctrg;
+
+ /*! \brief which link-layer are we based on? */
+ enum gprs_ns_ll ll;
+
+ union {
+ struct {
+ struct sockaddr_in bts_addr;
+ } ip;
+ struct {
+ struct sockaddr_in bts_addr;
+ } frgre;
+ };
+};
+
+/* Create a new NS protocol instance */
+struct gprs_ns_inst *gprs_ns_instantiate(gprs_ns_cb_t *cb, void *ctx);
+
+/* Destroy a NS protocol instance */
+void gprs_ns_destroy(struct gprs_ns_inst *nsi);
+
+/* Listen for incoming GPRS packets via NS/UDP */
+int gprs_ns_nsip_listen(struct gprs_ns_inst *nsi);
+
+/* Establish a connection (from the BSS) to the SGSN */
+struct gprs_nsvc *gprs_ns_nsip_connect(struct gprs_ns_inst *nsi,
+ struct sockaddr_in *dest,
+ uint16_t nsei, uint16_t nsvci);
+
+
+struct sockaddr_in;
+
+/* main function for higher layers (BSSGP) to send NS messages */
+int gprs_ns_sendmsg(struct gprs_ns_inst *nsi, struct msgb *msg);
+
+int gprs_ns_tx_reset(struct gprs_nsvc *nsvc, uint8_t cause);
+int gprs_ns_tx_block(struct gprs_nsvc *nsvc, uint8_t cause);
+int gprs_ns_tx_unblock(struct gprs_nsvc *nsvc);
+
+/* Listen for incoming GPRS packets via NS/FR/GRE */
+int gprs_ns_frgre_listen(struct gprs_ns_inst *nsi);
+
+struct gprs_nsvc *gprs_nsvc_create(struct gprs_ns_inst *nsi, uint16_t nsvci);
+void gprs_nsvc_delete(struct gprs_nsvc *nsvc);
+struct gprs_nsvc *gprs_nsvc_by_nsei(struct gprs_ns_inst *nsi, uint16_t nsei);
+struct gprs_nsvc *gprs_nsvc_by_nsvci(struct gprs_ns_inst *nsi, uint16_t nsvci);
+
+/* Initiate a RESET procedure (including timer start, ...)*/
+void gprs_nsvc_reset(struct gprs_nsvc *nsvc, uint8_t cause);
+
+/* Add NS-specific VTY stuff */
+int gprs_ns_vty_init(struct gprs_ns_inst *nsi);
+
+#define NS_ALLOC_SIZE 2048
+#define NS_ALLOC_HEADROOM 20
+static inline struct msgb *gprs_ns_msgb_alloc(void)
+{
+ return msgb_alloc_headroom(NS_ALLOC_SIZE, NS_ALLOC_HEADROOM, "GPRS/NS");
+}
+
+enum signal_ns {
+ S_NS_RESET,
+ S_NS_BLOCK,
+ S_NS_UNBLOCK,
+ S_NS_ALIVE_EXP, /* Tns-alive expired more than N times */
+};
+
+struct ns_signal_data {
+ struct gprs_nsvc *nsvc;
+ uint8_t cause;
+};
+
+void gprs_ns_set_log_ss(int ss);
+
+/*! }@ */
+
+#endif
diff --git a/openbsc/include/osmocom/gprs/gprs_ns_frgre.h b/openbsc/include/osmocom/gprs/gprs_ns_frgre.h
new file mode 100644
index 00000000..abcd43ff
--- /dev/null
+++ b/openbsc/include/osmocom/gprs/gprs_ns_frgre.h
@@ -0,0 +1,6 @@
+#ifndef _GPRS_NS_FRGRE_H
+#define _GPRS_NS_FRGRE_H
+
+int gprs_ns_frgre_sendmsg(struct gprs_nsvc *nsvc, struct msgb *msg);
+
+#endif
diff --git a/openbsc/include/osmocom/gprs/protocol/Makefile.am b/openbsc/include/osmocom/gprs/protocol/Makefile.am
new file mode 100644
index 00000000..8255a952
--- /dev/null
+++ b/openbsc/include/osmocom/gprs/protocol/Makefile.am
@@ -0,0 +1,3 @@
+libgbp_HEADERS = gsm_08_16.h gsm_08_18.h
+
+libgbpdir = $(includedir)/osmocom/gprs/protocol
diff --git a/openbsc/include/osmocom/gprs/protocol/gsm_08_16.h b/openbsc/include/osmocom/gprs/protocol/gsm_08_16.h
new file mode 100644
index 00000000..4c3eda32
--- /dev/null
+++ b/openbsc/include/osmocom/gprs/protocol/gsm_08_16.h
@@ -0,0 +1,85 @@
+#ifndef _OSMO_08_16_H
+#define _OSMO_08_16_H
+
+/* GPRS Networks Service (NS) messages on the Gb interface
+ * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05)
+ * 3GPP TS 48.016 version 6.5.0 Release 6 / ETSI TS 148 016 V6.5.0 (2005-11) */
+
+#include <stdint.h>
+
+/*! \addtogroup libgb
+ * @{
+ */
+
+/*! \file gprs_ns.h */
+
+/*! \brief Common header of GPRS NS */
+struct gprs_ns_hdr {
+ uint8_t pdu_type; /*!< NS PDU type */
+ uint8_t data[0]; /*!< variable-length payload */
+} __attribute__((packed));
+
+/*! \brief NS PDU Type (TS 08.16, Section 10.3.7, Table 14) */
+enum ns_pdu_type {
+ NS_PDUT_UNITDATA = 0x00,
+ NS_PDUT_RESET = 0x02,
+ NS_PDUT_RESET_ACK = 0x03,
+ NS_PDUT_BLOCK = 0x04,
+ NS_PDUT_BLOCK_ACK = 0x05,
+ NS_PDUT_UNBLOCK = 0x06,
+ NS_PDUT_UNBLOCK_ACK = 0x07,
+ NS_PDUT_STATUS = 0x08,
+ NS_PDUT_ALIVE = 0x0a,
+ NS_PDUT_ALIVE_ACK = 0x0b,
+ /* TS 48.016 Section 10.3.7, Table 10.3.7.1 */
+ SNS_PDUT_ACK = 0x0c,
+ SNS_PDUT_ADD = 0x0d,
+ SNS_PDUT_CHANGE_WEIGHT = 0x0e,
+ SNS_PDUT_CONFIG = 0x0f,
+ SNS_PDUT_CONFIG_ACK = 0x10,
+ SNS_PDUT_DELETE = 0x11,
+ SNS_PDUT_SIZE = 0x12,
+ SNS_PDUT_SIZE_ACK = 0x13,
+};
+
+/*! \brief NS Control IE (TS 08.16, Section 10.3, Table 12) */
+enum ns_ctrl_ie {
+ NS_IE_CAUSE = 0x00,
+ NS_IE_VCI = 0x01,
+ NS_IE_PDU = 0x02,
+ NS_IE_BVCI = 0x03,
+ NS_IE_NSEI = 0x04,
+ /* TS 48.016 Section 10.3, Table 10.3.1 */
+ NS_IE_IPv4_LIST = 0x05,
+ NS_IE_IPv6_LIST = 0x06,
+ NS_IE_MAX_NR_NSVC = 0x07,
+ NS_IE_IPv4_EP_NR = 0x08,
+ NS_IE_IPv6_EP_NR = 0x09,
+ NS_IE_RESET_FLAG = 0x0a,
+ NS_IE_IP_ADDR = 0x0b,
+};
+
+/*! \brief NS Cause (TS 08.16, Section 10.3.2, Table 13) */
+enum ns_cause {
+ NS_CAUSE_TRANSIT_FAIL = 0x00,
+ NS_CAUSE_OM_INTERVENTION = 0x01,
+ NS_CAUSE_EQUIP_FAIL = 0x02,
+ NS_CAUSE_NSVC_BLOCKED = 0x03,
+ NS_CAUSE_NSVC_UNKNOWN = 0x04,
+ NS_CAUSE_BVCI_UNKNOWN = 0x05,
+ NS_CAUSE_SEM_INCORR_PDU = 0x08,
+ NS_CAUSE_PDU_INCOMP_PSTATE = 0x0a,
+ NS_CAUSE_PROTO_ERR_UNSPEC = 0x0b,
+ NS_CAUSE_INVAL_ESSENT_IE = 0x0c,
+ NS_CAUSE_MISSING_ESSENT_IE = 0x0d,
+ /* TS 48.016 Section 10.3.2, Table 10.3.2.1 */
+ NS_CAUSE_INVAL_NR_IPv4_EP = 0x0e,
+ NS_CAUSE_INVAL_NR_IPv6_EP = 0x0f,
+ NS_CAUSE_INVAL_NR_NS_VC = 0x10,
+ NS_CAUSE_INVAL_WEIGH = 0x11,
+ NS_CAUSE_UNKN_IP_EP = 0x12,
+ NS_CAUSE_UNKN_IP_ADDR = 0x13,
+ NS_CAUSE_UNKN_IP_TEST_FAILED = 0x14,
+};
+
+#endif
diff --git a/openbsc/include/osmocom/gprs/protocol/gsm_08_18.h b/openbsc/include/osmocom/gprs/protocol/gsm_08_18.h
new file mode 100644
index 00000000..3a351eaa
--- /dev/null
+++ b/openbsc/include/osmocom/gprs/protocol/gsm_08_18.h
@@ -0,0 +1,144 @@
+#ifndef _OSMO_08_18_H
+#define _OSMO_08_18_H
+
+#include <stdint.h>
+
+/*! \brief Fixed BVCI definitions (Section 5.4.1) */
+#define BVCI_SIGNALLING 0x0000
+#define BVCI_PTM 0x0001
+
+/*! \brief BSSGP PDU types (Section 11.3.26 / Table 11.27) */
+enum bssgp_pdu_type {
+ /* PDUs between RL and BSSGP SAPs */
+ BSSGP_PDUT_DL_UNITDATA = 0x00,
+ BSSGP_PDUT_UL_UNITDATA = 0x01,
+ BSSGP_PDUT_RA_CAPABILITY = 0x02,
+ BSSGP_PDUT_PTM_UNITDATA = 0x03,
+ /* PDUs between GMM SAPs */
+ BSSGP_PDUT_PAGING_PS = 0x06,
+ BSSGP_PDUT_PAGING_CS = 0x07,
+ BSSGP_PDUT_RA_CAPA_UDPATE = 0x08,
+ BSSGP_PDUT_RA_CAPA_UPDATE_ACK = 0x09,
+ BSSGP_PDUT_RADIO_STATUS = 0x0a,
+ BSSGP_PDUT_SUSPEND = 0x0b,
+ BSSGP_PDUT_SUSPEND_ACK = 0x0c,
+ BSSGP_PDUT_SUSPEND_NACK = 0x0d,
+ BSSGP_PDUT_RESUME = 0x0e,
+ BSSGP_PDUT_RESUME_ACK = 0x0f,
+ BSSGP_PDUT_RESUME_NACK = 0x10,
+ /* PDus between NM SAPs */
+ BSSGP_PDUT_BVC_BLOCK = 0x20,
+ BSSGP_PDUT_BVC_BLOCK_ACK = 0x21,
+ BSSGP_PDUT_BVC_RESET = 0x22,
+ BSSGP_PDUT_BVC_RESET_ACK = 0x23,
+ BSSGP_PDUT_BVC_UNBLOCK = 0x24,
+ BSSGP_PDUT_BVC_UNBLOCK_ACK = 0x25,
+ BSSGP_PDUT_FLOW_CONTROL_BVC = 0x26,
+ BSSGP_PDUT_FLOW_CONTROL_BVC_ACK = 0x27,
+ BSSGP_PDUT_FLOW_CONTROL_MS = 0x28,
+ BSSGP_PDUT_FLOW_CONTROL_MS_ACK = 0x29,
+ BSSGP_PDUT_FLUSH_LL = 0x2a,
+ BSSGP_PDUT_FLUSH_LL_ACK = 0x2b,
+ BSSGP_PDUT_LLC_DISCARD = 0x2c,
+ BSSGP_PDUT_SGSN_INVOKE_TRACE = 0x40,
+ BSSGP_PDUT_STATUS = 0x41,
+ /* PDUs between PFM SAP's */
+ BSSGP_PDUT_DOWNLOAD_BSS_PFC = 0x50,
+ BSSGP_PDUT_CREATE_BSS_PFC = 0x51,
+ BSSGP_PDUT_CREATE_BSS_PFC_ACK = 0x52,
+ BSSGP_PDUT_CREATE_BSS_PFC_NACK = 0x53,
+ BSSGP_PDUT_MODIFY_BSS_PFC = 0x54,
+ BSSGP_PDUT_MODIFY_BSS_PFC_ACK = 0x55,
+ BSSGP_PDUT_DELETE_BSS_PFC = 0x56,
+ BSSGP_PDUT_DELETE_BSS_PFC_ACK = 0x57,
+};
+
+/*! \brief BSSGP User-Data header (Section 10.2.1 and 10.2.2) */
+struct bssgp_ud_hdr {
+ uint8_t pdu_type; /*!< BSSGP PDU type */
+ uint32_t tlli; /*!< Temporary Link-Local Identifier */
+ uint8_t qos_profile[3]; /*!< QoS profile */
+ uint8_t data[0]; /* optional/conditional IEs as TLVs */
+} __attribute__((packed));
+
+/*! \brief BSSGP normal header */
+struct bssgp_normal_hdr {
+ uint8_t pdu_type; /*!< BSSGP PDU type */
+ uint8_t data[0]; /*!< optional/conditional IEs as TLVs */
+};
+
+/*! \brief BSSGP Information Element Identifiers */
+enum bssgp_iei_type {
+ BSSGP_IE_ALIGNMENT = 0x00,
+ BSSGP_IE_BMAX_DEFAULT_MS = 0x01,
+ BSSGP_IE_BSS_AREA_ID = 0x02,
+ BSSGP_IE_BUCKET_LEAK_RATE = 0x03,
+ BSSGP_IE_BVCI = 0x04,
+ BSSGP_IE_BVC_BUCKET_SIZE = 0x05,
+ BSSGP_IE_BVC_MEASUREMENT = 0x06,
+ BSSGP_IE_CAUSE = 0x07,
+ BSSGP_IE_CELL_ID = 0x08,
+ BSSGP_IE_CHAN_NEEDED = 0x09,
+ BSSGP_IE_DRX_PARAMS = 0x0a,
+ BSSGP_IE_EMLPP_PRIO = 0x0b,
+ BSSGP_IE_FLUSH_ACTION = 0x0c,
+ BSSGP_IE_IMSI = 0x0d,
+ BSSGP_IE_LLC_PDU = 0x0e,
+ BSSGP_IE_LLC_FRAMES_DISCARDED = 0x0f,
+ BSSGP_IE_LOCATION_AREA = 0x10,
+ BSSGP_IE_MOBILE_ID = 0x11,
+ BSSGP_IE_MS_BUCKET_SIZE = 0x12,
+ BSSGP_IE_MS_RADIO_ACCESS_CAP = 0x13,
+ BSSGP_IE_OMC_ID = 0x14,
+ BSSGP_IE_PDU_IN_ERROR = 0x15,
+ BSSGP_IE_PDU_LIFETIME = 0x16,
+ BSSGP_IE_PRIORITY = 0x17,
+ BSSGP_IE_QOS_PROFILE = 0x18,
+ BSSGP_IE_RADIO_CAUSE = 0x19,
+ BSSGP_IE_RA_CAP_UPD_CAUSE = 0x1a,
+ BSSGP_IE_ROUTEING_AREA = 0x1b,
+ BSSGP_IE_R_DEFAULT_MS = 0x1c,
+ BSSGP_IE_SUSPEND_REF_NR = 0x1d,
+ BSSGP_IE_TAG = 0x1e,
+ BSSGP_IE_TLLI = 0x1f,
+ BSSGP_IE_TMSI = 0x20,
+ BSSGP_IE_TRACE_REFERENC = 0x21,
+ BSSGP_IE_TRACE_TYPE = 0x22,
+ BSSGP_IE_TRANSACTION_ID = 0x23,
+ BSSGP_IE_TRIGGER_ID = 0x24,
+ BSSGP_IE_NUM_OCT_AFF = 0x25,
+ BSSGP_IE_LSA_ID_LIST = 0x26,
+ BSSGP_IE_LSA_INFORMATION = 0x27,
+ BSSGP_IE_PACKET_FLOW_ID = 0x28,
+ BSSGP_IE_PACKET_FLOW_TIMER = 0x29,
+ BSSGP_IE_AGG_BSS_QOS_PROFILE = 0x3a,
+ BSSGP_IE_FEATURE_BITMAP = 0x3b,
+ BSSGP_IE_BUCKET_FULL_RATIO = 0x3c,
+ BSSGP_IE_SERVICE_UTRAN_CCO = 0x3d,
+};
+
+/*! \brief Cause coding (Section 11.3.8 / Table 11.10) */
+enum gprs_bssgp_cause {
+ BSSGP_CAUSE_PROC_OVERLOAD = 0x00,
+ BSSGP_CAUSE_EQUIP_FAIL = 0x01,
+ BSSGP_CAUSE_TRASIT_NET_FAIL = 0x02,
+ BSSGP_CAUSE_CAPA_GREATER_0KPBS = 0x03,
+ BSSGP_CAUSE_UNKNOWN_MS = 0x04,
+ BSSGP_CAUSE_UNKNOWN_BVCI = 0x05,
+ BSSGP_CAUSE_CELL_TRAF_CONG = 0x06,
+ BSSGP_CAUSE_SGSN_CONG = 0x07,
+ BSSGP_CAUSE_OML_INTERV = 0x08,
+ BSSGP_CAUSE_BVCI_BLOCKED = 0x09,
+ BSSGP_CAUSE_PFC_CREATE_FAIL = 0x0a,
+ BSSGP_CAUSE_SEM_INCORR_PDU = 0x20,
+ BSSGP_CAUSE_INV_MAND_INF = 0x21,
+ BSSGP_CAUSE_MISSING_MAND_IE = 0x22,
+ BSSGP_CAUSE_MISSING_COND_IE = 0x23,
+ BSSGP_CAUSE_UNEXP_COND_IE = 0x24,
+ BSSGP_CAUSE_COND_IE_ERR = 0x25,
+ BSSGP_CAUSE_PDU_INCOMP_STATE = 0x26,
+ BSSGP_CAUSE_PROTO_ERR_UNSPEC = 0x27,
+ BSSGP_CAUSE_PDU_INCOMP_FEAT = 0x28,
+};
+
+#endif
diff --git a/openbsc/src/libgb/Makefile.am b/openbsc/src/libgb/Makefile.am
new file mode 100644
index 00000000..eafbc343
--- /dev/null
+++ b/openbsc/src/libgb/Makefile.am
@@ -0,0 +1,9 @@
+INCLUDES = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir)
+AM_CFLAGS=-Wall -fno-strict-aliasing $(LIBOSMOCORE_CFLAGS) \
+ $(LIBOSMOVTY_CFLAGS) $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS)
+
+noinst_LIBRARIES = libgb.a
+
+libgb_a_SOURCES = gprs_ns.c gprs_ns_frgre.c gprs_ns_vty.c \
+ gprs_bssgp.c gprs_bssgp_util.c gprs_bssgp_vty.c \
+ gprs_bssgp_bss.c common_vty.c
diff --git a/openbsc/src/libgb/common_vty.c b/openbsc/src/libgb/common_vty.c
new file mode 100644
index 00000000..0bd0b6c3
--- /dev/null
+++ b/openbsc/src/libgb/common_vty.c
@@ -0,0 +1,90 @@
+/* OpenBSC VTY common helpers */
+/* (C) 2009-2012 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2009-2010 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/logging.h>
+
+#include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/command.h>
+#include <osmocom/vty/buffer.h>
+#include <osmocom/vty/vty.h>
+
+#include <osmocom/gprs/gprs_msgb.h>
+
+#include "common_vty.h"
+
+/* Down vty node level. */
+gDEFUN(libgb_exit,
+ libgb_exit_cmd, "exit", "Exit current mode and down to previous mode\n")
+{
+ switch (vty->node) {
+ case L_NS_NODE:
+ case L_BSSGP_NODE:
+ vty->node = CONFIG_NODE;
+ vty->index = NULL;
+ break;
+ default:
+ break;
+ }
+ return CMD_SUCCESS;
+}
+
+/* End of configuration. */
+gDEFUN(libgb_end,
+ libgb_end_cmd, "end", "End current mode and change to enable mode.")
+{
+ switch (vty->node) {
+ case L_NS_NODE:
+ case L_BSSGP_NODE:
+ vty_config_unlock(vty);
+ vty->node = ENABLE_NODE;
+ vty->index = NULL;
+ vty->index_sub = NULL;
+ break;
+ default:
+ break;
+ }
+ return CMD_SUCCESS;
+}
+
+int gprs_log_filter_fn(const struct log_context *ctx,
+ struct log_target *tar)
+{
+ const struct gprs_nsvc *nsvc = ctx->ctx[GPRS_CTX_NSVC];
+ const struct gprs_bvc *bvc = ctx->ctx[GPRS_CTX_BVC];
+
+ /* Filter on the NS Virtual Connection */
+ if ((tar->filter_map & (1 << FLT_NSVC)) != 0
+ && nsvc && (nsvc == tar->filter_data[FLT_NSVC]))
+ return 1;
+
+ /* Filter on the NS Virtual Connection */
+ if ((tar->filter_map & (1 << FLT_BVC)) != 0
+ && bvc && (bvc == tar->filter_data[FLT_BVC]))
+ return 1;
+
+ return 0;
+}
+
+
+int DNS, DBSSGP;
diff --git a/openbsc/src/libgb/common_vty.h b/openbsc/src/libgb/common_vty.h
new file mode 100644
index 00000000..d8d00407
--- /dev/null
+++ b/openbsc/src/libgb/common_vty.h
@@ -0,0 +1,14 @@
+#include <osmocom/vty/command.h>
+#include <osmocom/core/logging.h>
+
+extern int DNS, DBSSGP;
+
+enum log_filter {
+ _FLT_ALL = LOG_FILTER_ALL, /* libosmocore */
+ FLT_NSVC = 1,
+ FLT_BVC = 2,
+};
+
+extern struct cmd_element libgb_exit_cmd;
+extern struct cmd_element libgb_end_cmd;
+
diff --git a/openbsc/src/libgb/gprs_bssgp.c b/openbsc/src/libgb/gprs_bssgp.c
new file mode 100644
index 00000000..4b8c7302
--- /dev/null
+++ b/openbsc/src/libgb/gprs_bssgp.c
@@ -0,0 +1,919 @@
+/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */
+
+/* (C) 2009-2012 by Harald Welte <laforge@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * TODO:
+ * o properly count incoming BVC-RESET packets in counter group
+ * o set log context as early as possible for outgoing packets
+ */
+
+#include <errno.h>
+#include <stdint.h>
+
+#include <netinet/in.h>
+
+#include <osmocom/core/msgb.h>
+#include <osmocom/gsm/tlv.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/rate_ctr.h>
+
+#include <osmocom/gprs/gprs_bssgp.h>
+#include <osmocom/gprs/gprs_ns.h>
+
+#include "common_vty.h"
+
+void *bssgp_tall_ctx = NULL;
+
+static const struct rate_ctr_desc bssgp_ctr_description[] = {
+ { "packets.in", "Packets at BSSGP Level ( In)" },
+ { "packets.out","Packets at BSSGP Level (Out)" },
+ { "bytes.in", "Bytes at BSSGP Level ( In)" },
+ { "bytes.out", "Bytes at BSSGP Level (Out)" },
+ { "blocked", "BVC Blocking count" },
+ { "discarded", "BVC LLC Discarded count" },
+};
+
+static const struct rate_ctr_group_desc bssgp_ctrg_desc = {
+ .group_name_prefix = "bssgp.bss_ctx",
+ .group_description = "BSSGP Peer Statistics",
+ .num_ctr = ARRAY_SIZE(bssgp_ctr_description),
+ .ctr_desc = bssgp_ctr_description,
+};
+
+LLIST_HEAD(bssgp_bvc_ctxts);
+
+/* Find a BTS Context based on parsed RA ID and Cell ID */
+struct bssgp_bvc_ctx *btsctx_by_raid_cid(const struct gprs_ra_id *raid, uint16_t cid)
+{
+ struct bssgp_bvc_ctx *bctx;
+
+ llist_for_each_entry(bctx, &bssgp_bvc_ctxts, list) {
+ if (!memcmp(&bctx->ra_id, raid, sizeof(bctx->ra_id)) &&
+ bctx->cell_id == cid)
+ return bctx;
+ }
+ return NULL;
+}
+
+/* Find a BTS context based on BVCI+NSEI tuple */
+struct bssgp_bvc_ctx *btsctx_by_bvci_nsei(uint16_t bvci, uint16_t nsei)
+{
+ struct bssgp_bvc_ctx *bctx;
+
+ llist_for_each_entry(bctx, &bssgp_bvc_ctxts, list) {
+ if (bctx->nsei == nsei && bctx->bvci == bvci)
+ return bctx;
+ }
+ return NULL;
+}
+
+struct bssgp_bvc_ctx *btsctx_alloc(uint16_t bvci, uint16_t nsei)
+{
+ struct bssgp_bvc_ctx *ctx;
+
+ ctx = talloc_zero(bssgp_tall_ctx, struct bssgp_bvc_ctx);
+ if (!ctx)
+ return NULL;
+ ctx->bvci = bvci;
+ ctx->nsei = nsei;
+ /* FIXME: BVCI is not unique, only BVCI+NSEI ?!? */
+ ctx->ctrg = rate_ctr_group_alloc(ctx, &bssgp_ctrg_desc, bvci);
+
+ llist_add(&ctx->list, &bssgp_bvc_ctxts);
+
+ return ctx;
+}
+
+/* Chapter 10.4.5: Flow Control BVC ACK */
+static int bssgp_tx_fc_bvc_ack(uint16_t nsei, uint8_t tag, uint16_t ns_bvci)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ struct bssgp_normal_hdr *bgph =
+ (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+
+ msgb_nsei(msg) = nsei;
+ msgb_bvci(msg) = ns_bvci;
+
+ bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK;
+ msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag);
+
+ return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+/* 10.3.7 SUSPEND-ACK PDU */
+int bssgp_tx_suspend_ack(uint16_t nsei, uint32_t tlli,
+ const struct gprs_ra_id *ra_id, uint8_t suspend_ref)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ struct bssgp_normal_hdr *bgph =
+ (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+ uint32_t _tlli;
+ uint8_t ra[6];
+
+ msgb_nsei(msg) = nsei;
+ msgb_bvci(msg) = 0; /* Signalling */
+ bgph->pdu_type = BSSGP_PDUT_SUSPEND_ACK;
+
+ _tlli = htonl(tlli);
+ msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli);
+ gsm48_construct_ra(ra, ra_id);
+ msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra);
+ msgb_tvlv_put(msg, BSSGP_IE_SUSPEND_REF_NR, 1, &suspend_ref);
+
+ return gprs_ns_sendmsg(bssgp_nsi, msg);
+}
+
+/* 10.3.8 SUSPEND-NACK PDU */
+int bssgp_tx_suspend_nack(uint16_t nsei, uint32_t tlli,
+ const struct gprs_ra_id *ra_id,
+ uint8_t *cause)
+{
+ struct msgb *msg = bssgp_msgb_alloc();
+ struct bssgp_normal_hdr *bgph =
+ (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
+ uint32_t _tlli;
+ uint8_t ra[6];
+
+ msgb_nsei(msg) = nsei;
+ msgb_bvci(msg) = 0; /* Signalling */
+ bgph->pdu_type = BSSGP_PDUT_SUSPEND_NACK;
+
+ _tlli = htonl(tlli);
+ msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &