Create new 'gprs-sgsn' branch on top of 'gprs-conf'

This branch contains the partial SGSN/GGSN implementation that
was originally developed as part of the gprs branch.
diff --git a/openbsc/include/openbsc/crc24.h b/openbsc/include/openbsc/crc24.h
new file mode 100644
index 0000000..358fcb5
--- /dev/null
+++ b/openbsc/include/openbsc/crc24.h
@@ -0,0 +1,8 @@
+#ifndef _CRC24_H
+#define _CRC24_H
+
+#define INIT_CRC24	0xffffff
+
+u_int32_t crc24_calc(u_int32_t fcs, u_int8_t *cp, unsigned int len);
+
+#endif
diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h
index f1c5a69..49b417e 100644
--- a/openbsc/include/openbsc/debug.h
+++ b/openbsc/include/openbsc/debug.h
@@ -29,6 +29,7 @@
 	DHO,
 	DDB,
 	DREF,
+	DGPRS,
 	Debug_LastEntry,
 };
 
diff --git a/openbsc/include/openbsc/gprs_bssgp.h b/openbsc/include/openbsc/gprs_bssgp.h
new file mode 100644
index 0000000..f85ac48
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_bssgp.h
@@ -0,0 +1,138 @@
+#ifndef _GPRS_BSSGP_H
+#define _GPRS_BSSGP_H
+
+/* 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,
+};
+
+/* Section 10.2.1 and 10.2.2 */
+struct bssgp_ud_hdr {
+	u_int8_t pdu_type;
+	u_int32_t tlli;
+	u_int8_t qos_profile[3];
+	u_int8_t data[0];	/* TLV's */
+} __attribute__((packed));
+
+struct bssgp_normal_hdr {
+	u_int8_t pdu_type;
+	u_int8_t data[0];	/* TLV's */
+};
+
+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,
+};
+
+/* Section 11.3.8 / Table 11.10: Cause coding */
+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,
+};
+
+extern int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t bvci);
+
+#endif /* _GPRS_BSSGP_H */
diff --git a/openbsc/include/openbsc/gprs_llc.h b/openbsc/include/openbsc/gprs_llc.h
new file mode 100644
index 0000000..cd4e215
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_llc.h
@@ -0,0 +1,20 @@
+#ifndef _GPRS_LLC_H
+#define _GPRS_LLC_H
+
+/* 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,
+};
+
+
+int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv);
+int gprs_llc_tx_ui(struct msgb *msg, u_int8_t sapi, int command);
+
+#endif
diff --git a/openbsc/include/openbsc/gprs_ns.h b/openbsc/include/openbsc/gprs_ns.h
new file mode 100644
index 0000000..90f1adf
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_ns.h
@@ -0,0 +1,61 @@
+#ifndef _GPRS_NS_H
+#define _GPRS_NS_H
+
+struct gprs_ns_hdr {
+	u_int8_t pdu_type;
+	u_int8_t data[0];
+} __attribute__((packed));
+
+/* 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 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 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,
+};
+
+/* a layer 1 entity transporting NS frames */
+struct gprs_ns_link {
+	union {
+		struct {
+			int fd;
+		} ip;
+	};
+};
+
+
+int gprs_ns_rcvmsg(struct msgb *msg);
+
+int gprs_ns_sendmsg(struct gprs_ns_link *link, u_int16_t bvci,
+		    struct msgb *msg);
+#endif
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h
new file mode 100644
index 0000000..87c7fa8
--- /dev/null
+++ b/openbsc/include/openbsc/gprs_sgsn.h
@@ -0,0 +1,107 @@
+#ifndef _GPRS_SGSN_H
+#define _GPRS_SGSN_H
+
+/* TS 04.08 4.1.3.3 GMM mobility management states on the network side */
+enum gprs_mm_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 */
+};
+
+enum gprs_ciph_algo {
+	GPRS_ALGO_GEA0,
+	GPRS_ALGO_GEA1,
+	GPRS_ALGO_GEA2,
+};
+
+#define MS_RADIO_ACCESS_CAPA
+
+/* According to TS 03.60, Table 5: SGSN MM and PDP Contexts */
+struct sgsn_mm_ctx {
+	struct llist_head	list;
+
+	char 			imsi[GSM_IMSI_LENGTH];
+	enum gprs_mm_state	mm_state;
+	u_int32_t 		p_tmsi;
+	u_int32_t 		p_tmsi_sig;
+	char 			imei[GSM_IMEI_LENGTH];
+	char 			msisdn[GSM_EXTENSION_LENGTH];
+	struct gprs_ra_id	ra;
+	u_int16_t		cell_id;
+	u_int32_t		cell_id_age;
+	/* VLR number */
+	u_int32_t		new_sgsn_addr;
+	/* Authentication Triplets */
+	/* Kc */
+	/* CKSN */
+	enum gprs_ciph_algo	ciph_algo;
+	struct {
+		u_int8_t	buf[14];	/* 10.5.5.12a */
+		u_int8_t	len;
+	} ms_radio_access_capa;
+	struct {
+		u_int8_t	buf[4];		/* 10.5.5.12 */
+		u_int8_t	len;
+	} ms_network_capa;
+	u_int16_t		drx_parms;
+	int			mnrg;	/* MS reported to HLR? */
+	int			ngaf;	/* MS reported to MSC/VLR? */
+	int			ppf;	/* paging for GPRS + non-GPRS? */
+	/* SMS Parameters */
+	int			recovery;
+	u_int8_t		radio_prio_sms;
+
+	struct llist_head	pdp_list;
+
+	/* Additional bits not present in the GSM TS */
+	u_int32_t		tlli;
+	struct timer_list	timer;
+	unsigned int		T;
+};
+
+enum pdp_ctx_state {
+	PDP_STAE_NONE,
+};
+
+enum pdp_type {
+	PDP_TYPE_NONE,
+};
+
+struct sgsn_pdp_ctx {
+	struct llist_head	list;
+
+	unsigned int		id;
+	enum pdp_ctx_state	state;
+	enum pdp_type		type;
+	u_int32_t		addresss;
+	char 			*apn_subscribed;
+	char 			*apn_used;
+	u_int16_t		nsapi;
+	u_int8_t		ti;	/* transaction identifier */
+	u_int32_t		ggsn_in_use;
+	int			vplmn_allowed;
+	u_int32_t		qos_profile_subscr;
+	u_int32_t		qos_profile_req;
+	u_int32_t		qos_profile_neg;
+	u_int8_t		radio_prio;
+	u_int32_t		tx_npdu_nr;
+	u_int32_t		rx_npdu_nr;
+	u_int32_t		tx_gtp_snd;
+	u_int32_t		rx_gtp_snu;
+	u_int32_t		charging_id;
+	int			reordering_reqd;
+};
+
+/* look-up a SGSN MM context based on TLLI + RAI */
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(u_int32_t tlli,
+					const struct gprs_ra_id *raid);
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_ptmsi(u_int32_t tmsi);
+struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi);
+
+/* Allocate a new SGSN MM context */
+struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(u_int32_t tlli,
+					const struct gprs_ra_id *raid);
+
+#endif /* _GPRS_SGSN_H */
diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h
new file mode 100644
index 0000000..20ab044
--- /dev/null
+++ b/openbsc/include/openbsc/gsm_04_08_gprs.h
@@ -0,0 +1,203 @@
+#ifndef _GSM48_GPRS_H
+#define _GSM48_GPRS_H
+
+/* Table 10.4 / 10.4a, GPRS Mobility Management (GMM) */
+#define GSM48_MT_GMM_ATTACH_REQ		0x01
+#define GSM48_MT_GMM_ATTACH_ACK		0x02
+#define GSM48_MT_GMM_ATTACH_COMPL	0x03
+#define GSM48_MT_GMM_ATTACH_REJ		0x04
+#define GSM48_MT_GMM_DETACH_REQ		0x05
+#define GSM48_MT_GMM_DETACH_ACK		0x06
+
+#define GSM48_MT_GMM_RA_UPD_REQ		0x08
+#define GSM48_MT_GMM_RA_UPD_ACK		0x09
+#define GSM48_MT_GMM_RA_UPD_COMPL	0x0a
+#define GSM48_MT_GMM_RA_UPD_REJ		0x0b
+
+#define GSM48_MT_GMM_PTMSI_REALL_CMD	0x10
+#define GSM48_MT_GMM_PTMSI_REALL_COMPL	0x11
+#define GSM48_MT_GMM_AUTH_CIPH_REQ	0x12
+#define GSM48_MT_GMM_AUTH_CIPH_RESP	0x13
+#define GSM48_MT_GMM_AUTH_CIPH_REJ	0x14
+#define GSM48_MT_GMM_ID_REQ		0x15
+#define GSM48_MT_GMM_ID_RESP		0x16
+#define GSM48_MT_GMM_STATUS		0x20
+#define GSM48_MT_GMM_INFO		0x21
+
+/* Table 10.4a, GPRS Session Management (GSM) */
+#define GSM48_MT_GSM_ACT_PDP_REQ	0x41
+#define GSM48_MT_GSM_ACT_PDP_ACK	0x42
+#define GSM48_MT_GSM_ACT_PDP_REJ	0x43
+#define GSM48_MT_GSM_REQ_PDP_ACT	0x44
+#define GSM48_MT_GSM_REQ_PDP_ACT_REJ	0x45
+#define GSM48_MT_GSM_DEACT_PDP_REQ	0x46
+#define GSM48_MT_GSM_DEACT_PDP_ACK	0x47
+#define GSM48_MT_GSM_ACT_AA_PDP_REQ	0x50
+#define GSM48_MT_GSM_ACT_AA_PDP_ACK	0x51
+#define GSM48_MT_GSM_ACT_AA_PDP_REJ	0x52
+#define GSM48_MT_GSM_DEACT_AA_PDP_REQ	0x53
+#define GSM48_MT_GSM_DEACT_AA_PDP_ACK	0x54
+#define GSM48_MT_GSM_STATUS		0x55
+
+/* Chapter 10.5.5.2 / Table 10.5.135 */
+#define GPRS_ATT_T_ATTACH		1
+#define GPRS_ATT_T_ATT_WHILE_IMSI	2
+#define GPRS_ATT_T_COMBINED		3
+
+/* Chapter 10.5.5.18 / Table 105.150 */
+#define GPRS_UPD_T_RA			0
+#define GPRS_UPD_T_RA_LA		1
+#define GPRS_UPD_T_RA_LA_IMSI_ATT	2
+#define GPRS_UPD_T_PERIODIC		3
+
+enum gsm48_gprs_ie_mm {
+	GSM48_IE_GMM_TIMER_READY	= 0x17, /* 10.5.7.3 */
+	GSM48_IE_GMM_PTMSI_SIG		= 0x19,	/* 10.5.5.8 */
+	GSM48_IE_GMM_AUTH_RAND		= 0x21, /* 10.5.3.1 */
+	GSM48_IE_GMM_AUTH_SRES		= 0x22, /* 10.5.3.2 */
+	GSM48_IE_GMM_IMEISV		= 0x23, /* 10.5.1.4 */
+	GSM48_IE_GMM_DRX_PARAM		= 0x27,	/* 10.5.5.6 */
+	GSM48_IE_GMM_MS_NET_CAPA	= 0x31,	/* 10.5.5.12 */
+};
+
+enum gsm48_gprs_ie_sm {
+	GSM48_IE_GSM_APN		= 0x28,	/* 10.5.6.1 */
+	GSM48_IE_GSM_PROTO_CONF_OPT	= 0x27,	/* 10.5.6.3 */
+	GSM48_IE_GSM_PDP_ADDR		= 0x2b, /* 10.5.6.4 */
+	GSM48_IE_GSM_AA_TMR		= 0x29,	/* 10.5.7.3 */
+	GSM48_IE_GSM_NAME_FULL		= 0x43, /* 10.5.3.5a */
+	GSM48_IE_GSM_NAME_SHORT		= 0x45, /* 10.5.3.5a */
+	GSM48_IE_GSM_TIMEZONE		= 0x46, /* 10.5.3.8 */
+	GSM48_IE_GSM_UTC_AND_TZ		= 0x47, /* 10.5.3.9 */
+	GSM48_IE_GSM_LSA_ID		= 0x48, /* 10.5.3.11 */
+};
+
+/* Chapter 10.4.4.15 */
+struct gsm48_ra_id {
+	u_int8_t digits[3];	/* MCC + MNC BCD digits */
+	u_int16_t lac;		/* Location Area Code */
+	u_int8_t rac;		/* Routing Area Code */
+} __attribute__ ((packed));
+
+/* Chapter 9.4.15 / Table 9.4.15 */
+struct gsm48_ra_upd_ack {
+	u_int8_t force_stby:4,	/* 10.5.5.7 */
+		 upd_result:4;	/* 10.5.5.17 */
+	u_int8_t ra_upd_timer;	/* 10.5.7.3 */
+	struct gsm48_ra_id ra_id; /* 10.5.5.15 */
+	u_int8_t data[0];
+} __attribute__((packed));
+
+/* Chapter 10.5.7.3 */
+enum gsm48_gprs_tmr_unit {
+	GPRS_TMR_2SECONDS	= 0 << 5,
+	GPRS_TMR_MINUTE		= 1 << 5,
+	GPRS_TMR_6MINUTE	= 2 << 5,
+	GPRS_TMR_DEACTIVATED	= 3 << 5,
+};
+
+/* Chapter 9.4.2 / Table 9.4.2 */
+struct gsm48_attach_ack {
+	u_int8_t att_result:4,	/* 10.5.5.7 */
+		 force_stby:4;	/* 10.5.5.1 */
+	u_int8_t ra_upd_timer;	/* 10.5.7.3 */
+	u_int8_t radio_prio;	/* 10.5.7.2 */
+	struct gsm48_ra_id ra_id; /* 10.5.5.15 */
+	u_int8_t data[0];
+} __attribute__((packed));
+
+/* Chapter 9.5.1 / Table 9.5.1 */
+struct gsm48_act_pdp_ctx_req {
+	u_int8_t req_nsapi;
+	u_int8_t req_llc_sapi;
+	u_int8_t req_qos_lv[4];
+	u_int8_t data[0];
+} __attribute__((packed));
+
+/* Chapter 9.5.2 / Table 9.5.2 */
+struct gsm48_act_pdp_ctx_ack {
+	u_int8_t llc_sapi;
+	u_int8_t qos_lv[4];
+	u_int8_t radio_prio:4,
+		 spare:4;
+	u_int8_t data[0];
+} __attribute__((packed));
+
+/* Chapter 10.5.5.14 / Table 10.5.147 */
+enum gsm48_gmm_cause {
+	GMM_CAUSE_IMSI_UNKNOWN		= 0x02,
+	GMM_CAUSE_ILLEGAL_MS		= 0x03,
+	GMM_CAUSE_ILLEGAL_ME		= 0x06,
+	GMM_CAUSE_GPRS_NOTALLOWED	= 0x07,
+	GMM_CAUSE_GPRS_OTHER_NOTALLOWED	= 0x08,
+	GMM_CAUSE_MS_ID_NOT_DERIVED	= 0x09,
+	GMM_CAUSE_IMPL_DETACHED		= 0x0a,
+	GMM_CAUSE_PLMN_NOTALLOWED	= 0x0b,
+	GMM_CAUSE_LA_NOTALLOWED		= 0x0c,
+	GMM_CAUSE_ROAMING_NOTALLOWED	= 0x0d,
+	GMM_CAUSE_NO_GPRS_PLMN		= 0x0e,
+	GMM_CAUSE_MSC_TEMP_NOTREACH	= 0x10,
+	GMM_CAUSE_NET_FAIL		= 0x11,
+	GMM_CAUSE_CONGESTION		= 0x16,
+	GMM_CAUSE_SEM_INCORR_MSG	= 0x5f,
+	GMM_CAUSE_INV_MAND_INFO		= 0x60,
+	GMM_CAUSE_MSGT_NOTEXIST_NOTIMPL	= 0x61,
+	GMM_CAUSE_MSGT_INCOMP_P_STATE	= 0x62,
+	GMM_CAUSE_IE_NOTEXIST_NOTIMPL	= 0x63,
+	GMM_CAUSE_COND_IE_ERR		= 0x64,
+	GMM_CAUSE_MSG_INCOMP_P_STATE	= 0x65,
+	GMM_CAUSE_PROTO_ERR_UNSPEC	= 0x6f,
+};
+
+/* Chapter 10.4.6.6 / Table 10.5.157 */
+enum gsm48_gsm_cause {
+	GSM_CAUSE_INSUFF_RSRC		= 0x1a,
+	GSM_CAUSE_MISSING_APN		= 0x1b,
+	GSM_CAUSE_UNKNOWN_PDP		= 0x1c,
+	GSM_CAUSE_AUTH_FAILED		= 0x1d,
+	GSM_CAUSE_ACT_REJ_GGSN		= 0x1e,
+	GSM_CAUSE_ACT_REJ_UNSPEC	= 0x1f,
+	GSM_CAUSE_SERV_OPT_NOTSUPP	= 0x20,
+	GSM_CAUSE_REQ_SERV_OPT_NOTSUB	= 0x21,
+	GSM_CAUSE_SERV_OPT_TEMP_OOO	= 0x22,
+	GSM_CAUSE_NSAPI_IN_USE		= 0x23,
+	GSM_CAUSE_DEACT_REGULAR		= 0x24,
+	GSM_CAUSE_QOS_NOT_ACCEPTED	= 0x25,
+	GSM_CAUSE_NET_FAIL		= 0x26,
+	GSM_CAUSE_REACT_RQD		= 0x27,
+	GSM_CAUSE_FEATURE_NOTSUPP	= 0x28,
+	GSM_CAUSE_INVALID_TRANS_ID	= 0x51,
+	GSM_CAUSE_SEM_INCORR_MSG	= 0x5f,
+	GSM_CAUSE_INV_MAND_INFO		= 0x60,
+	GSM_CAUSE_MSGT_NOTEXIST_NOTIMPL	= 0x61,
+	GSM_CAUSE_MSGT_INCOMP_P_STATE	= 0x62,
+	GSM_CAUSE_IE_NOTEXIST_NOTIMPL	= 0x63,
+	GSM_CAUSE_COND_IE_ERR		= 0x64,
+	GSM_CAUSE_MSG_INCOMP_P_STATE	= 0x65,
+	GSM_CAUSE_PROTO_ERR_UNSPEC	= 0x6f,
+};
+
+/* GSM TS 03.03 Chapter 2.6 */
+enum gprs_tlli_tyoe {
+	TLLI_LOCAL,
+	TLLI_FOREIGN,
+	TLLI_RANDOM,
+	TLLI_AUXILIARY,
+	TLLI_RESERVED,
+};
+
+/* Section 6.1.2.2: Session management states on the network side */
+enum gsm48_pdp_state {
+	PDP_S_INACTIVE,
+	PDP_S_ACTIVE_PENDING,
+	PDP_S_ACTIVE,
+	PDP_S_INACTIVE_PENDING,
+	PDP_S_MODIFY_PENDING,
+};
+
+int gprs_tlli_type(u_int32_t tlli);
+
+struct gsm_bts *gsm48_bts_by_ra_id(struct gsm_network *net,
+				   const u_int8_t *buf, unsigned int len);
+
+#endif /* _GSM48_GPRS_H */