Create new gprs-conf branch with  the non-SGSN part of the gprs branch

This new gprs-conf branch is intended to contain everything needed
to configure GPRS in the nanoBTS, but without implementing the SGSN/GGSN
functionality.

The SGSN/GGSN development will happen in a branch based on this branch
called "gprs-sgsn"
diff --git a/openbsc/include/openbsc/abis_nm.h b/openbsc/include/openbsc/abis_nm.h
index cff91e0..45307e3 100644
--- a/openbsc/include/openbsc/abis_nm.h
+++ b/openbsc/include/openbsc/abis_nm.h
@@ -154,6 +154,7 @@
 				u_int8_t *attr, u_int8_t attr_len);
 int abis_nm_ipaccess_rsl_connect(struct gsm_bts_trx *trx, 
 				 u_int32_t ip, u_int16_t port, u_int8_t stream);
+void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts);
 int ipac_parse_bcch_info(struct ipac_bcch_info *binf, u_int8_t *buf);
 const char *ipacc_testres_name(u_int8_t res);
 
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index db3eaff..1c18c55 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -374,6 +374,7 @@
 struct gsm_bts_gprs_nsvc {
 	struct gsm_bts *bts;
 	int id;
+	u_int16_t nsvci;
 	struct gsm_nm_state nm_state;
 };
 
@@ -467,8 +468,10 @@
 		} nse;
 		struct {
 			struct gsm_nm_state nm_state;
+			u_int16_t bvci;
 		} cell;
 		struct gsm_bts_gprs_nsvc nsvc[2];
+		u_int8_t rac;
 	} gprs;
 	
 	/* transceivers */
@@ -681,6 +684,16 @@
 
 void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked);
 
+/* A parsed GPRS routing area */
+struct gprs_ra_id {
+	u_int16_t	mnc;
+	u_int16_t	mcc;
+	u_int16_t	lac;
+	u_int8_t	rac;
+};
+
+int gsm48_ra_id_by_bts(u_int8_t *buf, struct gsm_bts *bts);
+void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts);
 struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan);
 
 int gsm_bts_model_register(struct gsm_bts_model *model);
diff --git a/openbsc/src/abis_nm.c b/openbsc/src/abis_nm.c
index 99d8dd6..1e5e1c8 100644
--- a/openbsc/src/abis_nm.c
+++ b/openbsc/src/abis_nm.c
@@ -856,28 +856,20 @@
 	const u_int8_t *sw_config;
 	int sw_config_len;
 	int file_id_len;
-	int nack = 0;
 	int ret;
 
 	debugp_foh(foh);
 
 	DEBUGPC(DNM, "SW Activate Request: ");
 
-	if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
-		DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
-		nack = 1;
-	} else
-		DEBUGPC(DNM, "ACKing and Activating\n");
+	DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
 
 	ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
 				      foh->obj_inst.bts_nr,
 				      foh->obj_inst.trx_nr,
-				      foh->obj_inst.ts_nr, nack,
+				      foh->obj_inst.ts_nr, 0,
 				      foh->data, oh->length-sizeof(*foh));
 
-	if (nack)
-		return ret;
-
 	abis_nm_tlv_parse(&tp, mb->trx->bts, foh->data, oh->length-sizeof(*foh));
 	sw_config = TLVP_VAL(&tp, NM_ATT_SW_CONFIG);
 	sw_config_len = TLVP_LEN(&tp, NM_ATT_SW_CONFIG);
@@ -2881,6 +2873,14 @@
 				     attr, attr_len);
 }
 
+void abis_nm_ipaccess_cgi(u_int8_t *buf, struct gsm_bts *bts)
+{
+	/* we simply reuse the GSM48 function and overwrite the RAC
+	 * with the Cell ID */
+	gsm48_ra_id_by_bts(buf, bts);
+	*((u_int16_t *)(buf + 5)) = htons(bts->cell_identity);
+}
+
 void gsm_trx_lock_rf(struct gsm_bts_trx *trx, int locked)
 {
 	int new_state = locked ? NM_STATE_LOCKED : NM_STATE_UNLOCKED;
@@ -3000,5 +3000,3 @@
 
 	return 0;
 }
