bssgp: Free msgb in case of error when calling into gprs_ns_sendmsg

In the OsmoSGSN we have a crash with a DEAD/BLOCKED GPRS-NS and
segmented SN-UNITDATA. For the caller it is not easy to know if
the passed msg buffer has been freed or not. The most easy solution
is to always take the ownership and either pass it on or free it
in case of an error.

Adjust indirect and direct callers of gprs_ns_sendmsg. I found
the following call-chains with an external msgb parameter.

gprs_ns_sendmsg
  <- _bssgp_tx_dl_ud
     <- bssgp_fc_in
        <- bssgp_tx_dl_ud

Update the test to allocate a real msgb because for the test with
'1000' we will msgb_free it right away.

Sponsored-by: On-Waves ehf
diff --git a/src/gb/gprs_bssgp.c b/src/gb/gprs_bssgp.c
index 0e9fd38..7a5d628 100644
--- a/src/gb/gprs_bssgp.c
+++ b/src/gb/gprs_bssgp.c
@@ -696,6 +696,7 @@
 		LOGP(DBSSGP, LOGL_NOTICE, "Single PDU (size=%u) is larger "
 		     "than maximum bucket size (%u)!\n", llc_pdu_len,
 		     fc->bucket_size_max);
+		msgb_free(msg);
 		return -EIO;
 	}
 
@@ -1039,6 +1040,7 @@
 	if (bvci <= BVCI_PTM ) {
 		LOGP(DBSSGP, LOGL_ERROR, "Cannot send DL-UD to BVCI %u\n",
 			bvci);
+		msgb_free(msg);
 		return -EINVAL;
 	}
 
@@ -1046,6 +1048,7 @@
 	if (!bctx) {
 		LOGP(DBSSGP, LOGL_ERROR, "Cannot send DL-UD to unknown BVCI %u\n",
 			bvci);
+		msgb_free(msg);
 		return -ENODEV;
 	}
 
diff --git a/tests/gb/bssgp_fc_test.c b/tests/gb/bssgp_fc_test.c
index 64e4b4e..ad8f83d 100644
--- a/tests/gb/bssgp_fc_test.c
+++ b/tests/gb/bssgp_fc_test.c
@@ -43,18 +43,22 @@
 	unsigned int csecs = get_centisec_diff();
 	csecs = round_decisec(csecs);
 
-	printf("%u: FC OUT Nr %lu\n", csecs, (unsigned long) msg);
+	printf("%u: FC OUT Nr %lu\n", csecs, (unsigned long) msg->cb[0]);
+	msgb_free(msg);
 	return 0;
 }
 
 static int fc_in(struct bssgp_flow_control *fc, unsigned int pdu_len)
 {
+	struct msgb *msg;
 	unsigned int csecs = get_centisec_diff();
 	csecs = round_decisec(csecs);
 
-	printf("%u: FC IN Nr %lu\n", csecs, in_ctr);
-	bssgp_fc_in(fc, (struct msgb *) in_ctr, pdu_len, NULL);
-	in_ctr++;
+	msg = msgb_alloc(1, "fc test");
+	msg->cb[0] = in_ctr++;
+
+	printf("%u: FC IN Nr %lu\n", csecs, msg->cb[0]);
+	bssgp_fc_in(fc, msg, pdu_len, NULL);
 	return 0;
 }