bts: Add paging related tests

We're testing at 80% and 200% of PCH capacity, both for either IMSI-only
or TMSI-only paging requests.  The way how we test ensures:

* the expected number of paged mobile identities end up on the Um interface
* we implicitly check the queuing limit of 200 paging records by
  overflowing it in the 20-seconds-of-200%-load cases
* we implicitly check the batching of mobile identities into different
  paging types
* we test the PCH load reporting over RSL

As a side note, in case you were ever wondering what's the expected
paging throughput / capacity, there are now helper functions to compute
it.  For our combined CCCH/SDCCH4, it's about 16 IMSIs per second or
about 32 TMSIs per second.

Change-Id: I0b80b72bdab3d80d915296d70e1174623fbd8610
diff --git a/library/GSM_Types.ttcn b/library/GSM_Types.ttcn
index 634af34..5884c27 100644
--- a/library/GSM_Types.ttcn
+++ b/library/GSM_Types.ttcn
@@ -219,5 +219,33 @@
 	}
 }
 
+const float GSM_FRAME_DURATION := 0.12/26.0; /* 4.615 ms */
+const float GSM51_MFRAME_DURATION := 51.0 * GSM_FRAME_DURATION; /* 235.365 ms */
+const float GSM51_MFRAMES_PER_SEC := 1.0 / GSM51_MFRAME_DURATION; /* 4.248 */
+
+/* number of downlink CCCH blocks per second */
+function f_ccch_blocks_per_mframe(boolean combined_ccch) return integer {
+	if (not combined_ccch) {
+		/* 9 blocks per 51 multiframe */
+		return 9;
+	} else {
+		/* 3 blocks per 51 multiframe */
+		return 3;
+	}
+}
+
+/* this ignores any possible paging combining! */
+function f_pch_block_rate_est(boolean combined_ccch, integer bs_ag_blks_res) return float {
+	var integer ccch_per_mframe := f_ccch_blocks_per_mframe(combined_ccch);
+	var integer pch_per_mframe := ccch_per_mframe - bs_ag_blks_res;
+	return GSM51_MFRAMES_PER_SEC * int2float(pch_per_mframe);
+}
+
+/* this ignores any possible imm.ass combining! */
+function f_agch_block_rate_est(boolean combined_ccch, integer bs_ag_blks_res) return float {
+	var integer ccch_per_mframe := f_ccch_blocks_per_mframe(combined_ccch);
+	return GSM51_MFRAMES_PER_SEC * int2float(bs_ag_blks_res);
+}
+
 
 } with { encode "RAW"; variant "FIELDORDER(msb)" }
diff --git a/library/L1CTL_Types.ttcn b/library/L1CTL_Types.ttcn
index f9b4fe8..61d80cf 100644
--- a/library/L1CTL_Types.ttcn
+++ b/library/L1CTL_Types.ttcn
@@ -503,7 +503,8 @@
 
 	/* for matching against incoming DATA_IND */
 	template L1ctlDlMessage t_L1CTL_DATA_IND(template RslChannelNr chan_nr,
-						 template RslLinkId link_id := ?) := {
+						 template RslLinkId link_id := ?,
+						 template octetstring l2_data := ?) := {
 		header := t_L1ctlHeader(L1CTL_DATA_IND),
 		dl_info := {
 			chan_nr := chan_nr,
@@ -516,7 +517,9 @@
 			fire_crc := ?
 		},
 		payload := {
-			data_ind := ?
+			data_ind := {
+				payload := l2_data
+			}
 		}
 	};
 
@@ -538,4 +541,6 @@
 		}
 	};
 
+	const octetstring c_DummyUI := '0303012B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B'O;
+
 } with { encode "RAW" };
diff --git a/library/L3_Templates.ttcn b/library/L3_Templates.ttcn
index a614122..c2825a6 100644
--- a/library/L3_Templates.ttcn
+++ b/library/L3_Templates.ttcn
@@ -280,6 +280,74 @@
 	}
 }
 