-
-
diff --git a/openbsc/src/bsc_init.c b/openbsc/src/bsc_init.c
index 57fc4b3..3fc8184 100644
--- a/openbsc/src/bsc_init.c
+++ b/openbsc/src/bsc_init.c
@@ -20,6 +20,8 @@
  *
  */
 
+#define GPRS
+
 #include <openbsc/gsm_data.h>
 #include <osmocore/gsm_utils.h>
 #include <openbsc/gsm_04_08.h>
@@ -330,6 +332,8 @@
 	NM_ATT_NY1, 10, /* 10 retransmissions of physical config */
 	NM_ATT_BCCH_ARFCN, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
 	NM_ATT_BSIC, HARDCODED_BSIC,
+	/* FIXME: do not hardcode the CGI */
+	NM_ATT_IPACC_CGI, 0, 7,  0x00, 0xf1, 0x10, 0x00, 0x01, 0x00, 0x00,
 };
 
 static unsigned char nanobts_attr_radio[] = {
@@ -337,6 +341,66 @@
 	NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
 };
 
+static unsigned char nanobts_attr_nse[] = {
+	NM_ATT_IPACC_NSEI, 0, 2,  0x03, 0x9d, /* NSEI 925 */
+	NM_ATT_IPACC_NS_CFG, 0, 7,  3,  /* (un)blocking timer (Tns-block) */
+				    3,  /* (un)blocking retries */
+				    3,  /* reset timer (Tns-reset) */
+				    3,  /* reset retries */
+				    30,  /* test timer (Tns-test) */
+				    3,  /* alive timer (Tns-alive) */
+				    10, /* alive retrires */
+	NM_ATT_IPACC_BSSGP_CFG, 0, 11,
+				    3,  /* blockimg timer (T1) */
+				    3,  /* blocking retries */
+				    3,  /* unblocking retries */
+				    3,  /* reset timer */
+				    3,  /* reset retries */
+				    10, /* suspend timer (T3) in 100ms */
+				    3,  /* suspend retries */
+				    10, /* resume timer (T4) in 100ms */
+				    3,  /* resume retries */
+				    10, /* capability update timer (T5) */
+				    3,  /* capability update retries */
+};
+
+static unsigned char nanobts_attr_cell[] = {
+	NM_ATT_IPACC_RAC, 0, 1,  1, /* routing area code */
+	NM_ATT_IPACC_GPRS_PAGING_CFG, 0, 2,
+		5,	/* repeat time (50ms) */
+		3,	/* repeat count */
+	NM_ATT_IPACC_BVCI, 0, 2,  0x03, 0x9d, /* BVCI 925 */
+	NM_ATT_IPACC_RLC_CFG, 0, 9,
+		20, 	/* T3142 */
+		5, 	/* T3169 */
+		5,	/* T3191 */
+		200,	/* T3193 */
+		5,	/* T3195 */
+		10,	/* N3101 */
+		4,	/* N3103 */
+		8,	/* N3105 */
+		15,	/* RLC CV countdown */
+	NM_ATT_IPACC_CODING_SCHEMES, 0, 2,  0x0f, 0x00,
+	NM_ATT_IPACC_RLC_CFG_2, 0, 5,
+		0x00, 250,
+		0x00, 250,
+		2,	/* MCS2 */
+#if 0
+	/* EDGE model only, breaks older models.
+	 * Should inquire the BTS capabilities */
+	NM_ATT_IPACC_RLC_CFG_3, 0, 1,
+		2,	/* MCS2 */
+#endif
+};
+
+static unsigned char nanobts_attr_nsvc0[] = {
+	NM_ATT_IPACC_NSVCI, 0, 2,  0x03, 0x9d, /* 925 */
+	NM_ATT_IPACC_NS_LINK_CFG, 0, 8,
+		0x59, 0xd8, /* remote udp port (23000) */
+		192, 168, 100, 11, /* remote ip address */
+		0x59, 0xd8, /* local udp port (23000) */
+};
+
 /* Callback function to be called whenever we get a GSM 12.21 state change event */
 int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
 		   struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
@@ -344,6 +408,7 @@
 	struct gsm_bts *bts;
 	struct gsm_bts_trx *trx;
 	struct gsm_bts_trx_ts *ts;
+	struct gsm_bts_gprs_nsvc *nsvc;
 
 	/* This event-driven BTS setup is currently only required on nanoBTS */
 
