gprs_ns2: Encapsulate setting NSE dialect

Setting the NSE dialect possibly involves the creating (or destruction)
of a IP-SNS FSM.  Encapsulate that, rather than having every caller
re-implement that.

Change-Id: I24fdc26fbcfda039bd58ea166f4d5c2fd1801da1
diff --git a/src/gb/gprs_ns2.c b/src/gb/gprs_ns2.c
index e19ae78..93b7c3a 100644
--- a/src/gb/gprs_ns2.c
+++ b/src/gb/gprs_ns2.c
@@ -781,7 +781,6 @@
 					 enum gprs_ns2_ll linklayer, enum gprs_ns2_dialect dialect)
 {
 	struct gprs_ns2_nse *nse;
-	char sns[16];
 
 	nse = gprs_ns2_nse_by_nsei(nsi, nsei);
 	if (nse) {
@@ -792,17 +791,13 @@
 	nse = talloc_zero(nsi, struct gprs_ns2_nse);
 	if (!nse)
 		return NULL;
+	nse->dialect = GPRS_NS2_DIALECT_UNDEF;
 
-	if (dialect == GPRS_NS2_DIALECT_SNS) {
-		snprintf(sns, sizeof(sns), "NSE%05u-SNS", nsei);
-		nse->bss_sns_fi = ns2_sns_bss_fsm_alloc(nse, sns);
-		if (!nse->bss_sns_fi) {
-			talloc_free(nse);
-			return NULL;
-		}
+	if (ns2_nse_set_dialect(nse, dialect) < 0) {
+		talloc_free(nse);
+		return NULL;
 	}
 
-	nse->dialect = dialect;
 	nse->ll = linklayer;
 	nse->nsei = nsei;
 	nse->nsi = nsi;
@@ -814,6 +809,38 @@
 	return nse;
 }
 
+int ns2_nse_set_dialect(struct gprs_ns2_nse *nse, enum gprs_ns2_dialect dialect)
+{
+	char sns[16];
+
+	if (nse->dialect == dialect)
+		return 0;
+
+	switch (nse->dialect) {
+	case GPRS_NS2_DIALECT_UNDEF:
+		if (dialect == GPRS_NS2_DIALECT_SNS) {
+			snprintf(sns, sizeof(sns), "NSE%05u-SNS", nse->nsei);
+			nse->bss_sns_fi = ns2_sns_bss_fsm_alloc(nse, sns);
+			if (!nse->bss_sns_fi)
+				return -1;
+		}
+		nse->dialect = dialect;
+		break;
+	default:
+		if (dialect == GPRS_NS2_DIALECT_UNDEF) {
+			if (nse->bss_sns_fi)
+				osmo_fsm_inst_term(nse->bss_sns_fi, OSMO_FSM_TERM_REQUEST, NULL);
+			nse->bss_sns_fi = NULL;
+			nse->dialect = GPRS_NS2_DIALECT_UNDEF;
+		} else {
+			/* we don't support arbitrary changes without going through UNDEF first */
+			return -EPERM;
+		}
+	}
+
+	return 0;
+}
+
 /*! Return the NSEI
  * \param[in] nse NS Entity
  * \return the nsei.