Merge branch 'master' of git@192.168.100.10:openbsc
diff --git a/hlrsync/hlrsync.py b/hlrsync/hlrsync.py
new file mode 100755
index 0000000..b2a632b
--- /dev/null
+++ b/hlrsync/hlrsync.py
@@ -0,0 +1,103 @@
+#!/usr/bin/python2.5
+
+from __future__ import with_statement
+
+from pysqlite2 import dbapi2 as sqlite3
+import sys
+
+hlr = sqlite3.connect(sys.argv[1])
+web = sqlite3.connect(sys.argv[2])
+
+# switch to autocommit
+hlr.isolation_level = None
+web.isolation_level = None
+
+hlr.row_factory = sqlite3.Row
+web.row_factory = sqlite3.Row
+
+with hlr:
+	hlr_subscrs = hlr.execute("""
+		SELECT * FROM Subscriber
+	""").fetchall()
+	hlr_tokens = hlr.execute("""
+		SELECT * FROM AuthToken
+	""").fetchall()
+
+with web:
+	web_tokens = web.execute("""
+		SELECT * FROM reg_tokens
+	""").fetchall()
+
+# index by subscr id
+hlr_subscrs_by_id = {}
+hlr_tokens_by_subscr_id = {}
+for x in hlr_subscrs:
+	hlr_subscrs_by_id[x['id']] = x
+del hlr_subscrs
+for x in hlr_tokens:
+	hlr_tokens_by_subscr_id[x['subscriber_id']] = x
+del hlr_tokens
+
+web_tokens_by_subscr_id = {}
+for x in web_tokens:
+	web_tokens_by_subscr_id[x['subscriber_id']] = x
+del web_tokens
+
+# remove leftover web_tokens and correct inconsistent fields
+with web:
+	for x in web_tokens_by_subscr_id.values():
+		subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None)
+		if subscr is None:
+			web.execute("""
+				      DELETE FROM reg_tokens WHERE subscriber_id = ?
+				   """, (x['subscriber_id'],))
+			del web_tokens_by_subscr_id[x['subscriber_id']]
+			continue
+		if str(x['imsi']) != str(subscr['imsi']) or \
+		   x['extension'] != subscr['extension'] or \
+		   x['tmsi'] != subscr['tmsi'] or \
+		   x['lac'] != subscr['lac']:
+			web.execute("""
+				      UPDATE reg_tokens
+				      SET imsi = ?, extension = ?, tmsi = ?, lac = ?
+				      WHERE subscriber_id = ?
+				   """, (str(subscr['imsi']), subscr['extension'], x['subscriber_id']))
+			x['imsi'] = str(subscr['imsi'])
+			x['extension'] = subscr['extension']
+			x['tmsi'] = subscr['tmsi']
+			x['lac'] = subscr['lac']
+
+# add missing web_tokens
+with web:
+	for x in hlr_tokens_by_subscr_id.values():
+		subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None)
+		if subscr is None:
+			hlr.execute("""
+				      DELETE FROM AuthToken WHERE subscriber_id = ?
+				   """, (x['subscriber_id'],))
+			del hlr_tokens_by_subscr_id[x['subscriber_id']]
+			continue
+		webtoken = web_tokens_by_subscr_id.get(x['subscriber_id'], None)
+		if webtoken is None:
+			web.execute("""
+				      INSERT INTO reg_tokens
+				      (subscriber_id, extension, reg_completed, name, email, lac, imsi, token, tmsi)
+				      VALUES
+				      (?, ?, 0, ?, '', ?, ?, ?, ?)
+				   """, (x['subscriber_id'], subscr['extension'], subscr['name'],
+				   subscr['lac'], str(subscr['imsi']), x['token'], subscr['tmsi']))
+
+# authorize subscribers
+with hlr:
+	for x in web_tokens_by_subscr_id.values():
+		subscr = hlr_subscrs_by_id.get(x['subscriber_id'], None)
+		if x['reg_completed'] and not subscr['authorized']:
+			hlr.execute("""
+				      UPDATE Subscriber
+				      SET authorized = 1
+				      WHERE id = ?
+				   """, (x['subscriber_id'],))
+
+hlr.close()
+web.close()
+
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 1a6a72a..4bdca2a 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -302,6 +302,8 @@
 	 * rather than starting from TRX0 and go upwards? */
 	int chan_alloc_reverse;
 	int cell_barred;