@@ -397,6 +462,49 @@
 			abis_nm_opstart(trx->bts, obj_class, trx->bts->bts_nr,
 					trx->nr, 0xff);
 		break;
+#ifdef GPRS
+	case NM_OC_GPRS_NSE:
+		bts = container_of(obj, struct gsm_bts, gprs.nse);
+		if (new_state->availability == 5) {
+			abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
+						  0xff, 0xff, nanobts_attr_nse,
+						  sizeof(nanobts_attr_nse));
+			abis_nm_opstart(bts, obj_class, bts->bts_nr,
+					0xff, 0xff);
+			abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
+					      0xff, 0xff, NM_STATE_UNLOCKED);
+		}
+		break;
+	case NM_OC_GPRS_CELL:
+		bts = container_of(obj, struct gsm_bts, gprs.cell);
+		if (new_state->availability == 5) {
+			abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
+						  0, 0xff, nanobts_attr_cell,
+						  sizeof(nanobts_attr_cell));
+			abis_nm_opstart(bts, obj_class, bts->bts_nr,
+					0, 0xff);
+			abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
+					      0, 0xff, NM_STATE_UNLOCKED);
+		}
+		break;
+	case NM_OC_GPRS_NSVC:
+		nsvc = obj;
+		bts = nsvc->bts;
+	        /* We skip NSVC1 since we only use NSVC0 */
+		if (nsvc->id == 1)
+			break;
+		if (new_state->availability == NM_AVSTATE_OFF_LINE) {
+			abis_nm_ipaccess_set_attr(bts, obj_class, bts->bts_nr,
+						  nsvc->id, 0xff,
+						  nanobts_attr_nsvc0,
+						  sizeof(nanobts_attr_nsvc0));
+			abis_nm_opstart(bts, obj_class, bts->bts_nr,
+					nsvc->id, 0xff);
+			abis_nm_chg_adm_state(bts, obj_class, bts->bts_nr,
+					      nsvc->id, 0xff,
+					      NM_STATE_UNLOCKED);
+		}
+#endif
 	default:
 		break;
 	}
@@ -713,6 +821,10 @@
 	DEBUGP(DRR, "SI%2u: %s\n", i, hexdump(si_tmp, rc));
 	rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si_tmp, rc);
 
+#ifdef GPRS
+	rsl_ipacc_pdch_activate(&trx->ts[7].lchan[0]);
+#endif
+
 	return 0;
 err_out:
 	LOGP(DRR, LOGL_ERROR, "Cannot generate SI %u for BTS %u, most likely "
@@ -745,11 +857,28 @@
 
 	/* patch BSIC */
 	bs11_attr_bts[1] = bts->bsic;
-	nanobts_attr_bts[sizeof(nanobts_attr_bts)-1] = bts->bsic;
+	nanobts_attr_bts[sizeof(nanobts_attr_bts)-11] = bts->bsic;
+
+	/* patch CGI */
+	abis_nm_ipaccess_cgi(nanobts_attr_bts+sizeof(nanobts_attr_bts)-7, bts);
 
 	/* patch the power reduction */
 	bs11_attr_radio[5] = bts->c0->max_power_red / 2;
 	nanobts_attr_radio[1] = bts->c0->max_power_red / 2;
+
+	/* patch NSVCI */
+	nanobts_attr_nsvc0[3] = bts->gprs.nsvc[0].nsvci >> 8;
+	nanobts_attr_nsvc0[4] = bts->gprs.nsvc[0].nsvci & 0xff;
+
+	/* FIXME: patch our own IP address as SGSN IP */
+	//nanobts_attr_nsvc0[10] = 
+
+	/* patch BVCI */
+	nanobts_attr_cell[12] = bts->gprs.cell.bvci >> 8;
+	nanobts_attr_cell[13] = bts->gprs.cell.bvci & 0xff;
+	/* patch RAC */
+	nanobts_attr_cell[3] = bts->gprs.rac;
+
 }
 
 static void bootstrap_rsl(struct gsm_bts_trx *trx)
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index a951821..5314d12 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -25,6 +25,8 @@
 #include <errno.h>
 #include <ctype.h>
 
+#include <netinet/in.h>
+
 #include <openbsc/gsm_data.h>
 #include <osmocore/talloc.h>
 #include <osmocore/gsm_utils.h>
