* add abis_nm_software_load_status() to header file
* new abis_nm_bs11_bsc_disconnect() function to disconnect BSC/BTS link
* add support for 'forced load' of BS-11 software to abis_nm.c and bs11_config
* remove lots of debug output
* print progress during software load

diff --git a/include/openbsc/abis_nm.h b/include/openbsc/abis_nm.h
index b8523b2..c9d12b0 100644
--- a/include/openbsc/abis_nm.h
+++ b/include/openbsc/abis_nm.h
@@ -461,7 +461,9 @@
 int abis_nm_event_reports(struct gsm_bts *bts, int on);
 int abis_nm_reset_resource(struct gsm_bts *bts);
 int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
-			  u_int8_t win_size, gsm_cbfn *cbfn, void *cb_data);
+			  u_int8_t win_size, int forced,
+			  gsm_cbfn *cbfn, void *cb_data);
+int abis_nm_software_load_status(struct gsm_bts *bts);
 int abis_nm_software_activate(struct gsm_bts *bts, const char *fname,
 			      gsm_cbfn *cbfn, void *cb_data);
 
@@ -480,7 +482,8 @@
 int abis_nm_bs11_set_trx1_pw(struct gsm_bts *bts, const char *password);
 int abis_nm_bs11_get_state(struct gsm_bts *bts);
 int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
-			  u_int8_t win_size, gsm_cbfn *cbfn);
+			  u_int8_t win_size, int forced, gsm_cbfn *cbfn);
 int abis_nm_bs11_set_ext_time(struct gsm_bts *bts);
+int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect);
 
 #endif /* _NM_H */
diff --git a/src/abis_nm.c b/src/abis_nm.c
index c9bea25..8ebd96d 100644
--- a/src/abis_nm.c
+++ b/src/abis_nm.c
@@ -296,6 +296,7 @@
 	struct gsm_bts *bts;
 	gsm_cbfn *cbfn;
 	void *cb_data;
+	int forced;
 
 	/* this will become part of the SW LOAD INITIATE */
 	u_int8_t obj_class;
@@ -518,7 +519,7 @@
 	struct abis_nm_sw *sw = &g_sw;
 	enum sw_state old_state = sw->state;
 	