+	/* maximum Tx power that the MS is permitted to use in this cell */
+	int ms_max_power;
 
 	/* how do we talk OML with this TRX? */
 	struct gsm_e1_subslot oml_e1_link;
diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h
index 0dc1772..1af8496 100644
--- a/openbsc/include/openbsc/signal.h
+++ b/openbsc/include/openbsc/signal.h
@@ -83,7 +83,6 @@
 enum signal_subscr {
 	S_SUBSCR_ATTACHED,
 	S_SUBSCR_DETACHED,
-	S_SUBSCR_FIRST_CONTACT,
 };
 
 typedef int signal_cbfn(unsigned int subsys, unsigned int signal,
diff --git a/openbsc/src/abis_rsl.c b/openbsc/src/abis_rsl.c
index f107216..d54f2fd 100644
--- a/openbsc/src/abis_rsl.c
+++ b/openbsc/src/abis_rsl.c
@@ -1082,7 +1082,7 @@
 	arfcn = lchan->ts->trx->arfcn;
 	subch = lchan->nr;
 	
-	lchan->ms_power = ms_pwr_ctl_lvl(bts->band, 20 /* dBm == 100mW */);
+	lchan->ms_power = ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
 	lchan->bs_power = 0; /* 0dB reduction, output power = Pn */
 	lchan->rsl_cmode = RSL_CMOD_SPD_SIGN;
 	rsl_chan_activate_lchan(lchan, 0x00, rqd_ta);
diff --git a/openbsc/src/bsc_hack.c b/openbsc/src/bsc_hack.c
index 15bc70c..4253959 100644
--- a/openbsc/src/bsc_hack.c
+++ b/openbsc/src/bsc_hack.c
@@ -956,7 +956,7 @@
 
 	/* patch MS max power for CCH */
 	type_4->cell_sel_par.ms_txpwr_max_ccch =
-			ms_pwr_ctl_lvl(bts->band, 20 /* dBm == 100mW */);
+			ms_pwr_ctl_lvl(bts->band, bts->ms_max_power);
 
 	if (bts->cell_barred) {
 		type_1->rach_control.cell_bar = 1;
@@ -1115,7 +1115,6 @@
 	printf("  -s --disable-color\n");
 	printf("  -c --config-file filename The config file to use.\n");
 	printf("  -l --database db-name The database to use\n");
-	printf("  -a --authorize-everyone Allow everyone into the network.\n");
 	printf("  -r --reject-cause number The reject cause for LOCATION UPDATING REJECT.\n");
 	printf("  -p --pcap file  The filename of the pcap file\n");
 	printf("  -C --cardnr number  For bs11 select E1 card number other than 0\n");
@@ -1165,9 +1164,6 @@
 		case 'c':
 			config_file = strdup(optarg);
 			break;
-		case 'a':
-			gsm0408_allow_everyone(1);
-			break;
 		case 'r':
 			gsm0408_set_reject_cause(atoi(optarg));
 			break;
@@ -1222,6 +1218,7 @@
 	int rc;
 
 	tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
+	on_dso_load_token();
 
 	/* parse options */
 	handle_options(argc, argv);
diff --git a/openbsc/src/db.c b/openbsc/src/db.c
index 938c5c4..0704bca 100644
--- a/openbsc/src/db.c
+++ b/openbsc/src/db.c
@@ -468,23 +468,24 @@
  * an error.
  */
 
-int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* token) {
-	dbi_result result=NULL;
+int db_subscriber_alloc_token(struct gsm_subscriber* subscriber, u_int32_t* token)
+{
+	dbi_result result;
 	u_int32_t try;
+
 	for (;;) {
 		try = rand();
 		if (!try) /* 0 is an invalid token */
 			continue;
 		result = dbi_conn_queryf(conn,
 			"SELECT * FROM AuthToken "
-			"WHERE subscriber_id = %llu OR token = %08x ",
-			subscriber->id, try
-		);
-		if (result==NULL) {
+			"WHERE subscriber_id = %llu OR token = \"%08X\" ",
+			subscriber->id, try);
+		if (!result) {
 			printf("DB: Failed to query AuthToken while allocating new token.\n");
 			return 1;
 		}
-		if (dbi_result_get_numrows(result)){
+		if (dbi_result_get_numrows(result)) {
 			dbi_result_free(result);
 			continue;
 		}
@@ -498,15 +499,16 @@
 		"INSERT INTO AuthToken "
 		"(subscriber_id, created, token) "
 		"VALUES "
-		"(%llu, datetime('now'), %08x)) ",
-		subscriber->id, try
-	);
-	if (result==NULL) {
-		printf("DB: Failed to create token %08x for IMSI %s.\n", try, subscriber->imsi);
+		"(%llu, datetime('now'), \"%08X\") ",
+		subscriber->id, try);
+	if (!result) {
+		printf("DB: Failed to create token %08X for IMSI %s.\n", try, subscriber->imsi);
 		return 1;
 	}
+	dbi_result_free(result);
 	*token = try;
-	printf("DB: Allocated token %08x for IMSI %s.\n", try, subscriber->imsi);
+	printf("DB: Allocated token %08X for IMSI %s.\n", try, subscriber->imsi);
+
 	return 0;
 }
 
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index f0ec3ff..03fe010 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -35,6 +35,7 @@
 #include <openbsc/tlv.h>
 #include <openbsc/debug.h>
 #include <openbsc/gsm_data.h>
+#include <openbsc/gsm_utils.h>
 #include <openbsc/gsm_subscriber.h>
 #include <openbsc/gsm_04_11.h>
 #include <openbsc/gsm_04_08.h>
@@ -304,13 +305,6 @@
 	u_int16_t lac;
 };
 
-static int authorize_everonye = 0;
-void gsm0408_allow_everyone(int everyone)
-{
-	printf("Allowing everyone?\n");
-	authorize_everonye = everyone;
-}
-
 static int reject_cause = 0;
 void gsm0408_set_reject_cause(int cause)
 {
@@ -333,10 +327,16 @@
 	if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei))
 		return 0;
 
-	if (authorize_everonye)
+	switch (subscriber->net->auth_policy) {
+	case GSM_AUTH_POLICY_CLOSED:
+		return subscriber->authorized;
+	case GSM_AUTH_POLICY_TOKEN:
+		return (subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT);
+	case GSM_AUTH_POLICY_ACCEPT_ALL:
 		return 1;
-
-	return subscriber->authorized;
+	default:
+		return 0;
+	}
 }
 
 static void release_loc_updating_req(struct gsm_lchan *lchan)
