Add support for ip.access RSL link on port 3003

diff --git a/src/abis_nm.c b/src/abis_nm.c
index 159424a..e3346a6 100644
--- a/src/abis_nm.c
+++ b/src/abis_nm.c
@@ -537,16 +537,26 @@
 {
 	struct abis_om_hdr *oh = msgb_l2(mb);
 	struct abis_om_fom_hdr *foh = msgb_l3(mb);
+	int nack = 0;
 	int ret;
 
-	DEBUGP(DNM, "Software Activate Request, ACKing and Activating\n");
+	DEBUGP(DNM, "Software Activate Request ");
 
-	ret =  abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
+	if (foh->obj_class >= 0xf0 && foh->obj_class <= 0xf3) {
+		DEBUGPC(DNM, "NACKing for GPRS obj_class 0x%02x\n", foh->obj_class);
+		nack = 1;
+	} else
+		DEBUGPC(DNM, "ACKing and Activating\n");
+
+	ret = abis_nm_sw_act_req_ack(mb->trx->bts, foh->obj_class,
 				      foh->obj_inst.bts_nr,
 				      foh->obj_inst.trx_nr,
-				      foh->obj_inst.ts_nr,
+				      foh->obj_inst.ts_nr, nack,
 				      foh->data, oh->length-sizeof(*foh));
 
+	if (nack)
+		return ret;
+
 	/* FIXME: properly parse attributes */
 	return ipacc_sw_activate(mb->trx->bts, foh->obj_class,
 				 foh->obj_inst.bts_nr,
@@ -1290,18 +1300,27 @@
 }
 
 int abis_nm_sw_act_req_ack(struct gsm_bts *bts, u_int8_t obj_class, u_int8_t i1,
-			u_int8_t i2, u_int8_t i3, u_int8_t *attr, int att_len)
+			u_int8_t i2, u_int8_t i3, int nack, u_int8_t *attr, int att_len)
 {
 	struct abis_om_hdr *oh;
 	struct msgb *msg = nm_msgb_alloc();
+	u_int8_t msgtype = NM_MT_SW_ACT_REQ_ACK;
+	u_int8_t len = att_len;
+
+	if (nack) {
+		len += 2;
+		msgtype = NM_MT_SW_ACT_REQ_NACK;
+	}
 
 	oh = (struct abis_om_hdr *) msgb_put(msg, ABIS_OM_FOM_HDR_SIZE);
-	fill_om_fom_hdr(oh, att_len, NM_MT_SW_ACT_REQ_ACK, obj_class, i1, i2, i3);
-	/* FIXME: don't send ARFCN list, hopping sequence, mAIO, ...*/
+	fill_om_fom_hdr(oh, att_len, msgtype, obj_class, i1, i2, i3);
+
 	if (attr) {
 		u_int8_t *ptr = msgb_put(msg, att_len);
 		memcpy(ptr, attr, att_len);
 	}
+	if (nack)
+		msgb_tv_put(msg, NM_ATT_NACK_CAUSES, NM_NACK_OBJCLASS_NOTSUPP);
 
 	return abis_nm_sendmsg(bts, msg);
 }
@@ -1779,3 +1798,43 @@
 
 	return abis_nm_sendmsg(bts, msg);
 }
+
+/* ip.access nanoBTS specific commands */
+
+static const char ipaccess_magic[] = "com.ipaccess";
+
+int abis_nm_ipaccess_msg(struct gsm_bts *bts, u_int8_t msg_type,
+			 u_int8_t obj_class, u_int8_t bts_nr,
+			 u_int8_t trx_nr, u_int8_t ts_nr,
+			 u_int8_t *attr, int attr_len)
+{
+	struct msgb *msg = nm_msgb_alloc();
+	struct abis_om_hdr *oh;
+	struct abis_om_fom_hdr *foh;
+	u_int8_t *data;
+
+	/* construct the 12.21 OM header, observe the erroneous length */
+	oh = (struct abis_om_hdr *) msgb_put(msg, sizeof(*oh));
+	fill_om_hdr(oh, sizeof(*foh) + attr_len);
+	oh->mdisc = ABIS_OM_MDISC_MANUF;
+
+	/* add the ip.access magic */
+	data = msgb_put(msg, sizeof(ipaccess_magic)+1);
+	*data++ = sizeof(ipaccess_magic);
+	memcpy(data, ipaccess_magic, sizeof(ipaccess_magic));
+
+	/* fill the 12.21 FOM header */
+	foh = (struct abis_om_fom_hdr *) msgb_put(msg, sizeof(*foh));
+	foh->msg_type = msg_type;
+	foh->obj_class = obj_class;
+	foh->obj_inst.bts_nr = bts_nr;
+	foh->obj_inst.trx_nr = trx_nr;
+	foh->obj_inst.ts_nr = ts_nr;
+
+	if (attr && attr_len) {
+		data = msgb_put(msg, attr_len);
+		memcpy(data, attr, attr_len);
+	}
+
+	return abis_nm_sendmsg(bts, msg);
+}