Expand BSSGP helpers + codec to cover expansion + compaction
diff --git a/gprs_gb/NS_Types.ttcn b/gprs_gb/NS_Types.ttcn
new file mode 100644
index 0000000..ee2444d
--- /dev/null
+++ b/gprs_gb/NS_Types.ttcn
@@ -0,0 +1,103 @@
+module NS_Types {
+	import from General_Types all;
+	import from Osmocom_Types all;
+	import from GSM_Types all;
+	import from BSSGP_Types all;
+
+	/* TS 48.016 10.3.7 */
+	type enumerated NsPduType {
+		NS_PDUT_NS_UNITDATA	('00000000'B),
+		NS_PDUT_NS_RESET	('00000010'B),
+		NS_PDUT_NS_RESET_ACK	('00000011'B),
+		NS_PDUT_NS_BLOCK	('00000100'B),
+		NS_PDUT_NS_BLOCK_ACK	('00000101'B),
+		NS_PDUT_NS_UNBLOCK	('00000110'B),
+		NS_PDUT_NS_UNBLOCK_ACK	('00000111'B),
+		NS_PDUT_NS_STATUS	('00001000'B),
+		NS_PDUT_NS_ALIVE	('00001010'B),
+		NS_PDUT_NS_ALIVE_ACK	('00001011'B)
+		/* FIXME: SNS */
+	} with { variant "FIELDLENGTH(8)" };
+
+	/* TS 48.016 10.3 */
+	type enumerated NsIEI {
+		NS_IEI_CAUSE		('00000000'B),
+		NS_IEI_NSVCI		('00000001'B),
+		NS_IEI_NS_PDU		('00000010'B),
+		NS_IEI_BVCI		('00000011'B),
+		NS_IEI_NSEI		('00000100'B),
+		NS_IEI_LIST_IPv4	('00000101'B),
+		NS_IEI_LIST_IPv6	('00000110'B),
+		NS_IEI_MAX_NUM_NSVC	('00000111'B),
+		NS_IEI_NUM_IPv4_EP	('00001000'B),
+		NS_IEI_NUM_IPv6_EP	('00001001'B),
+		NS_IEI_RESET_FLAG	('00001010'B),
+		NS_IEI_IP_ADDRESS	('00001011'B)
+	} with { variant "FIELDLENGTH(8)" };
+
+	/* TS 48.016 10.3.2 */
+	type enumerated NsCause {
+		NS_CAUSE_TRANSIT_NETWORK_FAILURE		('00000000'B),
+		NS_CAUSE_OM_INTERVENTION			('00000001'B),
+		NS_CAUSE_EQUIPMENT_FAILURE			('00000010'B),
+		NS_CAUSE_NSVC_BLOCKED				('00000011'B),
+		NS_CAUSE_NSVC_UNKNOWN				('00000100'B),
+		NS_CAUSE_BVCI_UNKNOWN_AT_NSE			('00000101'B),
+		NS_CAUSE_SEMANTICALLY_INCORRECT_PDU		('00001000'B),
+		NS_CAUSE_PDU_NOT_COMPATIBLE_WITH_PROTOCOL_STATE	('00001010'B),
+		NS_CAUSE_PROTOCOL_ERROR_UNSPEIFIED		('00001011'B),
+		NS_CAUSE_INVALID_ESSENTIAL_IE			('00001100'B),
+		NS_CAUSE_MISSING_ESSENTIAL_IE			('00001101'B),
+		NS_CAUSE_INVALID_NR_OF_IPv4_ENDPOINTS		('00001110'B),
+		NS_CAUSE_INVALID_NR_OF_IPv6_ENDPOINTS		('00001111'B),
+		NS_CAUSE_INVALID_NR_OF_NSVCS			('00010000'B),
+		NS_CAUSE_INVALID_WEIGHTS			('00010001'B),
+		NS_CAUSE_UNKNOWN_IP_ENDPOINT			('00010010'B),
+		NS_CAUSE_UNKNOWN_IP_ADDRESS			('00010011'B),
+		NS_CAUSE_IP_TEST_FAILEDA			('00010100'B)
+	} with { variant "FIELDLENGTH(8)" };
+
+	type uint16_t Nsvci;
+	type uint16_t Nsei;
+
+	type union NsIeUnion {
+		BssgpBvci		bvci,		/* 10.3.1 */
+		NsCause			cause,		/* 10.3.2 */
+		uint16_t		max_num_nsvc,	/* 10.3.2e */
+		uint16_t		num_ipv4_ep,	/* 10.3.2f */
+		uint16_t		num_ipv6_ep,	/* 10.3.2g */
+		Nsvci			nsvci,		/* 10.3.5 */
+		Nsei			nsei,		/* 10.3.6 */
+		octetstring 		other
+	};
+
+	type record NsTLV {
+		NsIEI		iei,
+		uint16_t	len,
+		NsIeUnion	u
+	} with {
+		variant (u) "CROSSTAG(
+				bvci, 			iei = NS_IEI_BVCI;
+				cause,			iei = NS_IEI_CAUSE;
+				max_num_nsvc,		iei = NS_IEI_MAX_NUM_NSVC;
+				num_ipv4_ep,		iei = NS_IEI_NUM_IPv4_EP;
+				num_ipv6_ep,		iei = NS_IEI_NUM_IPv6_EP;
+				nsvci,			iei = NS_IEI_NSVCI;
+				nsei,			iei = NS_IEI_NSEI;
+				other,			OTHERWISE)"
+		variant (len) "LENGTHTO(u)"
+	};
+
+	type record of NsTLV NsTLVs;
+
+	type record NsPdu {
+		NsPduType	pdu_type,
+		NsTLVs		tlvs optional
+	} with { variant "" };
+
+	external function enc_NsPdu(in NsPdu pdu) return octetstring
+		with { extension "prototype(convert) encode(RAW)" };
+	external function dec_NsPdu(in octetstring stream) return NsPdu
+		with { extension "prototype(convert) decode(RAW)" };
+
+} with { encode "RAW" };