@@ -1154,12 +1154,8 @@
 		/* look up subscriber based on IMSI, create if not found */
 		if (!lchan->subscr) {
 			lchan->subscr = subscr_get_by_imsi(net, mi_string);
-		}
-		if (!lchan->subscr) {
-			lchan->subscr = db_create_subscriber(net, mi_string);
-			if (lchan->subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) {
-				dispatch_signal(SS_SUBSCR, S_SUBSCR_FIRST_CONTACT, &lchan->subscr);
-			}
+			if (!lchan->subscr)
+				lchan->subscr = db_create_subscriber(net, mi_string);
 		}
 		if (lchan->loc_operation)
 			lchan->loc_operation->waiting_for_imsi = 0;
@@ -1256,9 +1252,6 @@
 		if (!subscr) {
 			subscr = db_create_subscriber(bts->network, mi_string);
 		}
-		if (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) {
-			dispatch_signal(SS_SUBSCR, S_SUBSCR_FIRST_CONTACT, &subscr);
-		}
 		break;
 	case GSM_MI_TYPE_TMSI:
 		DEBUGPC(DMM, "\n");
@@ -1343,7 +1336,7 @@
 	struct gsm_network *net = lchan->ts->trx->bts->network;
 	u_int8_t *ptr8;
 	u_int16_t *ptr16;
-	int name_len;
+	int name_len, name_pad;
 	int i;
 #if 0
 	time_t cur_t;