-	DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
+	//DEBUGP(DNM, "state %u, NM MT 0x%02x\n", sw->state, foh->msg_type);
 
 	switch (sw->state) {
 	case SW_STATE_WAIT_INITACK:
@@ -533,18 +534,33 @@
 			sw->state = SW_STATE_WAIT_SEGACK;
 			break;
 		case NM_MT_LOAD_INIT_NACK:
-			DEBUGP(DNM, "Software Load Init NACK\n");
-			if (sw->cbfn)
-				sw->cbfn(GSM_HOOK_NM_SWLOAD,
-					 NM_MT_LOAD_INIT_NACK, mb,
-					 sw->cb_data, NULL);
-			sw->state = SW_STATE_ERROR;
+			if (sw->forced) {
+				DEBUGP(DNM, "FORCED: Ignoring Software Load "
+					"Init NACK\n");
+				if (sw->cbfn)
+					sw->cbfn(GSM_HOOK_NM_SWLOAD,
+						 NM_MT_LOAD_INIT_ACK, mb,
+						 sw->cb_data, NULL);
+				rc = sw_fill_window(sw);
+				sw->state = SW_STATE_WAIT_SEGACK;
+			} else {
+				DEBUGP(DNM, "Software Load Init NACK\n");
+				if (sw->cbfn)
+					sw->cbfn(GSM_HOOK_NM_SWLOAD,
+						 NM_MT_LOAD_INIT_NACK, mb,
+						 sw->cb_data, NULL);
+				sw->state = SW_STATE_ERROR;
+			}
 			break;
 		}
 		break;
 	case SW_STATE_WAIT_SEGACK:
 		switch (foh->msg_type) {
 		case NM_MT_LOAD_SEG_ACK:
+			if (sw->cbfn)
+				sw->cbfn(GSM_HOOK_NM_SWLOAD,
+					 NM_MT_LOAD_SEG_ACK, mb,
+					 sw->cb_data, NULL);
 			sw->seg_in_window = 0;
 			if (!sw->last_seg) {
 				/* fill window with more segments */
@@ -614,7 +630,8 @@
 
 /* Load the specified software into the BTS */
 int abis_nm_software_load(struct gsm_bts *bts, const char *fname,
-			  u_int8_t win_size, gsm_cbfn *cbfn, void *cb_data)
+			  u_int8_t win_size, int forced,
+			  gsm_cbfn *cbfn, void *cb_data)
 {
 	struct abis_nm_sw *sw = &g_sw;
 	int rc;
@@ -634,6 +651,7 @@
 	sw->state = SW_STATE_WAIT_INITACK;
 	sw->cbfn = cbfn;
 	sw->cb_data = cb_data;
+	sw->forced = forced;
 
 	rc = sw_open_file(sw, fname);
 	if (rc < 0) {
@@ -835,8 +853,17 @@
 		return __simple_cmd(bts, NM_MT_REST_EVENT_REP);
 }
 
+
 /* Siemens (or BS-11) specific commands */
 
+int abis_nm_bs11_bsc_disconnect(struct gsm_bts *bts, int reconnect)
+{
+	if (reconnect == 0)
+		return __simple_cmd(bts, NM_MT_BS11_DISCONNECT);
+	else
+		return __simple_cmd(bts, NM_MT_BS11_RECONNECT);
+}
+
 struct bs11_date_time {
 	u_int16_t	year;
 	u_int8_t	month;
@@ -1022,6 +1049,7 @@
 	struct gsm_bts *bts;
 	char swl_fname[PATH_MAX];
 	u_int8_t win_size;
+	int forced;
 	struct llist_head file_list;
 	gsm_cbfn *user_cb;	/* specified by the user */
 };
@@ -1070,7 +1098,7 @@
 
 		if (strlen(linebuf) < 4)
 			continue;
-		printf("linebuf='%s'\n", linebuf);
+	
 		rc = sscanf(linebuf+4, "%12s:%80s\r\n", file_id, file_version);
 		if (rc < 0) {
 			perror("ERR parsing SWL file");
@@ -1092,7 +1120,6 @@
 		strncat(fle->fname, dirname(dir), sizeof(fle->fname) - 1);
 		strcat(fle->fname, "/");
 		strncat(fle->fname, file_id, sizeof(fle->fname) - 1 -strlen(fle->fname));
-		printf("fname='%s'\n", fle->fname);
 		
 		llist_add_tail(&fle->list, &bs11_sw->file_list);
 	}
@@ -1110,8 +1137,6 @@
 	struct file_list_entry *fle;
 	int rc = 0;
 
-	printf("bs11_swload_cbfn(%u, %u, %p, %p, %p)\n", hook, event, msg, data, param);
-
 	switch (event) {
 	case NM_MT_LOAD_END_ACK:
 		fle = fl_dequeue(&bs11_sw->file_list);
@@ -1119,6 +1144,7 @@
 			/* start download the next file of our file list */
 			rc = abis_nm_software_load(bs11_sw->bts, fle->fname,
 						   bs11_sw->win_size,
+						   bs11_sw->forced,
 						   &bs11_swload_cbfn, bs11_sw);
 			free(fle);
 		} else {
@@ -1129,6 +1155,7 @@
 							bs11_sw);
 		}
 		break;
+	case NM_MT_LOAD_SEG_ACK:
 	case NM_MT_LOAD_END_NACK:
 	case NM_MT_LOAD_INIT_ACK:
 	case NM_MT_LOAD_INIT_NACK:
@@ -1147,7 +1174,7 @@
  * files that are part of a software release.  We need to upload first
  * the list file, and then each file that is listed in the list file */
 int abis_nm_bs11_load_swl(struct gsm_bts *bts, const char *fname,
-			  u_int8_t win_size, gsm_cbfn *cbfn)
+			  u_int8_t win_size, int forced, gsm_cbfn *cbfn)
 {
 	struct abis_nm_bs11_sw *bs11_sw = g_bs11_sw;
 	struct file_list_entry *fle;
@@ -1157,6 +1184,7 @@
 	bs11_sw->bts = bts;
 	bs11_sw->win_size = win_size;
 	bs11_sw->user_cb = cbfn;
+	bs11_sw->forced = forced;
 
 	strncpy(bs11_sw->swl_fname, fname, sizeof(bs11_sw->swl_fname));
 	rc = bs11_read_swl_file(bs11_sw);
@@ -1169,7 +1197,7 @@
 		return -EINVAL;
 
 	/* start download the next file of our file list */
-	rc = abis_nm_software_load(bts, fle->fname, win_size,
+	rc = abis_nm_software_load(bts, fle->fname, win_size, forced,
 				   bs11_swload_cbfn, bs11_sw);
 	free(fle);
 	return rc;
diff --git a/src/bs11_config.c b/src/bs11_config.c
index e2916ab..9acf301 100644
--- a/src/bs11_config.c
+++ b/src/bs11_config.c
@@ -92,9 +92,8 @@
 }
 
 /* create all objects for an initial configuration */
-static int create_objects(struct gsm_bts *bts, int trx1)
+static int create_objects(struct gsm_bts *bts)
 {
-	//abis_nm_bs11_factory_logon(bts, 1);
 	abis_nm_bs11_create_object(bts, BS11_OBJ_LI, 0, sizeof(obj_li_attr),
 				   obj_li_attr);
 	abis_nm_bs11_create_object(bts, BS11_OBJ_GPSU, 0, 0, NULL);
@@ -113,7 +112,6 @@
 	abis_nm_bs11_set_oml_tei(bts, TEI_OML);
 
 	abis_nm_bs11_set_trx_power(&bts->trx[0], BS11_TRX_POWER_GSM_30mW);
-	//abis_nm_bs11_factory_logon(bts, 0);
 	
 	return 0;
 }
@@ -124,6 +122,8 @@
 static int delay_ms = 0;
 static int have_trx1 = 0;
 static int win_size = 8;
+static int param_disconnect = 0;
+static int param_forced = 0;
 static struct gsm_bts *g_bts;
 
 static int file_is_readable(const char *fname)
@@ -141,6 +141,9 @@
 	return 0;
 }
 
