[handover] Implement 04.08 HANDOVER COMMAND

This is needed by a yet-to-be-implemented handover algorithm, after
it has allocated a new lchan for the MS.  Also missing: handling
the actual HANDOVER COMPLETE / FAIL messages in response.
diff --git a/openbsc/doc/handover.txt b/openbsc/doc/handover.txt
index 524d386..ac19e87 100644
--- a/openbsc/doc/handover.txt
+++ b/openbsc/doc/handover.txt
@@ -75,3 +75,15 @@
 * RXQUAL >= 6: 1 dB
 
 
+
+== Actual Handover on a protocol level ==
+
+After the BSC has decided a handover shall be done, it has to
+
+# allocate a channel at the new BTS
+# allocate a handover reference
+# activate the channel on the BTS side using RSL CHANNEL ACTIVATION,
+  indicating the HO reference
+# BTS responds with CHAN ACT ACK, including GSM frame number
+# BSC sends 04.08 HO CMD to MS using old BTS
+
diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h
index cd85dff..359aa1b 100644
--- a/openbsc/include/openbsc/gsm_04_08.h
+++ b/openbsc/include/openbsc/gsm_04_08.h
@@ -90,6 +90,22 @@
 	u_int8_t data[0];
 } __attribute__((packed));
 
+/* Chapter 10.5.2.2 */
+struct gsm48_cell_desc {
+	u_int8_t bcc:3,
+		 ncc:3,
+		 arfcn_hi:2;
+	u_int8_t arfcn_lo;
+} __attribute__((packed));
+
+/* Chapter 9.1.15 */
+struct gsm48_ho_cmd {
+	struct gsm48_cell_desc cell_desc;
+	struct gsm48_chan_desc chan_desc;
+	u_int8_t ho_ref;
+	u_int8_t power_command;
+	u_int8_t data[0];
+} __attribute__((packed));
 
 /* Chapter 9.1.18 */
 struct gsm48_imm_ass {
diff --git a/openbsc/src/gsm_04_08_utils.c b/openbsc/src/gsm_04_08_utils.c
index ad038fb..d3e4689 100644
--- a/openbsc/src/gsm_04_08_utils.c
+++ b/openbsc/src/gsm_04_08_utils.c
@@ -519,6 +519,50 @@
 	return rsl_encryption_cmd(msg);
 }
 
+static void gsm48_cell_desc(struct gsm48_cell_desc *cd,
+			    const struct gsm_bts *bts)
+{
+	cd->ncc = (bts->bsic >> 3 & 0x7);
+	cd->bcc = (bts->bsic & 0x7);
+	cd->arfcn_hi = bts->c0->arfcn >> 8;
+	cd->arfcn_lo = bts->c0->arfcn & 0xff;
+}
+
+static void gsm48_chan_desc(struct gsm48_chan_desc *cd,
+			    const struct gsm_lchan *lchan)
+{
+	u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
+
+	cd->chan_nr = lchan2chan_nr(lchan);
+	cd->h0.tsc = lchan->ts->trx->bts->tsc;
+	cd->h0.h = 0;
+	cd->h0.arfcn_high = arfcn >> 8;
+	cd->h0.arfcn_low = arfcn & 0xff;
+}
+
+/* Chapter 9.1.15: Handover Command */
+int gsm48_send_ho_cmd(struct gsm_lchan *old_lchan,
+		      struct gsm_lchan *new_lchan, u_int8_t power_command)
+{
+	struct msgb *msg = gsm48_msgb_alloc();
+	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
+	struct gsm48_ho_cmd *ho =
+		(struct gsm48_ho_cmd *) msgb_put(msg, sizeof(*ho));
+	static u_int8_t ho_ref;
+
+	msg->lchan = old_lchan;
+
+	/* mandatory bits */
+	gsm48_cell_desc(&ho->cell_desc, new_lchan->ts->trx->bts);
+	gsm48_chan_desc(&ho->chan_desc, new_lchan);
+	ho->ho_ref = ho_ref++;
+	ho->power_command = power_command;
+
+	/* FIXME: optional bits for type of synchronization? */
+
+	return gsm48_sendmsg(msg, NULL);
+}
+
 /* Chapter 9.1.2: Assignment Command */
 int gsm48_send_rr_ass_cmd(struct gsm_lchan *lchan, u_int8_t power_command)
 {
@@ -526,7 +570,6 @@
 	struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
 	struct gsm48_ass_cmd *ass =
 		(struct gsm48_ass_cmd *) msgb_put(msg, sizeof(*ass));
-	u_int16_t arfcn = lchan->ts->trx->arfcn & 0x3ff;
 
 	DEBUGP(DRR, "-> ASSIGNMENT COMMAND tch_mode=0x%02x\n", lchan->tch_mode);
 
@@ -542,11 +585,7 @@
 	 * the chan_desc. But as long as multi-slot configurations
 	 * are not used we seem to be fine.
 	 */
-	ass->chan_desc.chan_nr = lchan2chan_nr(lchan);
-	ass->chan_desc.h0.tsc = lchan->ts->trx->bts->tsc;
-	ass->chan_desc.h0.h = 0;
-	ass->chan_desc.h0.arfcn_high = arfcn >> 8;
-	ass->chan_desc.h0.arfcn_low = arfcn & 0xff;
+	gsm48_chan_desc(&ass->chan_desc, lchan);
 	ass->power_command = power_command;
 
 	/* in case of multi rate we need to attach a config */