@@ -1358,6 +1351,7 @@
 	gh->msg_type = GSM48_MT_MM_INFO;
 
 	if (net->name_long) {
+#if 0
 		name_len = strlen(net->name_long);
 		/* 10.5.3.5a */
 		ptr8 = msgb_put(msg, 3);
@@ -1371,9 +1365,24 @@
 
 		/* FIXME: Use Cell Broadcast, not UCS-2, since
 		 * UCS-2 is only supported by later revisions of the spec */
+#endif
+		name_len = (strlen(net->name_long)*7)/8;
+		name_pad = (8 - strlen(net->name_long)*7)%8;
+		if (name_pad > 0)
+			name_len++;
+		/* 10.5.3.5a */
+		ptr8 = msgb_put(msg, 3);
+		ptr8[0] = GSM48_IE_NAME_LONG;
+		ptr8[1] = name_len +1;
+		ptr8[2] = 0x80 | name_pad; /* Cell Broadcast DCS, no CI */
+
+		ptr8 = msgb_put(msg, name_len);
+		gsm_7bit_encode(ptr8, net->name_long);
+
 	}
 
 	if (net->name_short) {
+#if 0
 		name_len = strlen(net->name_short);
 		/* 10.5.3.5a */
 		ptr8 = (u_int8_t *) msgb_put(msg, 3);
@@ -1384,6 +1393,20 @@
 		ptr16 = (u_int16_t *) msgb_put(msg, name_len*2);
 		for (i = 0; i < name_len; i++)
 			ptr16[i] = htons(net->name_short[i]);
+#endif
+		name_len = (strlen(net->name_short)*7)/8;
+		name_pad = (8 - strlen(net->name_short)*7)%8;
+		if (name_pad > 0)
+			name_len++;
+		/* 10.5.3.5a */
+		ptr8 = (u_int8_t *) msgb_put(msg, 3);
+		ptr8[0] = GSM48_IE_NAME_SHORT;
+		ptr8[1] = name_len +1;
+		ptr8[2] = 0x80 | name_pad; /* Cell Broadcast DCS, no CI */
+
+		ptr8 = msgb_put(msg, name_len);
+		gsm_7bit_encode(ptr8, net->name_short);
+
 	}
 
 #if 0
@@ -1405,6 +1428,8 @@
 		ptr8[7] |= 0x80;
 #endif
 
+	DEBUGP(DMM, "-> MM INFO\n");
+
 	return gsm48_sendmsg(msg, NULL);
 }
 
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index 16c5c07..1b1368f 100644
--- a/openbsc/src/gsm_04_11.c
+++ b/openbsc/src/gsm_04_11.c
@@ -175,6 +175,10 @@
 		/* FIXME: implementation */
 		DEBUGP(DSMS, "VPI enhanced not implemented yet\n");
 		break;
+	case GSM340_TP_VPF_NONE:
+		/* Default validity: two days */
+		minutes = 24 * 60 * 2;
+		break;
 	}
 	return minutes;
 }
@@ -272,6 +276,7 @@
 	u_int8_t *smsp;
 	u_int8_t oa[12];	/* max len per 03.40 */
 	u_int8_t oa_len = 0;
+	u_int8_t octet_len;
 	unsigned int old_msg_len = msg->len;
 
 	/* generate first octet with masked bits */
@@ -317,10 +322,13 @@
 	/* generate TP-UD */
 	/* FIXME: Handle DSC of UCS2 or 8/bit default */
 	if (gsm338_get_sms_alphabet(sms->data_coding_scheme) == DCS_7BIT_DEFAULT) {
+		octet_len = sms->user_data_len*7/8;
+		if (sms->user_data_len*7%8 != 0)
+			octet_len++;
 		/* Warning, user_data_len indicates the amount of septets
 		 * (characters), we need amount of octets occupied */
-		smsp = msgb_put(msg, ceil(sms->user_data_len*7/8.0));
-		memcpy(smsp, sms->user_data, ceil(sms->user_data_len*7/8.0));
+		smsp = msgb_put(msg, octet_len);
+		memcpy(smsp, sms->user_data, octet_len);
 	}
 
 	return msg->len - old_msg_len;
@@ -383,6 +391,9 @@
 		sms_vp = smsp;
 		smsp += 7;
 		break;
+	case GSM340_TP_VPF_NONE:
+		sms_vp = 0;
+		break;
 	default:
 		DEBUGP(DSMS, "SMS Validity period not implemented: 0x%02x\n",
 				sms_vpf);
@@ -954,6 +965,8 @@
 	struct gsm_lchan *lchan;
 	struct gsm_sms *sms;
 