+static int percent;
+static int percent_old;
+
 /* callback function passed to the ABIS OML code */
 static int swload_cbfn(unsigned int hook, unsigned int event, struct msgb *msg,
 		       void *data, void *param)
@@ -174,6 +177,12 @@
 		bs11cfg_state = STATE_NONE;
 		
 		break;
+	case NM_MT_LOAD_SEG_ACK:
+		percent = abis_nm_software_load_status(g_bts);
+		if (percent > percent_old)
+			printf("Software Download Progress: %d%%\n", percent);
+		percent_old = percent;
+		break;
 	}
 	return 0;
 }
@@ -278,8 +287,8 @@
 		 * a safety load from a regular software */
 		if (file_is_readable(fname_safety))
 			rc = abis_nm_software_load(g_bts, fname_safety,
-						   win_size, swload_cbfn,
-						   g_bts);
+						   win_size, param_forced,
+						   swload_cbfn, g_bts);
 		else
 			fprintf(stderr, "No valid Safety Load file \"%s\"\n",
 				fname_safety);
@@ -287,17 +296,20 @@
 	case BS11_STATE_WAIT_MIN_CFG:
 	case BS11_STATE_WAIT_MIN_CFG_2:
 		bs11cfg_state = STATE_SWLOAD;
-		rc = create_objects(g_bts, have_trx1);
+		rc = create_objects(g_bts);
 		break;
 	case BS11_STATE_MAINTENANCE:
-		bs11cfg_state = STATE_SWLOAD;
-		/* send software (FIXME: over A-bis?) */
-		if (file_is_readable(fname_software))
-			rc = abis_nm_bs11_load_swl(g_bts, fname_software,
-						   win_size, swload_cbfn);
-		else
-			fprintf(stderr, "No valid Software file \"%s\"\n",
-				fname_software);
+		if (bs11cfg_state != STATE_SWLOAD) {
+			bs11cfg_state = STATE_SWLOAD;
+			/* send software (FIXME: over A-bis?) */
+			if (file_is_readable(fname_software))
+				rc = abis_nm_bs11_load_swl(g_bts, fname_software,
+							   win_size, param_forced,
+							   swload_cbfn);
+			else
+				fprintf(stderr, "No valid Software file \"%s\"\n",
+					fname_software);
+		}
 		break;
 	case BS11_STATE_NORMAL:
 		if (have_trx1)
@@ -389,7 +401,9 @@
 	printf("\t-s --software <file>\t\tSpecify Software file\n");
 	printf("\t-S --safety <file>\t\tSpecify Safety Load file\n");
 	printf("\t-d --delay <file>\t\tSpecify delay\n");
+	printf("\t-D --disconnect\t\t\tDisconnect BTS from BSC\n");
 	printf("\t-w --win-size <num>\t\tSpecify Window Size\n");
+	printf("\t-f --forced\t\t\tForce Software Load\n");
 }
 
 static void handle_options(int argc, char **argv)
@@ -405,10 +419,12 @@
 			{ "software", 1, 0, 's' },
 			{ "safety", 1, 0, 'S' },
 			{ "delay", 1, 0, 'd' },
+			{ "disconnect", 0, 0, 'D' },
 			{ "win-size", 1, 0, 'w' },
+			{ "forced", 0, 0, 'f' },
 		};
 
-		c = getopt_long(argc, argv, "hp:s:S:td:w:",
+		c = getopt_long(argc, argv, "hp:s:S:td:Dw:f",
 				long_options, &option_index);
 
 		if (c == -1)
@@ -436,6 +452,12 @@
 		case 'w':
 			win_size = atoi(optarg);
 			break;
+		case 'D':
+			param_disconnect = 1;
+			break;
+		case 'f':
+			param_forced = 1;
+			break;
 		default:
 			break;
 		}
@@ -474,6 +496,9 @@
 	abis_nm_bs11_factory_logon(g_bts, 1);
 	//abis_nm_bs11_get_serno(g_bts);
 
+	if (param_disconnect)
+		abis_nm_bs11_bsc_disconnect(g_bts, 0);
+
 	while (1) {
 		bsc_select_main();
 	}