* Fix BS11 software download routines in abis_nm.c
* Introduce user-configurable delay when sending serial msgs from bs11_config

diff --git a/src/abis_nm.c b/src/abis_nm.c
index 1e0b69a..3dd8baf 100644
--- a/src/abis_nm.c
+++ b/src/abis_nm.c
@@ -339,26 +339,34 @@
 	struct msgb *msg = nm_msgb_alloc();
 	char seg_buf[256];
 	char *line_buf = seg_buf+2;
+	unsigned char *tlv;
 	u_int8_t len;
-	int rc;
 
 	oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
-	/* FIXME: this is BS11 specific format */
-	rc = fscanf(sw->stream, "%s\r\n", line_buf);
-	if (rc < 1) {
-		perror("fscanf reading segment");
-		return -EINVAL;
+
+	switch (sw->bts->type) {
+	case GSM_BTS_TYPE_BS11:
+		if (fgets(line_buf, sizeof(seg_buf)-2, sw->stream) == NULL) {
+			perror("fgets reading segment");
+			return -EINVAL;
+		}
+		seg_buf[0] = 0x00;
+		seg_buf[1] = 1 + sw->seg_in_window++;
+
+		len = strlen(line_buf) + 2;
+		tlv = msgb_put(msg, TLV_GROSS_LEN(len));
+		tlv_put(tlv, NM_ATT_BS11_FILE_DATA, len, (u_int8_t *)seg_buf);
+		/* BS11 wants CR + LF in excess of the TLV length !?! */
+		tlv[1] -= 2;
+
+		/* we only now know the exact length for the OM hdr */
+		len = strlen(line_buf)+2;
+		break;
+	default:
+		/* FIXME: Other BTS types */
+		return -1;
 	}
-	seg_buf[0] = 0x00;
-	seg_buf[1] = sw->seg_in_window++;
 
-	msgb_tlv_put(msg, NM_ATT_FILE_DATA, 2+strlen(line_buf), 
-		     (u_int8_t *)seg_buf);
-	/* BS11 wants CR + LF in excess of the TLV length !?! */
-	msgb_tv_put(msg, 0x0d, 0x0a);
-
-	/* we only now know the exact length for the OM hdr */
-	len = 2+strlen(line_buf)+2;
 	fill_om_fom_hdr(oh, len, NM_MT_LOAD_SEG, sw->obj_class,
 			sw->obj_instance[0], sw->obj_instance[1],
 			sw->obj_instance[2]);
@@ -423,7 +431,7 @@
 			return -1;
 		}
 		/* read first line and parse file ID and VERSION */