+template PDU_ML3_NW_MS tr_PAGING_REQ1(template MobileIdentityLV mi1 := ?,
+				      template MobileIdentityTLV mi2 := *) := {
+	discriminator := '0110'B,
+	tiOrSkip := {
+		skipIndicator := '0000'B
+	},
+	msgs := {
+		rrm := {
+			pagingReq_Type1 := {
+				messageType := '00100001'B,
+				pageMode := ?,
+				channelNeeded := ?,
+				mobileIdentity1 := mi1,
+				mobileIdentity2 := mi2,
+				p1RestOctets := ?
+			}
+		}
+	}
+}
+
+template PDU_ML3_NW_MS tr_PAGING_REQ2(template TMSIP_TMSI_V mi1 := ?,
+				      template TMSIP_TMSI_V mi2 := ?,
+				      template MobileIdentityTLV mi3 := *) := {
+	discriminator := '0110'B,
+	tiOrSkip := {
+		skipIndicator := '0000'B
+	},
+	msgs := {
+		rrm := {
+			pagingReq_Type2 := {
+				messageType := '00100010'B,
+				pageMode := ?,
+				channelNeeded := ?,
+				mobileIdentity1 := mi1,
+				mobileIdentity2 := mi2,
+				mobileIdentity3 := mi3,
+				p2RestOctets := ?
+			}
+		}
+	}
+}
+
+template PDU_ML3_NW_MS tr_PAGING_REQ3(template TMSIP_TMSI_V mi1 := ?,
+				      template TMSIP_TMSI_V mi2 := ?,
+				      template TMSIP_TMSI_V mi3 := ?,
+				      template TMSIP_TMSI_V mi4 := ?) := {
+	discriminator := '0110'B,
+	tiOrSkip := {
+		skipIndicator := '0000'B
+	},
+	msgs := {
+		rrm := {
+			pagingReq_Type3 := {
+				messageType := '00100100'B,
+				pageMode := ?,
+				channelNeeded := ?,
+				mobileIdentity1 := mi1,
+				mobileIdentity2 := mi2,
+				mobileIdentity3 := mi3,
+				mobileIdentity4 := mi4,
+				p3RestOctets := ?
+			}
+		}
+	}
+}
+
+
+
 /* Send template for PAGING RESPONSE */
 template (value) PDU_ML3_MS_NW ts_PAG_RESP(MobileIdentityLV mi_lv) := {
 	discriminator := '0000'B, /* overwritten */
diff --git a/library/RSL_Types.ttcn b/library/RSL_Types.ttcn
index 8fb44ad..5366b31 100644
--- a/library/RSL_Types.ttcn
+++ b/library/RSL_Types.ttcn
@@ -392,6 +392,15 @@
 		access_count := acc
 	}
 
+	template RSL_IE_RachLoad tr_RSL_IE_RachLoad(template uint16_t slot,
+						    template uint16_t busy,
+						    template uint16_t acc) := {
+		len := ?, /* overwritten */
+		slot_count := slot,
+		busy_count := busy,
+		access_count := acc
+	}
+
 	/* 9.3.19 */
 	type record RSL_IE_RequestRef {
 		OCT1		ra,
@@ -1149,6 +1158,17 @@
 			t_RSL_IE(RSL_IE_RACH_LOAD, RSL_IE_Body:{rach_load := ts_RSL_IE_RachLoad(slot_ct, busy_ct, acc_ct)})
 		}
 	}
+	template RSL_Message tr_RSL_RACH_LOAD_IND(template uint16_t slot_ct := ?,
+						  template uint16_t busy_ct := ?,
+						  template uint16_t acc_ct) := {
+		msg_disc := ts_RSL_MsgDisc(RSL_MDISC_CCHAN, false),
+		msg_type := RSL_MT_CCCH_LOAD_IND,
+		ies := {
+			tr_RSL_IE(RSL_IE_Body:{chan_nr := t_RslChanNr_RACH(0)}),
+			tr_RSL_IE(RSL_IE_Body:{rach_load := tr_RSL_IE_RachLoad(slot_ct, busy_ct, acc_ct)})
+		}
+	}
+
 	template RSL_Message ts_RSL_PAGING_LOAD_IND(uint16_t buffer_space) := {
 		msg_disc := ts_RSL_MsgDisc(RSL_MDISC_CCHAN, false),
 		msg_type := RSL_MT_CCCH_LOAD_IND,
@@ -1157,6 +1177,15 @@
 			t_RSL_IE(RSL_IE_PAGING_LOAD, RSL_IE_Body:{paging_load := buffer_space})
 		}
 	}
+	template RSL_Message tr_RSL_PAGING_LOAD_IND(template uint16_t buffer_space := ?) := {
+		msg_disc := ts_RSL_MsgDisc(RSL_MDISC_CCHAN, false),
+		msg_type := RSL_MT_CCCH_LOAD_IND,
+		ies := {
+			tr_RSL_IE(RSL_IE_Body:{chan_nr := t_RslChanNr_PCH_AGCH(0)}),
+			tr_RSL_IE(RSL_IE_Body:{paging_load := buffer_space})
+		}
+	}
+
 
 	/* 8.5.3 BTS -> BSC */
 	template RSL_Message ts_RSL_CHAN_RQD(OCT1 ra, GsmFrameNumber fn, uint8_t acc_del := 0) := {
@@ -1228,6 +1257,22 @@
 		}
 	}
 
+	template RSL_Message tr_RSL_RF_RES_IND := {
+		msg_disc := ts_RSL_MsgDisc(RSL_MDISC_TRX_MGMT, false),
+		msg_type := RSL_MT_RF_RES_IND,
+		ies := *
+	}
+
+	/* 8.6.2 BTS <- BSC */
+	template RSL_Message ts_RSL_SACCH_FILL(RSL_IE_SysinfoType si_type, octetstring l3_info) := {
+		msg_disc := ts_RSL_MsgDisc(RSL_MDISC_TRX_MGMT, false),
+		msg_type := RSL_MT_SACCH_FILL,
+		ies := {
+			t_RSL_IE(RSL_IE_SYSINFO_TYPE, RSL_IE_Body:{sysinfo_type := si_type}),
+			t_RSL_IE(RSL_IE_L3_INFO, RSL_IE_Body:{l3_info := ts_RSL_L16V(l3_info)})
+		}
+	}
+
 	/* 8.6.4 BTS -> BSC */
 	template RSL_Message ts_RSL_ERROR_REPORT(RSL_Cause cause) := {
 		msg_disc := ts_RSL_MsgDisc(RSL_MDISC_CCHAN, false),