+	u_int32_t token;
+
 	switch (signal) {
 	case S_SUBSCR_ATTACHED:
 		/* A subscriber has attached. Check if there are
diff --git a/openbsc/src/gsm_data.c b/openbsc/src/gsm_data.c
index 22e8422..7e8100d 100644
--- a/openbsc/src/gsm_data.c
+++ b/openbsc/src/gsm_data.c
@@ -151,6 +151,7 @@
 	bts->bsic = bsic;
 	bts->num_trx = 0;
 	INIT_LLIST_HEAD(&bts->trx_list);
+	bts->ms_max_power = 15;	/* dBm */
 
 	/* create our primary TRX */
 	bts->c0 = gsm_bts_trx_alloc(bts);
diff --git a/openbsc/src/token_auth.c b/openbsc/src/token_auth.c
index be951c4..6d4f14b 100644
--- a/openbsc/src/token_auth.c
+++ b/openbsc/src/token_auth.c
@@ -20,34 +20,94 @@
  *
  */
 
+#include <stdio.h>
+#include <openbsc/talloc.h>
 #include <openbsc/signal.h>
 #include <openbsc/gsm_data.h>
 #include <openbsc/gsm_04_11.h>
 #include <openbsc/gsm_04_08.h>
 #include <openbsc/gsm_subscriber.h>
+#include <openbsc/chan_alloc.h>
+#include <openbsc/db.h>
 
-#define TOKEN_SMS_TEXT "HAR 2009 GSM.  Please visit http://127.0.0.1/ to register"
+#define TOKEN_SMS_TEXT "HAR 2009 GSM.  Please visit http://har2009.gnumonks.org/ to" \
+			"register. Your IMSI is %s, your auth token is %08X."
+
+static char *build_sms_string(struct gsm_subscriber *subscr, u_int32_t token)
+{
+	char *sms_str;
+	unsigned int len;
+
+	len = strlen(subscr->imsi) + 8 + strlen(TOKEN_SMS_TEXT);
+	sms_str = talloc_size(tall_bsc_ctx, len);
+	if (!sms_str)
+		return NULL;
+
+	snprintf(sms_str, len, TOKEN_SMS_TEXT, subscr->imsi, token);
+	sms_str[len-1] = '\0';
+
+	return sms_str;
+}
 
 static int token_subscr_cb(unsigned int subsys, unsigned int signal,
 			void *handler_data, void *signal_data)
 {
 	struct gsm_subscriber *subscr = signal_data;
 	struct gsm_sms *sms;
+	int rc = 0;
 
 	if (subscr->net->auth_policy != GSM_AUTH_POLICY_TOKEN)
 		return 0;
 
-	switch (signal) {
-	case S_SUBSCR_FIRST_CONTACT:
+	if (signal != S_SUBSCR_ATTACHED)
+		return 0;
+
+	if (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) {
+		u_int32_t token;
+		char *sms_str;
+
 		/* we've seen this subscriber for the first time. */
-		sms = sms_from_text(subscr, TOKEN_SMS_TEXT);
-		if (!sms)
-			return -ENOMEM;
-		gsm411_send_sms_subscr(subscr, sms);
-		break;
+		rc = db_subscriber_alloc_token(subscr, &token);
+		if (rc != 0) {
+			rc = -EIO;
+			goto unauth;
+		}
+
+		sms_str = build_sms_string(subscr, token);
+		if (!sms_str) {
+			rc = -ENOMEM;
+			goto unauth;
+		}
+
+		sms = sms_from_text(subscr, sms_str);
+		talloc_free(sms_str);
+		if (!sms) {
+			rc = -ENOMEM;
+			goto unauth;
+		}
+
+		rc = gsm411_send_sms_subscr(subscr, sms);
+
+		/* FIXME: else, delete the subscirber from database */
+unauth:
+
+		/* make sure we don't allow him in again unless he clicks the web UI */
+		subscr->authorized = 0;
+		db_sync_subscriber(subscr);
+		if (rc) {
+			struct gsm_lchan *lchan = lchan_for_subscr(subscr);
+			if (lchan) {
+				u_int8_t auth_rand[16];
+				/* kick the subscriber off the network */
+				gsm48_tx_mm_auth_req(lchan, auth_rand);
+				gsm48_tx_mm_auth_rej(lchan);
+				/* FIXME: close the channel early ?*/
+				//gsm48_send_rr_Release(lchan);
+			}
+		}
 	}
 
-	return 0;
+	return rc;
 }
 
 static int token_sms_cb(unsigned int subsys, unsigned int signal,
@@ -55,37 +115,37 @@
 {
 	struct gsm_sms *sms = signal_data;
 	struct gsm_lchan *lchan;
-	u_int16_t rand[16];
+	u_int8_t auth_rand[16];
+
 
 	if (signal != S_SMS_DELIVERED)
 		return 0;
 
+
 	/* these are not the droids we've been looking for */
 	if (!sms->receiver ||
 	    !(sms->receiver->flags & GSM_SUBSCRIBER_FIRST_CONTACT))
 		return 0;
 
+
 	if (sms->receiver->net->auth_policy != GSM_AUTH_POLICY_TOKEN)
 		return 0;
 
+
 	lchan = lchan_for_subscr(sms->receiver);
 	if (lchan) {
 		/* kick the subscriber off the network */
-		gsm48_tx_mm_auth_req(lchan, rand);
+		gsm48_tx_mm_auth_req(lchan, auth_rand);
 		gsm48_tx_mm_auth_rej(lchan);
-		/* close the channel */
+		/* FIXME: close the channel early ?*/
 		//gsm48_send_rr_Release(lchan);
-		lchan_free(lchan);
 	}
 
-	/* make sure we don't allow him in again unless he clicks the web UI */
-	sms->receiver->authorized = 0;
-	db_sync_subscriber(sms->receiver);
-
 	return 0;
 }
 
-static __attribute__((constructor)) void on_dso_load_token(void)
+//static __attribute__((constructor)) void on_dso_load_token(void)
+void on_dso_load_token(void)
 {
 	register_signal_handler(SS_SUBSCR, token_subscr_cb, NULL);
 	register_signal_handler(SS_SMS, token_sms_cb, NULL);
diff --git a/openbsc/src/vty_interface.c b/openbsc/src/vty_interface.c
index 70c5e01..4933bb4 100644
--- a/openbsc/src/vty_interface.c
+++ b/openbsc/src/vty_interface.c
@@ -233,6 +233,7 @@
 		VTY_NEWLINE);
 	vty_out(vty, "  training_sequence_code %u%s", bts->tsc, VTY_NEWLINE);
 	vty_out(vty, "  base_station_id_code %u%s", bts->bsic, VTY_NEWLINE);
+	vty_out(vty, "  ms max power %u%s", bts->ms_max_power, VTY_NEWLINE);
 	vty_out(vty, "  channel allocator %s%s",
 		bts->chan_alloc_reverse ? "descending" : "ascending",
 		VTY_NEWLINE);
@@ -975,6 +976,17 @@
 	return CMD_SUCCESS;
 }
 
+DEFUN(cfg_bts_ms_max_power, cfg_bts_ms_max_power_cmd,
+      "ms max power <0-40>",
+      "Maximum transmit power of the MS")
+{
+	struct gsm_bts *bts = vty->index;
+
+	bts->ms_max_power = atoi(argv[0]);
+
+	return CMD_SUCCESS;
+}
+
 
 /* per TRX configuration */
 DEFUN(cfg_trx,
@@ -1205,11 +1217,10 @@
 
 	if (!receiver->lac) {
 		/* subscriber currently not attached, store in database? */
-		subscr_put(sms->receiver);
 		return CMD_WARNING;
 	}
 
-	sms->receiver = receiver;
+	sms->receiver = subscr_get(receiver);
 	strncpy(sms->text, text, sizeof(sms->text)-1);
 
 	/* FIXME: don't use ID 1 static */
@@ -1233,7 +1244,7 @@
 
 	sms = sms_from_text(receiver, buffer_getstr(b));
 
-	gsm411_send_sms_subscr(sms->receiver, sms);
+	gsm411_send_sms_subscr(receiver, sms);
 
 	return CMD_SUCCESS;
 }
@@ -1374,6 +1385,7 @@
 	install_element(BTS_NODE, &cfg_bts_oml_e1_tei_cmd);
 	install_element(BTS_NODE, &cfg_bts_challoc_cmd);
 	install_element(BTS_NODE, &cfg_bts_cell_barred_cmd);
+	install_element(BTS_NODE, &cfg_bts_ms_max_power_cmd);
 
 
 	install_element(BTS_NODE, &cfg_trx_cmd);