-		rc = fscanf(sw->stream, "@(@)%12s:%80s\r\n", 
+		rc = fscanf(sw->stream, "@(#)%12s:%80s\r\n", 
 			    file_id, file_version);
 		if (rc != 2) {
 			perror("parsing header line of software file");
@@ -434,7 +442,7 @@
 		strcpy((char *)sw->file_version, file_version);
 		sw->file_version_len = strlen(file_version);
 		/* rewind to start of file */
-		fseek(sw->stream, 0, SEEK_SET);
+		rewind(sw->stream);
 		break;	
 	default:
 		/* We don't know how to treat them yet */
diff --git a/src/bs11_config.c b/src/bs11_config.c
index 0be7f7b..b1a8877 100644
--- a/src/bs11_config.c
+++ b/src/bs11_config.c
@@ -40,6 +40,15 @@
 #include <openbsc/tlv.h>
 #include <openbsc/debug.h>
 
+/* state of our bs11_config application */
+enum bs11cfg_state {
+	STATE_NONE,
+	STATE_LOGON_WAIT,
+	STATE_LOGON_ACK,
+	STATE_SWLOAD,
+};
+static enum bs11cfg_state bs11cfg_state = STATE_NONE;
+
 static const u_int8_t obj_li_attr[] = { 
 	0xa0, 0x09, 0x00,
 	0xab, 0x00, 
@@ -55,6 +64,8 @@
 static const char *trx1_password = "1111111111";
 #define TEI_OML	25
 
+static const u_int8_t too_fast[] = { 0x12, 0x80, 0x00, 0x00, 0x02, 0x02 };
+
 /* create all objects for an initial configuration */
 static int create_objects(struct gsm_bts *bts, int trx1)
 {
@@ -104,6 +115,7 @@
 static char *serial_port = "/dev/ttyUSB0";
 static char *fname_safety = "BTSBMC76.SWI";
 static char *fname_software = "HS011106.SWL";
+static int delay_ms = 100;
 static int serial_fd = -1;
 static int have_trx1 = 0;
 static struct gsm_bts *g_bts;
@@ -146,6 +158,7 @@
 	}
 
 	msgb_free(msg);
+	usleep(delay_ms*1000);
 
 	return 0;
 }
@@ -161,6 +174,8 @@
 	if (!msg)
 		return NULL;
 
+	msg->l2h = NULL;
+
 	/* first read two byes to obtain length */
 	while (msg->len < 2) {
 		rc = read(serial_fd, msg->tail, 2 - msg->len);
@@ -176,9 +191,8 @@
 			msg->data[0]);
 
 	/* second byte is LAPD payload length */
-	if (msg->data[1] < LAPD_HDR_LEN + sizeof(struct abis_om_fom_hdr) +
-			   sizeof(struct abis_om_hdr))
-		fprintf(stderr, "Invalied header byte 1(len): %u\n",
+	if (msg->data[1] + 2 < LAPD_HDR_LEN)
+		fprintf(stderr, "Invalid header byte 1(len): %u\n",
 			msg->data[1]);
 
 	while (msg->len < 2 + msg->data[1]) {
@@ -191,10 +205,11 @@
 		msgb_put(msg, rc);
 	}
 
-	msg->l2h = msg->data + LAPD_HDR_LEN;
+	if (msg->len > LAPD_HDR_LEN)
+		msg->l2h = msg->data + LAPD_HDR_LEN;
 
 	fprintf(stdout, "RX: ");
-	hexdump(msg->l2h, msg->len - (msg->l2h - msg->data));
+	hexdump(msg->data, msg->len);
 
 	return msg;
 }
@@ -217,7 +232,10 @@
 
 static int handle_state_resp(u_int8_t state)
 {
+	int rc = 0;
+
 	printf("STATE: ");
+
 	switch (state) {
 	case BS11_STATE_WARM_UP:
 		printf("Warm Up...\n");
@@ -229,9 +247,10 @@
 		break;
 	case BS11_STATE_SOFTWARE_RQD:
 		printf("Software required...\n");
+		bs11cfg_state = STATE_SWLOAD;
 		/* send safety load */
 		if (file_is_readable(fname_safety))
-			abis_nm_software_load(g_bts, fname_safety, 8);
+			rc = abis_nm_software_load(g_bts, fname_safety, 8);
 		else
 			fprintf(stderr, "No valid Safety Load file \"%s\"\n",
 				fname_safety);
@@ -239,13 +258,15 @@
 	case BS11_STATE_WAIT_MIN_CFG:
 	case BS11_STATE_WAIT_MIN_CFG_2:
 		printf("Wait minimal config...\n");
-		create_objects(g_bts, have_trx1);
+		bs11cfg_state = STATE_SWLOAD;
+		rc = create_objects(g_bts, have_trx1);
 		break;
 	case BS11_STATE_MAINTENANCE:
 		printf("Maintenance...\n");
+		bs11cfg_state = STATE_SWLOAD;
 		/* send software (FIXME: over A-bis?) */
 		if (file_is_readable(fname_software))
-			abis_nm_software_load(g_bts, fname_software, 8);
+			rc = abis_nm_software_load(g_bts, fname_software, 8);
 		else
 			fprintf(stderr, "No valid Software file \"%s\"\n",
 				fname_software);
@@ -258,7 +279,7 @@
 		sleep(5);
 		break;
 	}
-	return 0;
+	return rc;
 }
 
 static void print_banner(void)
@@ -274,7 +295,7 @@
 	printf("\t--port /dev/ttyXXX\t-p\tSpecify serial port\n");
 	printf("\t--with-trx1\t\t-t\tAssume the BS-11 has 2 TRX\n");
 	printf("\t--software file\t\t-s\tSpecify Software file\n");
-	printf("\t--safety file\t\t-s\tSpecify Safety Load file\n");
+	printf("\t--safety file\t\t-S\tSpecify Safety Load file\n");
 }
 
 static void handle_options(int argc, char **argv)
@@ -289,6 +310,7 @@
 			{ "with-trx1", 0, 0, 't' },
 			{ "software", 1, 0, 's' },
 			{ "safety", 1, 0, 'S' },
+			{ "delay", 1, 0, 'd' },
 		};
 
 		c = getopt_long(argc, argv, "hp:s:S:t",
@@ -313,24 +335,19 @@
 		case 'S':
 			fname_safety = optarg;
 			break;
+		case 'd':
+			delay_ms = atoi(optarg);
+			break;
 		default:
 			break;
 		}
 	}
 }
 
-enum bs11_state {
-	STATE_NONE,
-	STATE_LOGON_WAIT,
-	STATE_LOGON_ACK,
-	STATE_SWLOAD,
-};
-
 int main(int argc, char **argv)
 {
 	struct gsm_network *gsmnet;
 	struct termios tio;
-	enum bs11_state state = STATE_NONE;
 	int rc;
 
 	handle_options(argc, argv);
@@ -377,13 +394,28 @@
 
 		rx_msg = serial_read_msg();
 
+		if (rx_msg->len < LAPD_HDR_LEN
+				  + sizeof(struct abis_om_fom_hdr)
+				  + sizeof(struct abis_om_hdr)) {
+			if (!memcmp(rx_msg->data + 2, too_fast,
+				    sizeof(too_fast))) {
+				fprintf(stderr, "BS11 tells us we're too "
+					"fast, try --delay bigger than %u\n",
+					delay_ms);
+				break;
+			} else
+				fprintf(stderr, "unknown BS11 message\n");
+
+			continue;
+		}
+
 		oh = (struct abis_om_hdr *) msgb_l2(rx_msg);
 		foh = (struct abis_om_fom_hdr *) oh->data;
 		switch (foh->msg_type) {
 		case NM_MT_BS11_FACTORY_LOGON_ACK:
 			printf("FACTORY LOGON: ACK\n");
-			if (state == STATE_NONE)
-				state = STATE_LOGON_ACK;
+			if (bs11cfg_state == STATE_NONE)
+				bs11cfg_state = STATE_LOGON_ACK;
 			rc = 0;
 			break;
 		case NM_MT_BS11_GET_STATE_ACK:
@@ -394,12 +426,12 @@
 		}
 		if (rc < 0) {
 			perror("in main loop");
-			break;
+			//break;
 		}
 		if (rc == 1)
 			break;
 
-		switch (state) {
+		switch (bs11cfg_state) {
 		case STATE_NONE:
 			abis_nm_bs11_factory_logon(g_bts, 1);
 			break;