@@ -459,6 +461,50 @@
 	return gsm_auth_policy_names[policy];
 }
 
+/* this should not be here but in gsm_04_08... but that creates
+   in turn a dependency nightmare (abis_nm depending on 04_08, ...) */
+static int gsm48_construct_ra(u_int8_t *buf, const struct gprs_ra_id *raid)
+{
+	u_int16_t mcc = raid->mcc;
+	u_int16_t mnc = raid->mnc;
+
+	buf[0] = ((mcc / 100) % 10) | (((mcc / 10) % 10) << 4);
+	buf[1] = (mcc % 10);
+
+	/* I wonder who came up with the stupidity of encoding the MNC
+	 * differently depending on how many digits its decimal number has! */
+	if (mnc < 100) {
+		buf[1] |= 0xf0;
+		buf[2] = ((mnc / 10) % 10) | ((mnc % 10) << 4);
+	} else {
+		buf[1] |= (mnc % 10) << 4;
+		buf[2] = ((mnc / 100) % 10) | (((mcc / 10) % 10) << 4);
+	}
+
+	*(u_int16_t *)(buf+3) = htons(raid->lac);
+
+	buf[5] = raid->rac;
+
+	return 6;
+}
+
+void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts)
+{
+	raid->mcc = bts->network->country_code;
+	raid->mnc = bts->network->network_code;
+	raid->lac = bts->location_area_code;
+	raid->rac = bts->gprs.rac;
+}
+
+int gsm48_ra_id_by_bts(u_int8_t *buf, struct gsm_bts *bts)
+{
+	struct gprs_ra_id raid;
+
+	gprs_ra_id_by_bts(&raid, bts);
+
+	return gsm48_construct_ra(buf, &raid);
+}
+
 static const char *rrlp_mode_names[] = {
 	[RRLP_MODE_NONE] = "none",
 	[RRLP_MODE_MS_BASED] = "ms-based",
diff --git a/openbsc/src/rest_octets.c b/openbsc/src/rest_octets.c
index a57e7df..16996ce 100644
--- a/openbsc/src/rest_octets.c
+++ b/openbsc/src/rest_octets.c
@@ -350,7 +350,7 @@
 		bitvec_set_bit(&bv, H);
 		bitvec_set_uint(&bv, si13->bcch_change_mark, 3);
 		bitvec_set_uint(&bv, si13->si_change_field, 4);
-		if (0) {
+		if (1) {
 			bitvec_set_bit(&bv, 0);
 		} else {
 			bitvec_set_bit(&bv, 1);
diff --git a/openbsc/src/system_information.c b/openbsc/src/system_information.c
index a9df0ba..7015b38 100644
--- a/openbsc/src/system_information.c
+++ b/openbsc/src/system_information.c
@@ -264,7 +264,7 @@
 	.gprs_ind = {
 		.si13_position = 0,
 		.ra_colour = 0,
-		.present = 0,
+		.present = 1,
 	},
 	.lsa_params = {
 		.present = 0,
@@ -398,9 +398,9 @@
 static struct gsm48_si13_info si13_default = {
 	.cell_opts = {
 		.nmo 		= GPRS_NMO_III,
-		.t3168		= 1000,
-		.t3192		= 1000,
-		.drx_timer_max	= 1,
+		.t3168		= 1500,
+		.t3192		= 500,
+		.drx_timer_max	= 3,
 		.bs_cv_max	= 15,
 	},
 	.pwr_ctrl_pars = {
@@ -410,19 +410,31 @@
 		.pc_meas_chan	= 0, 	/* downling measured on CCCH */
 		.n_avg_i	= 15,
 	},
-	.bcch_change_mark	= 0,
+	.bcch_change_mark	= 1,
 	.si_change_field	= 0,
 	.pbcch_present		= 0,
 	{
 		.no_pbcch = {
-			.rac		= 0,
+			.rac		= 0,	/* needs to be patched */
 			.spgc_ccch_sup 	= 0,
 			.net_ctrl_ord	= 0,
-			.prio_acc_thr	= 0,
+			.prio_acc_thr	= 6,
 		},
 	},
 };
 
+static u_int8_t si13_template[] = {
+	0x09, 0x06, 0x00,
+#if 0
+       /* This is what our system_information branch geneates */
+       0x2a, 0x01, 0x00, 0x04, 0x00, 0xd8, 0xa5, 0xef, 0xff, 0xf7,
+#else
+       /* This is what Dieter has sent me as hand-coded example */
+       0x90, 0x00, 0x58, 0x98, 0x6f, 0xc9, 0x70, 0x4a, 0x84, 0x10,
+#endif
+       0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b, 0x2b,
+};
+
 static int generate_si13(u_int8_t *output, struct gsm_bts *bts)
 {
 	struct gsm48_system_information_type_13 *si13 =
@@ -435,12 +447,18 @@
 	si13->header.skip_indicator = 0;
 	si13->header.system_information = GSM48_MT_RR_SYSINFO_13;
 
+	si13_default.no_pbcch.rac = bts->gprs.rac;
+
 	ret = rest_octets_si13(si13->rest_octets, &si13_default);
 	if (ret < 0)
 		return ret;
 
 	si13->header.l2_plen = ret & 0xff;
 
+	printf("SI13 template : %s\n", hexdump(si13_template, GSM_MACBLOCK_LEN));
+	printf("SI13 generated: %s\n", hexdump(si13, GSM_MACBLOCK_LEN));
+	//memcpy(si13, si13_template, sizeof(si13_template));
+
 	return sizeof (*si13) + ret;
 }
 
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index dc70e98..c789a15 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -278,6 +278,7 @@
 static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts)
 {
 	struct gsm_bts_trx *trx;
+	int i;
 
 	vty_out(vty, " bts %u%s", bts->nr, VTY_NEWLINE);
 	vty_out(vty, "  type %s%s", btstype2str(bts->type), VTY_NEWLINE);
@@ -313,6 +314,12 @@
 		config_write_e1_link(vty, &bts->oml_e1_link, "  oml ");
 		vty_out(vty, "  oml e1 tei %u%s", bts->oml_tei, VTY_NEWLINE);
 	}
+	vty_out(vty, "  gprs routing area %u%s", bts->gprs.rac, VTY_NEWLINE);
+	vty_out(vty, "  gprs cell bvci %u%s", bts->gprs.cell.bvci,
+		VTY_NEWLINE);
+	for (i = 0; i < ARRAY_SIZE(bts->gprs.nsvc); i++)
+		vty_out(vty, "  gprs nsvc %u nsvci %u%s", i,
+			bts->gprs.cell.bvci, VTY_NEWLINE);
 
 	llist_for_each_entry(trx, &bts->trx_list, list)
 		config_write_trx_single(vty, trx);
@@ -1604,6 +1611,40 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_bts_gprs_bvci, cfg_bts_gprs_bvci_cmd,
+	"gprs cell bvci <0-65535>",
+	"GPRS BSSGP VC Identifier")
+{
+	struct gsm_bts *bts = vty->index;
+
+	bts->gprs.cell.bvci = atoi(argv[0]);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gprs_nsvci, cfg_bts_gprs_nsvci_cmd,
+	"gprs nsvc <0-1> nsvci <0-65535>",
+	"GPRS NS VC Identifier")
+{
+	struct gsm_bts *bts = vty->index;
+	int idx = atoi(argv[0]);
+
+	bts->gprs.nsvc[idx].nsvci = atoi(argv[1]);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_bts_gprs_rac, cfg_bts_gprs_rac_cmd,
+	"gprs routing area <0-255>",
+	"GPRS Routing Area Code")
+{
+	struct gsm_bts *bts = vty->index;
+
+	bts->gprs.rac = atoi(argv[0]);
+
+	return CMD_SUCCESS;
+}
+
 
 /* per TRX configuration */
 DEFUN(cfg_trx,
@@ -1865,7 +1906,9 @@
 	install_element(BTS_NODE, &cfg_bts_per_loc_upd_cmd);
 	install_element(BTS_NODE, &cfg_bts_cell_resel_hyst_cmd);
 	install_element(BTS_NODE, &cfg_bts_rxlev_acc_min_cmd);
-
+	install_element(BTS_NODE, &cfg_bts_gprs_rac_cmd);
+	install_element(BTS_NODE, &cfg_bts_gprs_bvci_cmd);
+	install_element(BTS_NODE, &cfg_bts_gprs_nsvci_cmd);
 
 	install_element(BTS_NODE, &cfg_trx_cmd);
 	install_node(&trx_node, dummy_config_write);