[BSC] introduce the concept of 'BTS features'

We can then check if a bts supports a certain feature or not.
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 1074344..8cb09d2 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -402,6 +402,17 @@
 	const char *name;
 
 	struct tlv_definition nm_att_tlvdef;
+
+	struct bitvec features;
+	uint8_t _features_data[128/8];
+};
+
+enum gsm_bts_features {
+	BTS_FEAT_HSCSD,
+	BTS_FEAT_GPRS,
+	BTS_FEAT_EGPRS,
+	BTS_FEAT_ECSD,
+	BTS_FEAT_HOPPING,
 };
 
 /**
@@ -792,6 +803,8 @@
 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_btsmodel_set_feature(struct gsm_bts_model *model, enum gsm_bts_features feat);
+int gsm_bts_has_feature(struct gsm_bts *bts, enum gsm_bts_features feat);
 int gsm_bts_model_register(struct gsm_bts_model *model);
 
 #endif
diff --git a/openbsc/src/bsc_vty.c b/openbsc/src/bsc_vty.c
index 5eacb22..46a13d3 100644
--- a/openbsc/src/bsc_vty.c
+++ b/openbsc/src/bsc_vty.c
@@ -1817,8 +1817,22 @@
 	"EGPRS (EDGE) Enabled on this BTS\n")
 {
 	struct gsm_bts *bts = vty->index;
+	enum bts_gprs_mode mode = bts_gprs_mode_parse(argv[0]);
 
-	bts->gprs.mode = bts_gprs_mode_parse(argv[0]);
+	if (mode != BTS_GPRS_NONE &&
+	    !gsm_bts_has_feature(bts, BTS_FEAT_GPRS)) {
+		vty_out(vty, "This BTS type does not support %s%s", argv[0],
+			VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+	if (mode == BTS_GPRS_EGPRS &&
+	    !gsm_bts_has_feature(bts, BTS_FEAT_EGPRS)) {
+		vty_out(vty, "This BTS type does not support %s%s", argv[0],
+			VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	bts->gprs.mode = mode;
 
 	return CMD_SUCCESS;
 }
diff --git a/openbsc/src/bts_ipaccess_nanobts.c b/openbsc/src/bts_ipaccess_nanobts.c
index cb48ea9..92ab41a 100644
--- a/openbsc/src/bts_ipaccess_nanobts.c
+++ b/openbsc/src/bts_ipaccess_nanobts.c
@@ -80,5 +80,11 @@
 
 int bts_model_nanobts_init(void)
 {
+	model_nanobts.features.data = &model_nanobts._features_data;
+	model_nanobts.features.data_len = sizeof(model_nanobts._features_data);
+
+	gsm_btsmodel_set_feature(&model_nanobts, BTS_FEAT_GPRS);
+	gsm_btsmodel_set_feature(&model_nanobts, BTS_FEAT_EGPRS);
+
 	return gsm_bts_model_register(&model_nanobts);
 }
diff --git a/openbsc/src/bts_siemens_bs11.c b/openbsc/src/bts_siemens_bs11.c
index c966825..3d4ddda 100644
--- a/openbsc/src/bts_siemens_bs11.c
+++ b/openbsc/src/bts_siemens_bs11.c
@@ -62,5 +62,11 @@
 
 int bts_model_bs11_init(void)
 {
+	model_bs11.features.data = &model_bs11._features_data;
+	model_bs11.features.data_len = sizeof(model_bs11._features_data);
+
+	gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_HOPPING);
+	gsm_btsmodel_set_feature(&model_bs11, BTS_FEAT_HSCSD);
+
 	return gsm_bts_model_register(&model_bs11);
 }
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index ede1c00..bbf150a 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -519,6 +519,16 @@
 	return meas_rep;
 }
 
+int gsm_btsmodel_set_feature(struct gsm_bts_model *bts, enum gsm_bts_features feat)
+{
+	return bitvec_set_bit_pos(&bts->features, feat, 1);
+}
+
+int gsm_bts_has_feature(struct gsm_bts *bts, enum gsm_bts_features feat)
+{
+	return bitvec_get_bit_pos(&bts->model->features, feat);
+}
+
 int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type)
 {
 	struct gsm_bts_model *model;