mirror of
				https://gitea.osmocom.org/cellular-infrastructure/osmo-pcu.git
				synced 2025-11-04 06:03:30 +00:00 
			
		
		
		
	Compare commits
	
		
			19 Commits
		
	
	
		
			pespin/mas
			...
			jerlbeck/w
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					407851b865 | ||
| 
						 | 
					196ddc58a4 | ||
| 
						 | 
					77a23a7de4 | ||
| 
						 | 
					e75e76defe | ||
| 
						 | 
					67728acc7a | ||
| 
						 | 
					967e4dd2c3 | ||
| 
						 | 
					0a96390122 | ||
| 
						 | 
					155cf8442a | ||
| 
						 | 
					bd8c689ed4 | ||
| 
						 | 
					618babae12 | ||
| 
						 | 
					2f7228b15f | ||
| 
						 | 
					e61b652e1b | ||
| 
						 | 
					53a32b8e95 | ||
| 
						 | 
					6634635cf5 | ||
| 
						 | 
					5823b20f2f | ||
| 
						 | 
					6659c516fa | ||
| 
						 | 
					54fff3b3e4 | ||
| 
						 | 
					3bea905e0d | ||
| 
						 | 
					4ff709c3ac | 
							
								
								
									
										98
									
								
								src/bts.cpp
									
									
									
									
									
								
							
							
						
						
									
										98
									
								
								src/bts.cpp
									
									
									
									
									
								
							@@ -522,6 +522,17 @@ void BTS::snd_dl_ass(gprs_rlcmac_tbf *tbf, uint8_t poll, const char *imsi)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GprsMs *BTS::ms_alloc(uint8_t ms_class)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GprsMs *ms;
 | 
				
			||||||
 | 
						ms = ms_store().create_ms();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ms->set_timeout(m_bts.ms_idle_sec);
 | 
				
			||||||
 | 
						ms->set_ms_class(ms_class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ms;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * PDCH code below. TODO: move to a separate file
 | 
					 * PDCH code below. TODO: move to a separate file
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -657,7 +668,8 @@ void gprs_rlcmac_pdch::add_paging(struct gprs_rlcmac_paging *pag)
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 * The blocks are defragmented and forwarded as LLC frames, if complete.
 | 
					 * The blocks are defragmented and forwarded as LLC frames, if complete.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int gprs_rlcmac_pdch::rcv_data_block_acknowledged(uint8_t *data, uint8_t len, int8_t rssi)
 | 
					int gprs_rlcmac_pdch::rcv_data_block_acknowledged(uint8_t *data, uint8_t len,
 | 
				
			||||||
 | 
						struct pcu_l1_meas *meas)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gprs_rlcmac_ul_tbf *tbf;
 | 
						struct gprs_rlcmac_ul_tbf *tbf;
 | 
				
			||||||
	struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
 | 
						struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
 | 
				
			||||||
@@ -692,7 +704,7 @@ int gprs_rlcmac_pdch::rcv_data_block_acknowledged(uint8_t *data, uint8_t len, in
 | 
				
			|||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return tbf->rcv_data_block_acknowledged(data, len, rssi);
 | 
						return tbf->rcv_data_block_acknowledged(data, len, meas);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, uint32_t fn)
 | 
					void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet, uint32_t fn)
 | 
				
			||||||
@@ -711,7 +723,6 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
 | 
				
			|||||||
			fn, tlli, trx_no(), ts_no);
 | 
								fn, tlli, trx_no(), ts_no);
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	tbf->update_tlli(tlli);
 | 
					 | 
				
			||||||
	tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF);
 | 
						tbf->update_ms(tlli, GPRS_RLCMAC_UL_TBF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] %s Packet Control Ack\n", tbf_name(tbf));
 | 
						LOGP(DRLCMAC, LOGL_DEBUG, "RX: [PCU <- BTS] %s Packet Control Ack\n", tbf_name(tbf));
 | 
				
			||||||
@@ -789,11 +800,70 @@ void gprs_rlcmac_pdch::rcv_control_ack(Packet_Control_Acknowledgement_t *packet,
 | 
				
			|||||||
		"at no request\n");
 | 
							"at no request\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void get_rx_qual_meas(struct pcu_l1_meas *meas, uint8_t rx_qual_enc)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						static const int16_t rx_qual_map[] = {
 | 
				
			||||||
 | 
							0, /* 0,14 % */
 | 
				
			||||||
 | 
							0, /* 0,28 % */
 | 
				
			||||||
 | 
							1, /* 0,57 % */
 | 
				
			||||||
 | 
							1, /* 1,13 % */
 | 
				
			||||||
 | 
							2, /* 2,26 % */
 | 
				
			||||||
 | 
							5, /* 4,53 % */
 | 
				
			||||||
 | 
							9, /* 9,05 % */
 | 
				
			||||||
 | 
							18, /* 18,10 % */
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						meas->set_ms_rx_qual(rx_qual_map[
 | 
				
			||||||
 | 
							OSMO_MIN(rx_qual_enc, ARRAY_SIZE(rx_qual_map)-1)
 | 
				
			||||||
 | 
							]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void get_meas(struct pcu_l1_meas *meas,
 | 
				
			||||||
 | 
						const Packet_Resource_Request_t *qr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						meas->set_ms_c_value(qr->C_VALUE);
 | 
				
			||||||
 | 
						if (qr->Exist_SIGN_VAR)
 | 
				
			||||||
 | 
							meas->set_ms_sign_var((qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->Slot), ARRAY_SIZE(meas->ts)); i++)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (qr->Slot[i].Exist) {
 | 
				
			||||||
 | 
								LOGP(DRLCMAC, LOGL_INFO,
 | 
				
			||||||
 | 
									"Packet resource request: i_level[%d] = %d\n",
 | 
				
			||||||
 | 
									i, qr->Slot[i].I_LEVEL);
 | 
				
			||||||
 | 
								meas->set_ms_i_level(i, -2 * qr->Slot[i].I_LEVEL);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void get_meas(struct pcu_l1_meas *meas,
 | 
				
			||||||
 | 
						const Channel_Quality_Report_t *qr)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						get_rx_qual_meas(meas, qr->RXQUAL);
 | 
				
			||||||
 | 
						meas->set_ms_c_value(qr->C_VALUE);
 | 
				
			||||||
 | 
						meas->set_ms_sign_var((qr->SIGN_VAR + 2) / 4); /* SIGN_VAR * 0.25 dB */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < OSMO_MIN(ARRAY_SIZE(qr->Slot), ARRAY_SIZE(meas->ts)); i++)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (qr->Slot[i].Exist) {
 | 
				
			||||||
 | 
								LOGP(DRLCMAC, LOGL_INFO,
 | 
				
			||||||
 | 
									"Channel quality report: i_level[%d] = %d\n",
 | 
				
			||||||
 | 
									i, qr->Slot[i].I_LEVEL_TN);
 | 
				
			||||||
 | 
								meas->set_ms_i_level(i, -2 * qr->Slot[i].I_LEVEL_TN);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_nack, uint32_t fn)
 | 
					void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_nack, uint32_t fn)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int8_t tfi = 0; /* must be signed */
 | 
						int8_t tfi = 0; /* must be signed */
 | 
				
			||||||
	struct gprs_rlcmac_dl_tbf *tbf;
 | 
						struct gprs_rlcmac_dl_tbf *tbf;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
						struct pcu_l1_meas meas;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tfi = ack_nack->DOWNLINK_TFI;
 | 
						tfi = ack_nack->DOWNLINK_TFI;
 | 
				
			||||||
	tbf = bts()->dl_tbf_by_poll_fn(fn, trx_no(), ts_no);
 | 
						tbf = bts()->dl_tbf_by_poll_fn(fn, trx_no(), ts_no);
 | 
				
			||||||
@@ -835,11 +905,16 @@ void gprs_rlcmac_pdch::rcv_control_dl_ack_nack(Packet_Downlink_Ack_Nack_t *ack_n
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		/* This call will register the new TBF with the MS on success */
 | 
							/* This call will register the new TBF with the MS on success */
 | 
				
			||||||
		tbf_alloc_ul(bts_data(), tbf->trx->trx_no, tbf->ms_class(),
 | 
							tbf_alloc_ul(bts_data(), tbf->trx->trx_no, tbf->ms_class(),
 | 
				
			||||||
			tbf->tlli(), tbf->ta(), tbf);
 | 
								tbf->tlli(), tbf->ta(), tbf->ms());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* schedule uplink assignment */
 | 
							/* schedule uplink assignment */
 | 
				
			||||||
		tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
 | 
							tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						/* get measurements */
 | 
				
			||||||
 | 
						if (tbf->ms()) {
 | 
				
			||||||
 | 
							get_meas(&meas, &ack_nack->Channel_Quality_Report);
 | 
				
			||||||
 | 
							tbf->ms()->update_l1_meas(&meas);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, uint32_t fn)
 | 
					void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request, uint32_t fn)
 | 
				
			||||||
@@ -852,6 +927,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
 | 
				
			|||||||
		uint32_t tlli = request->ID.u.TLLI;
 | 
							uint32_t tlli = request->ID.u.TLLI;
 | 
				
			||||||
		uint8_t ms_class = 0;
 | 
							uint8_t ms_class = 0;
 | 
				
			||||||
		uint8_t ta = 0;
 | 
							uint8_t ta = 0;
 | 
				
			||||||
 | 
							struct pcu_l1_meas meas;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		GprsMs *ms = bts()->ms_by_tlli(tlli);
 | 
							GprsMs *ms = bts()->ms_by_tlli(tlli);
 | 
				
			||||||
		/* Keep the ms, even if it gets idle temporarily */
 | 
							/* Keep the ms, even if it gets idle temporarily */
 | 
				
			||||||
@@ -897,7 +973,7 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
 | 
				
			|||||||
			ms_class = Decoding::get_ms_class_by_capability(&request->MS_Radio_Access_capability);
 | 
								ms_class = Decoding::get_ms_class_by_capability(&request->MS_Radio_Access_capability);
 | 
				
			||||||
		if (!ms_class)
 | 
							if (!ms_class)
 | 
				
			||||||
			LOGP(DRLCMAC, LOGL_NOTICE, "MS does not give us a class.\n");
 | 
								LOGP(DRLCMAC, LOGL_NOTICE, "MS does not give us a class.\n");
 | 
				
			||||||
		ul_tbf = tbf_alloc_ul(bts_data(), trx_no(), ms_class, tlli, ta, NULL);
 | 
							ul_tbf = tbf_alloc_ul(bts_data(), trx_no(), ms_class, tlli, ta, ms);
 | 
				
			||||||
		if (!ul_tbf)
 | 
							if (!ul_tbf)
 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -906,6 +982,12 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
 | 
				
			|||||||
		ul_tbf->control_ts = ts_no;
 | 
							ul_tbf->control_ts = ts_no;
 | 
				
			||||||
		/* schedule uplink assignment */
 | 
							/* schedule uplink assignment */
 | 
				
			||||||
		ul_tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
 | 
							ul_tbf->ul_ass_state = GPRS_RLCMAC_UL_ASS_SEND_ASS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* get measurements */
 | 
				
			||||||
 | 
							if (ul_tbf->ms()) {
 | 
				
			||||||
 | 
								get_meas(&meas, request);
 | 
				
			||||||
 | 
								ul_tbf->ms()->update_l1_meas(&meas);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -932,7 +1014,6 @@ void gprs_rlcmac_pdch::rcv_resource_request(Packet_Resource_Request_t *request,
 | 
				
			|||||||
			"RX: [PCU <- BTS] %s FIXME: Packet resource request\n",
 | 
								"RX: [PCU <- BTS] %s FIXME: Packet resource request\n",
 | 
				
			||||||
			tbf_name(ul_tbf));
 | 
								tbf_name(ul_tbf));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gprs_rlcmac_pdch::rcv_measurement_report(Packet_Measurement_Report_t *report, uint32_t fn)
 | 
					void gprs_rlcmac_pdch::rcv_measurement_report(Packet_Measurement_Report_t *report, uint32_t fn)
 | 
				
			||||||
@@ -995,7 +1076,8 @@ int gprs_rlcmac_pdch::rcv_control_block(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* received RLC/MAC block from L1 */
 | 
					/* received RLC/MAC block from L1 */
 | 
				
			||||||
int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn, int8_t rssi)
 | 
					int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn,
 | 
				
			||||||
 | 
						struct pcu_l1_meas *meas)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned payload = data[0] >> 6;
 | 
						unsigned payload = data[0] >> 6;
 | 
				
			||||||
	bitvec *block;
 | 
						bitvec *block;
 | 
				
			||||||
@@ -1003,7 +1085,7 @@ int gprs_rlcmac_pdch::rcv_block(uint8_t *data, uint8_t len, uint32_t fn, int8_t
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	switch (payload) {
 | 
						switch (payload) {
 | 
				
			||||||
	case GPRS_RLCMAC_DATA_BLOCK:
 | 
						case GPRS_RLCMAC_DATA_BLOCK:
 | 
				
			||||||
		rc = rcv_data_block_acknowledged(data, len, rssi);
 | 
							rc = rcv_data_block_acknowledged(data, len, meas);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case GPRS_RLCMAC_CONTROL_BLOCK:
 | 
						case GPRS_RLCMAC_CONTROL_BLOCK:
 | 
				
			||||||
		block = bitvec_alloc(len);
 | 
							block = bitvec_alloc(len);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								src/bts.h
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/bts.h
									
									
									
									
									
								
							@@ -37,6 +37,7 @@ extern "C" {
 | 
				
			|||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct BTS;
 | 
					struct BTS;
 | 
				
			||||||
 | 
					struct GprsMs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * PDCH instance
 | 
					 * PDCH instance
 | 
				
			||||||
@@ -56,7 +57,8 @@ struct gprs_rlcmac_pdch {
 | 
				
			|||||||
	void disable();
 | 
						void disable();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* dispatching of messages */
 | 
						/* dispatching of messages */
 | 
				
			||||||
	int rcv_block(uint8_t *data, uint8_t len, uint32_t fn, int8_t rssi);
 | 
						int rcv_block(uint8_t *data, uint8_t len, uint32_t fn,
 | 
				
			||||||
 | 
							struct pcu_l1_meas *meas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gprs_rlcmac_bts *bts_data() const;
 | 
						gprs_rlcmac_bts *bts_data() const;
 | 
				
			||||||
	BTS *bts() const;
 | 
						BTS *bts() const;
 | 
				
			||||||
@@ -80,7 +82,8 @@ struct gprs_rlcmac_pdch {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	int rcv_data_block_acknowledged(uint8_t *data, uint8_t len, int8_t rssi);
 | 
						int rcv_data_block_acknowledged(uint8_t *data, uint8_t len,
 | 
				
			||||||
 | 
							struct pcu_l1_meas *meas);
 | 
				
			||||||
	int rcv_control_block(bitvec *rlc_block, uint32_t fn);
 | 
						int rcv_control_block(bitvec *rlc_block, uint32_t fn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void rcv_control_ack(Packet_Control_Acknowledgement_t *, uint32_t fn);
 | 
						void rcv_control_ack(Packet_Control_Acknowledgement_t *, uint32_t fn);
 | 
				
			||||||
@@ -136,7 +139,7 @@ struct gprs_rlcmac_bts {
 | 
				
			|||||||
	uint8_t n3105;
 | 
						uint8_t n3105;
 | 
				
			||||||
	struct gprs_rlcmac_trx trx[8];
 | 
						struct gprs_rlcmac_trx trx[8];
 | 
				
			||||||
	int (*alloc_algorithm)(struct gprs_rlcmac_bts *bts,
 | 
						int (*alloc_algorithm)(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
		struct gprs_rlcmac_tbf *old_tbf,
 | 
							struct GprsMs *ms,
 | 
				
			||||||
		struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
 | 
							struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
 | 
				
			||||||
	uint32_t alloc_algorithm_curst; /* options to customize algorithm */
 | 
						uint32_t alloc_algorithm_curst; /* options to customize algorithm */
 | 
				
			||||||
	uint8_t force_two_phase;
 | 
						uint8_t force_two_phase;
 | 
				
			||||||
@@ -146,6 +149,8 @@ struct gprs_rlcmac_bts {
 | 
				
			|||||||
	uint8_t cs_adj_enabled;
 | 
						uint8_t cs_adj_enabled;
 | 
				
			||||||
	uint8_t cs_adj_upper_limit;
 | 
						uint8_t cs_adj_upper_limit;
 | 
				
			||||||
	uint8_t cs_adj_lower_limit;
 | 
						uint8_t cs_adj_lower_limit;
 | 
				
			||||||
 | 
						struct {int16_t low; int16_t high;} cs_lqual_ranges[4];
 | 
				
			||||||
 | 
						uint16_t cs_downgrade_threshold; /* downgrade if less packets left (DL) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TBF handling, make private or move into TBFController */
 | 
						/* TBF handling, make private or move into TBFController */
 | 
				
			||||||
	/* list of uplink TBFs */
 | 
						/* list of uplink TBFs */
 | 
				
			||||||
@@ -224,6 +229,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	GprsMsStorage &ms_store();
 | 
						GprsMsStorage &ms_store();
 | 
				
			||||||
	GprsMs *ms_by_tlli(uint32_t tlli, uint32_t old_tlli = 0);
 | 
						GprsMs *ms_by_tlli(uint32_t tlli, uint32_t old_tlli = 0);
 | 
				
			||||||
 | 
						GprsMs *ms_alloc(uint8_t ms_class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Statistics
 | 
						 * Statistics
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -804,8 +804,8 @@ struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void)
 | 
				
			|||||||
	return the_pcu.bctx;
 | 
						return the_pcu.bctx;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gprs_bssgp_update_queue_delay(struct timeval *tv_recv,
 | 
					void gprs_bssgp_update_queue_delay(const struct timeval *tv_recv,
 | 
				
			||||||
	struct timeval *tv_now)
 | 
						const struct timeval *tv_now)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct timeval *delay_sum = &the_pcu.queue_delay_sum;
 | 
						struct timeval *delay_sum = &the_pcu.queue_delay_sum;
 | 
				
			||||||
	struct timeval tv_delay;
 | 
						struct timeval tv_delay;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -83,7 +83,7 @@ void gprs_bssgp_destroy(void);
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void);
 | 
					struct bssgp_bvc_ctx *gprs_bssgp_pcu_current_bctx(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gprs_bssgp_update_queue_delay(struct timeval *tv_recv,
 | 
					void gprs_bssgp_update_queue_delay(const struct timeval *tv_recv,
 | 
				
			||||||
		struct timeval *tv_now);
 | 
							const struct timeval *tv_now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // GPRS_BSSGP_PCU_H
 | 
					#endif // GPRS_BSSGP_PCU_H
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										117
									
								
								src/gprs_ms.cpp
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								src/gprs_ms.cpp
									
									
									
									
									
								
							@@ -90,7 +90,8 @@ GprsMs::GprsMs(BTS *bts, uint32_t tlli) :
 | 
				
			|||||||
	m_is_idle(true),
 | 
						m_is_idle(true),
 | 
				
			||||||
	m_ref(0),
 | 
						m_ref(0),
 | 
				
			||||||
	m_list(this),
 | 
						m_list(this),
 | 
				
			||||||
	m_delay(0)
 | 
						m_delay(0),
 | 
				
			||||||
 | 
						m_nack_rate_dl(0)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
 | 
						LOGP(DRLCMAC, LOGL_INFO, "Creating MS object, TLLI = 0x%08x\n", tlli);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -239,7 +240,7 @@ void GprsMs::detach_tbf(gprs_rlcmac_tbf *tbf)
 | 
				
			|||||||
	if (tbf->ms() == this)
 | 
						if (tbf->ms() == this)
 | 
				
			||||||
		tbf->set_ms(NULL);
 | 
							tbf->set_ms(NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!m_dl_tbf && !m_ul_tbf)
 | 
						if (!m_dl_tbf && !m_ul_tbf && tlli() != 0)
 | 
				
			||||||
		start_timer();
 | 
							start_timer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	update_status();
 | 
						update_status();
 | 
				
			||||||
@@ -367,7 +368,7 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	struct gprs_rlcmac_bts *bts_data;
 | 
						struct gprs_rlcmac_bts *bts_data;
 | 
				
			||||||
	int64_t now;
 | 
						int64_t now;
 | 
				
			||||||
	uint8_t max_cs_ul = 4, max_cs_dl = 4;
 | 
						uint8_t max_cs_dl = 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(m_bts != NULL);
 | 
						OSMO_ASSERT(m_bts != NULL);
 | 
				
			||||||
	bts_data = m_bts->bts_data();
 | 
						bts_data = m_bts->bts_data();
 | 
				
			||||||
@@ -377,18 +378,17 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	now = now_msec();
 | 
						now = now_msec();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bts_data->max_cs_ul)
 | 
					 | 
				
			||||||
		max_cs_ul = bts_data->max_cs_ul;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (bts_data->max_cs_dl)
 | 
						if (bts_data->max_cs_dl)
 | 
				
			||||||
		max_cs_dl = bts_data->max_cs_dl;
 | 
							max_cs_dl = bts_data->max_cs_dl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TODO: Check for TBF direction */
 | 
				
			||||||
	/* TODO: Support different CS values for UL and DL */
 | 
						/* TODO: Support different CS values for UL and DL */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m_nack_rate_dl = error_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (error_rate > bts_data->cs_adj_upper_limit) {
 | 
						if (error_rate > bts_data->cs_adj_upper_limit) {
 | 
				
			||||||
		if (m_current_cs_dl > 1) {
 | 
							if (m_current_cs_dl > 1) {
 | 
				
			||||||
			m_current_cs_dl -= 1;
 | 
								m_current_cs_dl -= 1;
 | 
				
			||||||
			m_current_cs_ul = m_current_cs_dl;
 | 
					 | 
				
			||||||
			LOGP(DRLCMACDL, LOGL_INFO,
 | 
								LOGP(DRLCMACDL, LOGL_INFO,
 | 
				
			||||||
				"MS (IMSI %s): High error rate %d%%, "
 | 
									"MS (IMSI %s): High error rate %d%%, "
 | 
				
			||||||
				"reducing CS level to %d\n",
 | 
									"reducing CS level to %d\n",
 | 
				
			||||||
@@ -399,12 +399,10 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
 | 
				
			|||||||
		if (m_current_cs_dl < max_cs_dl) {
 | 
							if (m_current_cs_dl < max_cs_dl) {
 | 
				
			||||||
		       if (now - m_last_cs_not_low > 1000) {
 | 
							       if (now - m_last_cs_not_low > 1000) {
 | 
				
			||||||
			       m_current_cs_dl += 1;
 | 
								       m_current_cs_dl += 1;
 | 
				
			||||||
			       if (m_current_cs_dl <= max_cs_ul)
 | 
					 | 
				
			||||||
				       m_current_cs_ul = m_current_cs_dl;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			       LOGP(DRLCMACDL, LOGL_INFO,
 | 
								       LOGP(DRLCMACDL, LOGL_INFO,
 | 
				
			||||||
				       "MS (IMSI %s): Low error rate %d%%, "
 | 
									       "MS (IMSI %s): Low error rate %d%%, "
 | 
				
			||||||
				       "increasing CS level to %d\n",
 | 
									       "increasing DL CS level to %d\n",
 | 
				
			||||||
				       imsi(), error_rate, m_current_cs_dl);
 | 
									       imsi(), error_rate, m_current_cs_dl);
 | 
				
			||||||
			       m_last_cs_not_low = now;
 | 
								       m_last_cs_not_low = now;
 | 
				
			||||||
		       } else {
 | 
							       } else {
 | 
				
			||||||
@@ -421,3 +419,102 @@ void GprsMs::update_error_rate(gprs_rlcmac_tbf *tbf, int error_rate)
 | 
				
			|||||||
		m_last_cs_not_low = now;
 | 
							m_last_cs_not_low = now;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void GprsMs::update_l1_meas(const pcu_l1_meas *meas)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gprs_rlcmac_bts *bts_data;
 | 
				
			||||||
 | 
						uint8_t max_cs_ul = 4;
 | 
				
			||||||
 | 
						unsigned i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(m_bts != NULL);
 | 
				
			||||||
 | 
						bts_data = m_bts->bts_data();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bts_data->max_cs_ul)
 | 
				
			||||||
 | 
							max_cs_ul = bts_data->max_cs_ul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (meas->have_link_qual) {
 | 
				
			||||||
 | 
							int old_link_qual = meas->link_qual;
 | 
				
			||||||
 | 
							int low  = bts_data->cs_lqual_ranges[current_cs_ul()-1].low;
 | 
				
			||||||
 | 
							int high  = bts_data->cs_lqual_ranges[current_cs_ul()-1].high;
 | 
				
			||||||
 | 
							uint8_t new_cs_ul = m_current_cs_ul;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (m_l1_meas.have_link_qual)
 | 
				
			||||||
 | 
							       old_link_qual = m_l1_meas.link_qual;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (meas->link_qual < low &&  old_link_qual < low)
 | 
				
			||||||
 | 
								new_cs_ul = m_current_cs_ul - 1;
 | 
				
			||||||
 | 
							else if (meas->link_qual > high &&  old_link_qual > high &&
 | 
				
			||||||
 | 
								m_current_cs_ul < max_cs_ul)
 | 
				
			||||||
 | 
								new_cs_ul = m_current_cs_ul + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (m_current_cs_ul != new_cs_ul) {
 | 
				
			||||||
 | 
								LOGP(DRLCMACDL, LOGL_INFO,
 | 
				
			||||||
 | 
									"MS (IMSI %s): "
 | 
				
			||||||
 | 
									"Link quality %ddB (%ddB) left window [%d, %d], "
 | 
				
			||||||
 | 
									"modifying uplink CS level: %d -> %d\n",
 | 
				
			||||||
 | 
									imsi(), meas->link_qual, old_link_qual,
 | 
				
			||||||
 | 
									low, high,
 | 
				
			||||||
 | 
									m_current_cs_ul, new_cs_ul);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								m_current_cs_ul = new_cs_ul;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (meas->have_rssi)
 | 
				
			||||||
 | 
							m_l1_meas.set_rssi(meas->rssi);
 | 
				
			||||||
 | 
						if (meas->have_bto)
 | 
				
			||||||
 | 
							m_l1_meas.set_bto(meas->bto);
 | 
				
			||||||
 | 
						if (meas->have_ber)
 | 
				
			||||||
 | 
							m_l1_meas.set_ber(meas->ber);
 | 
				
			||||||
 | 
						if (meas->have_link_qual)
 | 
				
			||||||
 | 
							m_l1_meas.set_link_qual(meas->link_qual);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (meas->have_ms_rx_qual)
 | 
				
			||||||
 | 
							m_l1_meas.set_ms_rx_qual(meas->ms_rx_qual);
 | 
				
			||||||
 | 
						if (meas->have_ms_c_value)
 | 
				
			||||||
 | 
							m_l1_meas.set_ms_c_value(meas->ms_c_value);
 | 
				
			||||||
 | 
						if (meas->have_ms_sign_var)
 | 
				
			||||||
 | 
							m_l1_meas.set_ms_sign_var(meas->ms_sign_var);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (meas->have_ms_i_level) {
 | 
				
			||||||
 | 
							for (i = 0; i < ARRAY_SIZE(meas->ts); ++i) {
 | 
				
			||||||
 | 
								if (meas->ts[i].have_ms_i_level)
 | 
				
			||||||
 | 
									m_l1_meas.set_ms_i_level(i, meas->ts[i].ms_i_level);
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									m_l1_meas.ts[i].have_ms_i_level = 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t GprsMs::current_cs_dl() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						uint8_t cs = m_current_cs_dl;
 | 
				
			||||||
 | 
						size_t unencoded_octets;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!m_bts)
 | 
				
			||||||
 | 
							return cs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unencoded_octets = m_llc_queue.octets();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* If the DL TBF is active, add number of unencoded chunk octets */
 | 
				
			||||||
 | 
						if (m_dl_tbf)
 | 
				
			||||||
 | 
							unencoded_octets = m_dl_tbf->m_llc.chunk_size();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* There are many unencoded octets, don't reduce */
 | 
				
			||||||
 | 
						if (unencoded_octets >= m_bts->bts_data()->cs_downgrade_threshold)
 | 
				
			||||||
 | 
							return cs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* RF conditions are good, don't reduce */
 | 
				
			||||||
 | 
						if (m_nack_rate_dl < m_bts->bts_data()->cs_adj_lower_limit)
 | 
				
			||||||
 | 
							return cs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* The throughput would probably be better if the CS level was reduced */
 | 
				
			||||||
 | 
						cs -= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* CS-2 doesn't gain throughput with small packets, further reduce to CS-1 */
 | 
				
			||||||
 | 
						if (cs == 2)
 | 
				
			||||||
 | 
							cs -= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return cs;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,7 @@ struct gprs_rlcmac_ul_tbf;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#include "cxx_linuxlist.h"
 | 
					#include "cxx_linuxlist.h"
 | 
				
			||||||
#include "llc.h"
 | 
					#include "llc.h"
 | 
				
			||||||
 | 
					#include "pcu_l1_if.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
	#include <osmocom/core/timer.h>
 | 
						#include <osmocom/core/timer.h>
 | 
				
			||||||
@@ -96,6 +97,10 @@ public:
 | 
				
			|||||||
	LListHead<GprsMs>& list() {return this->m_list;}
 | 
						LListHead<GprsMs>& list() {return this->m_list;}
 | 
				
			||||||
	const LListHead<GprsMs>& list() const {return this->m_list;}
 | 
						const LListHead<GprsMs>& list() const {return this->m_list;}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						void update_l1_meas(const pcu_l1_meas *meas);
 | 
				
			||||||
 | 
						const pcu_l1_meas* l1_meas() const {return &m_l1_meas;};
 | 
				
			||||||
 | 
						unsigned nack_rate_dl() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* internal use */
 | 
						/* internal use */
 | 
				
			||||||
	static void timeout(void *priv_);
 | 
						static void timeout(void *priv_);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -132,6 +137,9 @@ private:
 | 
				
			|||||||
	unsigned m_delay;
 | 
						unsigned m_delay;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int64_t m_last_cs_not_low;
 | 
						int64_t m_last_cs_not_low;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pcu_l1_meas m_l1_meas;
 | 
				
			||||||
 | 
						unsigned m_nack_rate_dl;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline uint32_t GprsMs::tlli() const
 | 
					inline uint32_t GprsMs::tlli() const
 | 
				
			||||||
@@ -162,11 +170,6 @@ inline uint8_t GprsMs::ms_class() const
 | 
				
			|||||||
	return m_ms_class;
 | 
						return m_ms_class;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
inline uint8_t GprsMs::current_cs_dl() const
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return m_current_cs_dl;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
inline uint8_t GprsMs::current_cs_ul() const
 | 
					inline uint8_t GprsMs::current_cs_ul() const
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return m_current_cs_ul;
 | 
						return m_current_cs_ul;
 | 
				
			||||||
@@ -187,3 +190,8 @@ inline const gprs_llc_queue *GprsMs::llc_queue() const
 | 
				
			|||||||
	return &m_llc_queue;
 | 
						return &m_llc_queue;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline unsigned GprsMs::nack_rate_dl() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return m_nack_rate_dl;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,6 +80,18 @@ GprsMs *GprsMsStorage::get_ms(uint32_t tlli, uint32_t old_tlli, const char *imsi
 | 
				
			|||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GprsMs *GprsMsStorage::create_ms()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						GprsMs *ms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ms = new GprsMs(m_bts, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ms->set_callback(this);
 | 
				
			||||||
 | 
						llist_add(&ms->list(), &m_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return ms;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
GprsMs *GprsMsStorage::create_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
 | 
					GprsMs *GprsMsStorage::create_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	GprsMs *ms = get_ms(tlli);
 | 
						GprsMs *ms = get_ms(tlli);
 | 
				
			||||||
@@ -87,15 +99,12 @@ GprsMs *GprsMsStorage::create_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction d
 | 
				
			|||||||
	if (ms)
 | 
						if (ms)
 | 
				
			||||||
		return ms;
 | 
							return ms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ms = new GprsMs(m_bts, 0);
 | 
						ms = create_ms();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dir == GPRS_RLCMAC_UL_TBF)
 | 
						if (dir == GPRS_RLCMAC_UL_TBF)
 | 
				
			||||||
		ms->set_tlli(tlli);
 | 
							ms->set_tlli(tlli);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		ms->confirm_tlli(tlli);
 | 
							ms->confirm_tlli(tlli);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ms->set_callback(this);
 | 
					 | 
				
			||||||
	llist_add(&ms->list(), &m_list);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return ms;
 | 
						return ms;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,6 +38,7 @@ public:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	GprsMs *get_ms(uint32_t tlli, uint32_t old_tlli = 0, const char *imsi = 0) const;
 | 
						GprsMs *get_ms(uint32_t tlli, uint32_t old_tlli = 0, const char *imsi = 0) const;
 | 
				
			||||||
	GprsMs *create_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir);
 | 
						GprsMs *create_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir);
 | 
				
			||||||
 | 
						GprsMs *create_ms();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const LListHead<GprsMs>& ms_list() const {return m_list;}
 | 
						const LListHead<GprsMs>& ms_list() const {return m_list;}
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -42,6 +42,7 @@ extern "C" {
 | 
				
			|||||||
struct gprs_rlcmac_tbf;
 | 
					struct gprs_rlcmac_tbf;
 | 
				
			||||||
struct gprs_rlcmac_bts;
 | 
					struct gprs_rlcmac_bts;
 | 
				
			||||||
struct BTS;
 | 
					struct BTS;
 | 
				
			||||||
 | 
					struct GprsMs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -95,11 +96,11 @@ int gprs_rlcmac_rcv_rts_block(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
 | 
					int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *old_tbf,
 | 
						struct GprsMs *ms,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
 | 
						struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
 | 
					int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *old_tbf,
 | 
						struct GprsMs *ms,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
 | 
						struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single);
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,6 +23,7 @@
 | 
				
			|||||||
#include <gprs_debug.h>
 | 
					#include <gprs_debug.h>
 | 
				
			||||||
#include <bts.h>
 | 
					#include <bts.h>
 | 
				
			||||||
#include <tbf.h>
 | 
					#include <tbf.h>
 | 
				
			||||||
 | 
					#include <gprs_ms.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <errno.h>
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -139,7 +140,7 @@ static void assign_dlink_tbf(
 | 
				
			|||||||
 * Assign single slot for uplink and downlink
 | 
					 * Assign single slot for uplink and downlink
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
 | 
					int alloc_algorithm_a(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *old_tbf,
 | 
						GprsMs *ms,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single)
 | 
						struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gprs_rlcmac_pdch *pdch;
 | 
						struct gprs_rlcmac_pdch *pdch;
 | 
				
			||||||
@@ -261,16 +262,21 @@ inc_window:
 | 
				
			|||||||
	return rx_window;
 | 
						return rx_window;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int reduce_rx_window(const int ms_type, const struct gprs_rlcmac_tbf *old_tbf,
 | 
					static int reduce_rx_window(const int ms_type, const GprsMs *ms,
 | 
				
			||||||
				const int Tt, const int Tr,
 | 
									const int Tt, const int Tr,
 | 
				
			||||||
				int *rx_window,
 | 
									int *rx_window,
 | 
				
			||||||
				uint8_t *rx_win_min, uint8_t *rx_win_max)
 | 
									uint8_t *rx_win_min, uint8_t *rx_win_max)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						gprs_rlcmac_ul_tbf *ul_tbf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ms_type != 1)
 | 
						if (ms_type != 1)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	if (!old_tbf)
 | 
						if (!ms)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
	if (old_tbf->direction != GPRS_RLCMAC_UL_TBF)
 | 
					
 | 
				
			||||||
 | 
						ul_tbf = ms->ul_tbf();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!ul_tbf)
 | 
				
			||||||
		return 0;
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint8_t collide = 0, ul_usage = 0;
 | 
						uint8_t collide = 0, ul_usage = 0;
 | 
				
			||||||
@@ -278,7 +284,7 @@ static int reduce_rx_window(const int ms_type, const struct gprs_rlcmac_tbf *old
 | 
				
			|||||||
	/* calculate mask of colliding slots */
 | 
						/* calculate mask of colliding slots */
 | 
				
			||||||
	for (uint8_t ts_no = 0; ts_no < 8; ts_no++) {
 | 
						for (uint8_t ts_no = 0; ts_no < 8; ts_no++) {
 | 
				
			||||||
		int j;
 | 
							int j;
 | 
				
			||||||
		if (!old_tbf->pdch[ts_no])
 | 
							if (!ul_tbf->pdch[ts_no])
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ul_usage |= (1 << ts_no);
 | 
							ul_usage |= (1 << ts_no);
 | 
				
			||||||
@@ -525,7 +531,7 @@ static int select_first_ts(gprs_rlcmac_trx *trx, uint8_t tx_win_min,
 | 
				
			|||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
 | 
					int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *old_tbf,
 | 
						GprsMs *ms,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single)
 | 
						struct gprs_rlcmac_tbf *tbf, uint32_t cust, uint8_t single)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct gprs_ms_multislot_class *ms_class;
 | 
						const struct gprs_ms_multislot_class *ms_class;
 | 
				
			||||||
@@ -592,7 +598,7 @@ int alloc_algorithm_b(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* reduce window, if existing uplink slots collide RX window */
 | 
						/* reduce window, if existing uplink slots collide RX window */
 | 
				
			||||||
	int rc = reduce_rx_window(ms_class->type, old_tbf, Tt, Tr,
 | 
						int rc = reduce_rx_window(ms_class->type, ms, Tt, Tr,
 | 
				
			||||||
				&rx_window, &rx_win_min, &rx_win_max);
 | 
									&rx_window, &rx_win_min, &rx_win_max);
 | 
				
			||||||
	if (rc < 0)
 | 
						if (rc < 0)
 | 
				
			||||||
		return rc;
 | 
							return rc;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										29
									
								
								src/llc.cpp
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								src/llc.cpp
									
									
									
									
									
								
							@@ -100,12 +100,23 @@ void gprs_llc_queue::init()
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	INIT_LLIST_HEAD(&m_queue);
 | 
						INIT_LLIST_HEAD(&m_queue);
 | 
				
			||||||
	m_queue_size = 0;
 | 
						m_queue_size = 0;
 | 
				
			||||||
 | 
						m_queue_octets = 0;
 | 
				
			||||||
	m_avg_queue_delay = 0;
 | 
						m_avg_queue_delay = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gprs_llc_queue::enqueue(struct msgb *llc_msg)
 | 
					void gprs_llc_queue::enqueue(struct msgb *llc_msg, const MetaInfo *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						static const MetaInfo def_meta = {{0}};
 | 
				
			||||||
 | 
						MetaInfo *meta_storage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						osmo_static_assert(sizeof(*info) <= sizeof(llc_msg->cb), info_does_not_fit);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_queue_size += 1;
 | 
						m_queue_size += 1;
 | 
				
			||||||
 | 
						m_queue_octets += msgb_length(llc_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						meta_storage = (MetaInfo *)&llc_msg->cb[0];
 | 
				
			||||||
 | 
						*meta_storage = info ? *info : def_meta;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msgb_enqueue(&m_queue, llc_msg);
 | 
						msgb_enqueue(&m_queue, llc_msg);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -120,27 +131,34 @@ void gprs_llc_queue::clear(BTS *bts)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_queue_size = 0;
 | 
						m_queue_size = 0;
 | 
				
			||||||
 | 
						m_queue_octets = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ALPHA 0.5f
 | 
					#define ALPHA 0.5f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct msgb *gprs_llc_queue::dequeue()
 | 
					struct msgb *gprs_llc_queue::dequeue(const MetaInfo **info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg;
 | 
						struct msgb *msg;
 | 
				
			||||||
	struct timeval *tv, tv_now, tv_result;
 | 
						struct timeval *tv, tv_now, tv_result;
 | 
				
			||||||
	uint32_t lifetime;
 | 
						uint32_t lifetime;
 | 
				
			||||||
 | 
						const MetaInfo *meta_storage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msg = msgb_dequeue(&m_queue);
 | 
						msg = msgb_dequeue(&m_queue);
 | 
				
			||||||
	if (!msg)
 | 
						if (!msg)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						meta_storage = (MetaInfo *)&msg->cb[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (info)
 | 
				
			||||||
 | 
							*info = meta_storage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m_queue_size -= 1;
 | 
						m_queue_size -= 1;
 | 
				
			||||||
 | 
						m_queue_octets -= msgb_length(msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* take the second time */
 | 
						/* take the second time */
 | 
				
			||||||
	gettimeofday(&tv_now, NULL);
 | 
						gettimeofday(&tv_now, NULL);
 | 
				
			||||||
	tv = (struct timeval *)&msg->data[sizeof(*tv)];
 | 
						tv = (struct timeval *)&msg->data[sizeof(*tv)];
 | 
				
			||||||
	timersub(&tv_now, tv, &tv_result);
 | 
						timersub(&tv_now, &meta_storage->recv_time, &tv_result);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	lifetime = tv_result.tv_sec*1000 + tv_result.tv_usec/1000;
 | 
						lifetime = tv_result.tv_sec*1000 + tv_result.tv_usec/1000;
 | 
				
			||||||
	m_avg_queue_delay = m_avg_queue_delay * ALPHA + lifetime * (1-ALPHA);
 | 
						m_avg_queue_delay = m_avg_queue_delay * ALPHA + lifetime * (1-ALPHA);
 | 
				
			||||||
@@ -171,7 +189,8 @@ void gprs_llc_queue::calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec,
 | 
				
			|||||||
	timeradd(&now, &csec, tv);
 | 
						timeradd(&now, &csec, tv);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool gprs_llc_queue::is_frame_expired(struct timeval *tv_now, struct timeval *tv)
 | 
					bool gprs_llc_queue::is_frame_expired(const struct timeval *tv_now,
 | 
				
			||||||
 | 
						const struct timeval *tv)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* Timeout is infinite */
 | 
						/* Timeout is infinite */
 | 
				
			||||||
	if (tv->tv_sec == 0 && tv->tv_usec == 0)
 | 
						if (tv->tv_sec == 0 && tv->tv_usec == 0)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										27
									
								
								src/llc.h
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								src/llc.h
									
									
									
									
									
								
							@@ -18,8 +18,13 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#pragma once
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
						#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <stdint.h>
 | 
					#include <stdint.h>
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <time.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define LLC_MAX_LEN 1543
 | 
					#define LLC_MAX_LEN 1543
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,20 +64,29 @@ struct gprs_llc {
 | 
				
			|||||||
 * I store the LLC frames that come from the SGSN.
 | 
					 * I store the LLC frames that come from the SGSN.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct gprs_llc_queue {
 | 
					struct gprs_llc_queue {
 | 
				
			||||||
	static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec, struct timeval *tv);
 | 
						struct MetaInfo {
 | 
				
			||||||
	static bool is_frame_expired(struct timeval *now, struct timeval *tv);
 | 
							struct timeval recv_time;
 | 
				
			||||||
 | 
							struct timeval expire_time;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						static void calc_pdu_lifetime(BTS *bts, const uint16_t pdu_delay_csec,
 | 
				
			||||||
 | 
							struct timeval *tv);
 | 
				
			||||||
 | 
						static bool is_frame_expired(const struct timeval *now,
 | 
				
			||||||
 | 
							const struct timeval *tv);
 | 
				
			||||||
	static bool is_user_data_frame(uint8_t *data, size_t len);
 | 
						static bool is_user_data_frame(uint8_t *data, size_t len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void init();
 | 
						void init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void enqueue(struct msgb *llc_msg);
 | 
						void enqueue(struct msgb *llc_msg, const MetaInfo *info = 0);
 | 
				
			||||||
	struct msgb *dequeue();
 | 
						struct msgb *dequeue(const MetaInfo **info = 0);
 | 
				
			||||||
	void clear(BTS *bts);
 | 
						void clear(BTS *bts);
 | 
				
			||||||
	size_t size() const;
 | 
						size_t size() const;
 | 
				
			||||||
 | 
						size_t octets() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
	uint32_t m_avg_queue_delay; /* Average delay of data going through the queue */
 | 
						uint32_t m_avg_queue_delay; /* Average delay of data going through the queue */
 | 
				
			||||||
	size_t m_queue_size;
 | 
						size_t m_queue_size;
 | 
				
			||||||
 | 
						size_t m_queue_octets;
 | 
				
			||||||
	struct llist_head m_queue; /* queued LLC DL data */
 | 
						struct llist_head m_queue; /* queued LLC DL data */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -114,3 +128,8 @@ inline size_t gprs_llc_queue::size() const
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
	return this ? m_queue_size : 0;
 | 
						return this ? m_queue_size : 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					inline size_t gprs_llc_queue::octets() const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return this ? m_queue_octets : 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -181,17 +181,19 @@ void pcu_l1if_tx_pch(bitvec * block, int plen, const char *imsi)
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern "C" int pcu_rx_data_ind_pdtch(uint8_t trx_no, uint8_t ts_no, uint8_t *data,
 | 
					extern "C" int pcu_rx_data_ind_pdtch(uint8_t trx_no, uint8_t ts_no, uint8_t *data,
 | 
				
			||||||
	uint8_t len, uint32_t fn, int8_t rssi)
 | 
						uint8_t len, uint32_t fn, struct pcu_l1_meas *meas)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gprs_rlcmac_pdch *pdch;
 | 
						struct gprs_rlcmac_pdch *pdch;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pdch = &bts_main_data()->trx[trx_no].pdch[ts_no];
 | 
						pdch = &bts_main_data()->trx[trx_no].pdch[ts_no];
 | 
				
			||||||
	return pdch->rcv_block(data, len, fn, rssi);
 | 
						return pdch->rcv_block(data, len, fn, meas);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
 | 
					static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						pcu_l1_meas meas;
 | 
				
			||||||
 | 
						meas.set_rssi(data_ind->rssi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DL1IF, LOGL_DEBUG, "Data indication received: sapi=%d arfcn=%d "
 | 
						LOGP(DL1IF, LOGL_DEBUG, "Data indication received: sapi=%d arfcn=%d "
 | 
				
			||||||
		"block=%d data=%s\n", data_ind->sapi,
 | 
							"block=%d data=%s\n", data_ind->sapi,
 | 
				
			||||||
@@ -202,7 +204,7 @@ static int pcu_rx_data_ind(struct gsm_pcu_if_data *data_ind)
 | 
				
			|||||||
	case PCU_IF_SAPI_PDTCH:
 | 
						case PCU_IF_SAPI_PDTCH:
 | 
				
			||||||
		rc = pcu_rx_data_ind_pdtch(data_ind->trx_nr, data_ind->ts_nr,
 | 
							rc = pcu_rx_data_ind_pdtch(data_ind->trx_nr, data_ind->ts_nr,
 | 
				
			||||||
			data_ind->data, data_ind->len, data_ind->fn,
 | 
								data_ind->data, data_ind->len, data_ind->fn,
 | 
				
			||||||
			data_ind->rssi);
 | 
								&meas);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		LOGP(DL1IF, LOGL_ERROR, "Received PCU data indication with "
 | 
							LOGP(DL1IF, LOGL_ERROR, "Received PCU data indication with "
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,7 +31,81 @@ extern "C" {
 | 
				
			|||||||
#include <osmocom/gsm/gsm_utils.h>
 | 
					#include <osmocom/gsm/gsm_utils.h>
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * L1 Measurement values
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct pcu_l1_meas_ts {
 | 
				
			||||||
 | 
						unsigned have_ms_i_level:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int16_t ms_i_level; /* I_LEVEL in dB */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
						pcu_l1_meas_ts& set_ms_i_level(int16_t v) {
 | 
				
			||||||
 | 
							ms_i_level = v; have_ms_i_level = 1; return *this;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pcu_l1_meas_ts() :
 | 
				
			||||||
 | 
							have_ms_i_level(0)
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct pcu_l1_meas {
 | 
				
			||||||
 | 
						unsigned have_rssi:1;
 | 
				
			||||||
 | 
						unsigned have_ber:1;
 | 
				
			||||||
 | 
						unsigned have_bto:1;
 | 
				
			||||||
 | 
						unsigned have_link_qual:1;
 | 
				
			||||||
 | 
						unsigned have_ms_rx_qual:1;
 | 
				
			||||||
 | 
						unsigned have_ms_c_value:1;
 | 
				
			||||||
 | 
						unsigned have_ms_sign_var:1;
 | 
				
			||||||
 | 
						unsigned have_ms_i_level:1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int8_t rssi; /* RSSI in dBm */
 | 
				
			||||||
 | 
						uint8_t ber; /* Bit error rate in % */
 | 
				
			||||||
 | 
						int16_t bto; /* Burst timing offset in quarter bits */
 | 
				
			||||||
 | 
						int16_t link_qual; /* Link quality in dB */
 | 
				
			||||||
 | 
						int16_t ms_rx_qual; /* MS RXQUAL value in % */
 | 
				
			||||||
 | 
						int16_t ms_c_value; /* C value in dB */
 | 
				
			||||||
 | 
						int16_t ms_sign_var; /* SIGN_VAR in dB */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct pcu_l1_meas_ts ts[8];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
						pcu_l1_meas& set_rssi(int8_t v) { rssi = v; have_rssi = 1; return *this;}
 | 
				
			||||||
 | 
						pcu_l1_meas& set_ber(uint8_t v) { ber = v; have_ber = 1; return *this;}
 | 
				
			||||||
 | 
						pcu_l1_meas& set_bto(int16_t v) { bto = v; have_bto = 1; return *this;}
 | 
				
			||||||
 | 
						pcu_l1_meas& set_link_qual(int16_t v) {
 | 
				
			||||||
 | 
							link_qual = v; have_link_qual = 1; return *this;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pcu_l1_meas& set_ms_rx_qual(int16_t v) {
 | 
				
			||||||
 | 
							ms_rx_qual = v; have_ms_rx_qual = 1; return *this;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pcu_l1_meas& set_ms_c_value(int16_t v) {
 | 
				
			||||||
 | 
							ms_c_value = v; have_ms_c_value = 1; return *this;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pcu_l1_meas& set_ms_sign_var(int16_t v) {
 | 
				
			||||||
 | 
							ms_sign_var = v; have_ms_sign_var = 1; return *this;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pcu_l1_meas& set_ms_i_level(size_t idx, int16_t v) {
 | 
				
			||||||
 | 
							ts[idx].set_ms_i_level(v); have_ms_i_level = 1; return *this;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pcu_l1_meas() :
 | 
				
			||||||
 | 
							have_rssi(0),
 | 
				
			||||||
 | 
							have_ber(0),
 | 
				
			||||||
 | 
							have_bto(0),
 | 
				
			||||||
 | 
							have_link_qual(0),
 | 
				
			||||||
 | 
							have_ms_rx_qual(0),
 | 
				
			||||||
 | 
							have_ms_c_value(0),
 | 
				
			||||||
 | 
							have_ms_sign_var(0),
 | 
				
			||||||
 | 
							have_ms_i_level(0)
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, 
 | 
					void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, 
 | 
				
			||||||
        uint32_t fn, uint8_t block_nr);
 | 
					        uint32_t fn, uint8_t block_nr);
 | 
				
			||||||
void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, 
 | 
					void pcu_l1if_tx_ptcch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn, 
 | 
				
			||||||
@@ -57,6 +131,6 @@ int pcu_rx_rts_req_pdtch(uint8_t trx, uint8_t ts, uint16_t arfcn,
 | 
				
			|||||||
extern "C"
 | 
					extern "C"
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
int pcu_rx_data_ind_pdtch(uint8_t trx, uint8_t ts, uint8_t *data,
 | 
					int pcu_rx_data_ind_pdtch(uint8_t trx, uint8_t ts, uint8_t *data,
 | 
				
			||||||
	uint8_t len, uint32_t fn, int8_t rssi);
 | 
						uint8_t len, uint32_t fn, struct pcu_l1_meas *meas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif // PCU_L1_IF_H
 | 
					#endif // PCU_L1_IF_H
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -178,6 +178,16 @@ int main(int argc, char *argv[])
 | 
				
			|||||||
	bts->cs_adj_lower_limit = 10; /* Increase CS if the error rate is below */
 | 
						bts->cs_adj_lower_limit = 10; /* Increase CS if the error rate is below */
 | 
				
			||||||
	bts->max_cs_ul = 4;
 | 
						bts->max_cs_ul = 4;
 | 
				
			||||||
	bts->max_cs_dl = 4;
 | 
						bts->max_cs_dl = 4;
 | 
				
			||||||
 | 
						/* CS-1 to CS-4 */
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[0].low = -256;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[0].high = 6;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[1].low = 5;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[1].high = 8;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[2].low = 7;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[2].high = 13;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[3].low = 12;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[3].high = 256;
 | 
				
			||||||
 | 
						bts->cs_downgrade_threshold = 200;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	msgb_set_talloc_ctx(tall_pcu_ctx);
 | 
						msgb_set_talloc_ctx(tall_pcu_ctx);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -90,6 +90,21 @@ static int config_write_pcu(struct vty *vty)
 | 
				
			|||||||
	else
 | 
						else
 | 
				
			||||||
		vty_out(vty, " no cs threshold%s", VTY_NEWLINE);
 | 
							vty_out(vty, " no cs threshold%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (bts->cs_downgrade_threshold)
 | 
				
			||||||
 | 
							vty_out(vty, " cs downgrade-threshold %d%s",
 | 
				
			||||||
 | 
								bts->cs_downgrade_threshold, VTY_NEWLINE);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							vty_out(vty, " no cs downgrade-threshold%s", VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vty_out(vty, " cs link-quality-ranges cs1 %d cs2 %d %d cs3 %d %d cs4 %d%s",
 | 
				
			||||||
 | 
							bts->cs_lqual_ranges[0].high,
 | 
				
			||||||
 | 
							bts->cs_lqual_ranges[1].low,
 | 
				
			||||||
 | 
							bts->cs_lqual_ranges[1].high,
 | 
				
			||||||
 | 
							bts->cs_lqual_ranges[2].low,
 | 
				
			||||||
 | 
							bts->cs_lqual_ranges[2].high,
 | 
				
			||||||
 | 
							bts->cs_lqual_ranges[3].low,
 | 
				
			||||||
 | 
							VTY_NEWLINE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bts->force_llc_lifetime == 0xffff)
 | 
						if (bts->force_llc_lifetime == 0xffff)
 | 
				
			||||||
		vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE);
 | 
							vty_out(vty, " queue lifetime infinite%s", VTY_NEWLINE);
 | 
				
			||||||
	else if (bts->force_llc_lifetime)
 | 
						else if (bts->force_llc_lifetime)
 | 
				
			||||||
@@ -600,6 +615,67 @@ DEFUN(cfg_pcu_no_cs_err_limits,
 | 
				
			|||||||
	return CMD_SUCCESS;
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define CS_DOWNGRADE_STR "set threshold for data size based CS downgrade\n"
 | 
				
			||||||
 | 
					DEFUN(cfg_pcu_cs_downgrade_thrsh,
 | 
				
			||||||
 | 
					      cfg_pcu_cs_downgrade_thrsh_cmd,
 | 
				
			||||||
 | 
					      "cs downgrade-threshold <1-10000>",
 | 
				
			||||||
 | 
					      CS_STR CS_DOWNGRADE_STR "downgrade if less octets left\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gprs_rlcmac_bts *bts = bts_main_data();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bts->cs_downgrade_threshold = atoi(argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_pcu_no_cs_downgrade_thrsh,
 | 
				
			||||||
 | 
					      cfg_pcu_no_cs_downgrade_thrsh_cmd,
 | 
				
			||||||
 | 
					      "no cs downgrade-threshold",
 | 
				
			||||||
 | 
					      CS_STR CS_DOWNGRADE_STR)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gprs_rlcmac_bts *bts = bts_main_data();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bts->cs_downgrade_threshold = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFUN(cfg_pcu_cs_lqual_ranges,
 | 
				
			||||||
 | 
					      cfg_pcu_cs_lqual_ranges_cmd,
 | 
				
			||||||
 | 
					      "cs link-quality-ranges cs1 <0-35> cs2 <0-35> <0-35> cs3 <0-35> <0-35> cs4 <0-35>",
 | 
				
			||||||
 | 
					      CS_STR "Set link quality ranges\n"
 | 
				
			||||||
 | 
					      "Set quality range for CS-1 (high value only)\n"
 | 
				
			||||||
 | 
					      "CS-1 high (dB)\n"
 | 
				
			||||||
 | 
					      "Set quality range for CS-2\n"
 | 
				
			||||||
 | 
					      "CS-2 low (dB)\n"
 | 
				
			||||||
 | 
					      "CS-2 high (dB)\n"
 | 
				
			||||||
 | 
					      "Set quality range for CS-3\n"
 | 
				
			||||||
 | 
					      "CS-3 low (dB)\n"
 | 
				
			||||||
 | 
					      "CS-3 high (dB)\n"
 | 
				
			||||||
 | 
					      "Set quality range for CS-4 (low value only)\n"
 | 
				
			||||||
 | 
					      "CS-4 low (dB)\n")
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct gprs_rlcmac_bts *bts = bts_main_data();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint8_t cs1_high = atoi(argv[0]);
 | 
				
			||||||
 | 
						uint8_t cs2_low = atoi(argv[1]);
 | 
				
			||||||
 | 
						uint8_t cs2_high = atoi(argv[2]);
 | 
				
			||||||
 | 
						uint8_t cs3_low = atoi(argv[3]);
 | 
				
			||||||
 | 
						uint8_t cs3_high = atoi(argv[4]);
 | 
				
			||||||
 | 
						uint8_t cs4_low = atoi(argv[5]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[0].high = cs1_high;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[1].low  = cs2_low;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[1].high = cs2_high;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[2].low  = cs3_low;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[2].high = cs3_high;
 | 
				
			||||||
 | 
						bts->cs_lqual_ranges[3].low  = cs4_low;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return CMD_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DEFUN(show_tbf,
 | 
					DEFUN(show_tbf,
 | 
				
			||||||
      show_tbf_cmd,
 | 
					      show_tbf_cmd,
 | 
				
			||||||
      "show tbf all",
 | 
					      "show tbf all",
 | 
				
			||||||
@@ -685,6 +761,9 @@ int pcu_vty_init(const struct log_info *cat)
 | 
				
			|||||||
	install_element(PCU_NODE, &cfg_pcu_no_cs_max_cmd);
 | 
						install_element(PCU_NODE, &cfg_pcu_no_cs_max_cmd);
 | 
				
			||||||
	install_element(PCU_NODE, &cfg_pcu_cs_err_limits_cmd);
 | 
						install_element(PCU_NODE, &cfg_pcu_cs_err_limits_cmd);
 | 
				
			||||||
	install_element(PCU_NODE, &cfg_pcu_no_cs_err_limits_cmd);
 | 
						install_element(PCU_NODE, &cfg_pcu_no_cs_err_limits_cmd);
 | 
				
			||||||
 | 
						install_element(PCU_NODE, &cfg_pcu_cs_downgrade_thrsh_cmd);
 | 
				
			||||||
 | 
						install_element(PCU_NODE, &cfg_pcu_no_cs_downgrade_thrsh_cmd);
 | 
				
			||||||
 | 
						install_element(PCU_NODE, &cfg_pcu_cs_lqual_ranges_cmd);
 | 
				
			||||||
	install_element(PCU_NODE, &cfg_pcu_queue_lifetime_cmd);
 | 
						install_element(PCU_NODE, &cfg_pcu_queue_lifetime_cmd);
 | 
				
			||||||
	install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd);
 | 
						install_element(PCU_NODE, &cfg_pcu_queue_lifetime_inf_cmd);
 | 
				
			||||||
	install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd);
 | 
						install_element(PCU_NODE, &cfg_pcu_no_queue_lifetime_cmd);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,6 +58,8 @@ int pcu_vty_show_ms_all(struct vty *vty, struct gprs_rlcmac_bts *bts_data)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static int show_ms(struct vty *vty, GprsMs *ms)
 | 
					static int show_ms(struct vty *vty, GprsMs *ms)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						unsigned i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vty_out(vty, "MS TLLI=%08x, IMSI=%s%s", ms->tlli(), ms->imsi(), VTY_NEWLINE);
 | 
						vty_out(vty, "MS TLLI=%08x, IMSI=%s%s", ms->tlli(), ms->imsi(), VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, "  Timing advance (TA):    %d%s", ms->ta(), VTY_NEWLINE);
 | 
						vty_out(vty, "  Timing advance (TA):    %d%s", ms->ta(), VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, "  Coding scheme uplink:   CS-%d%s", ms->current_cs_ul(),
 | 
						vty_out(vty, "  Coding scheme uplink:   CS-%d%s", ms->current_cs_ul(),
 | 
				
			||||||
@@ -67,6 +69,35 @@ static int show_ms(struct vty *vty, GprsMs *ms)
 | 
				
			|||||||
	vty_out(vty, "  MS class:               %d%s", ms->ms_class(), VTY_NEWLINE);
 | 
						vty_out(vty, "  MS class:               %d%s", ms->ms_class(), VTY_NEWLINE);
 | 
				
			||||||
	vty_out(vty, "  LLC queue length:       %d%s", ms->llc_queue()->size(),
 | 
						vty_out(vty, "  LLC queue length:       %d%s", ms->llc_queue()->size(),
 | 
				
			||||||
		VTY_NEWLINE);
 | 
							VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (ms->l1_meas()->have_rssi)
 | 
				
			||||||
 | 
							vty_out(vty, "  RSSI:                   %d dBm%s",
 | 
				
			||||||
 | 
								ms->l1_meas()->rssi, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (ms->l1_meas()->have_ber)
 | 
				
			||||||
 | 
							vty_out(vty, "  Bit error rate:         %d %%%s",
 | 
				
			||||||
 | 
								ms->l1_meas()->ber, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (ms->l1_meas()->have_link_qual)
 | 
				
			||||||
 | 
							vty_out(vty, "  Link quality:           %d dB%s",
 | 
				
			||||||
 | 
								ms->l1_meas()->link_qual, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (ms->l1_meas()->have_bto)
 | 
				
			||||||
 | 
							vty_out(vty, "  Burst timing offset:    %d/4 bit%s",
 | 
				
			||||||
 | 
								ms->l1_meas()->bto, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (ms->l1_meas()->have_ms_rx_qual)
 | 
				
			||||||
 | 
							vty_out(vty, "  Downlink NACK rate:     %d %%%s",
 | 
				
			||||||
 | 
								ms->nack_rate_dl(), VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (ms->l1_meas()->have_ms_rx_qual)
 | 
				
			||||||
 | 
							vty_out(vty, "  MS RX quality:          %d %%%s",
 | 
				
			||||||
 | 
								ms->l1_meas()->ms_rx_qual, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (ms->l1_meas()->have_ms_c_value)
 | 
				
			||||||
 | 
							vty_out(vty, "  MS C value:             %d dB%s",
 | 
				
			||||||
 | 
								ms->l1_meas()->ms_c_value, VTY_NEWLINE);
 | 
				
			||||||
 | 
						if (ms->l1_meas()->have_ms_sign_var)
 | 
				
			||||||
 | 
							vty_out(vty, "  MS SIGN variance:       %d dB%s",
 | 
				
			||||||
 | 
								ms->l1_meas()->ms_sign_var, VTY_NEWLINE);
 | 
				
			||||||
 | 
						for (i = 0; i < ARRAY_SIZE(ms->l1_meas()->ts); ++i) {
 | 
				
			||||||
 | 
							if (ms->l1_meas()->ts[i].have_ms_i_level)
 | 
				
			||||||
 | 
								vty_out(vty, "  MS I level (slot %d):    %d dB%s",
 | 
				
			||||||
 | 
									i, ms->l1_meas()->ts[i].ms_i_level, VTY_NEWLINE);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	if (ms->ul_tbf())
 | 
						if (ms->ul_tbf())
 | 
				
			||||||
		vty_out(vty, "  Uplink TBF:             TFI=%d, state=%s%s",
 | 
							vty_out(vty, "  Uplink TBF:             TFI=%d, state=%s%s",
 | 
				
			||||||
			ms->ul_tbf()->tfi(),
 | 
								ms->ul_tbf()->tfi(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -166,10 +166,23 @@ static int handle_ph_readytosend_ind(struct femtol1_hdl *fl1h,
 | 
				
			|||||||
	return rc;
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void get_meas(struct pcu_l1_meas *meas, const GsmL1_MeasParam_t *l1_meas)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						meas->rssi = (int8_t) (l1_meas->fRssi);
 | 
				
			||||||
 | 
						meas->have_rssi = 1;
 | 
				
			||||||
 | 
						meas->ber  = (uint8_t) (l1_meas->fBer * 100);
 | 
				
			||||||
 | 
						meas->have_ber = 1;
 | 
				
			||||||
 | 
						meas->bto  = (int16_t) (l1_meas->i16BurstTiming);
 | 
				
			||||||
 | 
						meas->have_bto = 1;
 | 
				
			||||||
 | 
						meas->link_qual  = (int16_t) (l1_meas->fLinkQuality);
 | 
				
			||||||
 | 
						meas->have_link_qual = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int handle_ph_data_ind(struct femtol1_hdl *fl1h,
 | 
					static int handle_ph_data_ind(struct femtol1_hdl *fl1h,
 | 
				
			||||||
	GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg)
 | 
						GsmL1_PhDataInd_t *data_ind, struct msgb *l1p_msg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc = 0;
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						struct pcu_l1_meas meas = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	DEBUGP(DL1IF, "Rx PH-DATA.ind %s (hL2 %08x): %s\n",
 | 
						DEBUGP(DL1IF, "Rx PH-DATA.ind %s (hL2 %08x): %s\n",
 | 
				
			||||||
		get_value_string(femtobts_l1sapi_names, data_ind->sapi),
 | 
							get_value_string(femtobts_l1sapi_names, data_ind->sapi),
 | 
				
			||||||
@@ -190,8 +203,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1h,
 | 
				
			|||||||
			data_ind->u32Fn, 0, 0, data_ind->msgUnitParam.u8Buffer+1,
 | 
								data_ind->u32Fn, 0, 0, data_ind->msgUnitParam.u8Buffer+1,
 | 
				
			||||||
			data_ind->msgUnitParam.u8Size-1);
 | 
								data_ind->msgUnitParam.u8Size-1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						get_meas(&meas, &data_ind->measParam);
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (data_ind->sapi) {
 | 
						switch (data_ind->sapi) {
 | 
				
			||||||
	case GsmL1_Sapi_Pdtch:
 | 
						case GsmL1_Sapi_Pdtch:
 | 
				
			||||||
@@ -205,7 +217,7 @@ static int handle_ph_data_ind(struct femtol1_hdl *fl1h,
 | 
				
			|||||||
			data_ind->msgUnitParam.u8Buffer + 1,
 | 
								data_ind->msgUnitParam.u8Buffer + 1,
 | 
				
			||||||
			data_ind->msgUnitParam.u8Size - 1,
 | 
								data_ind->msgUnitParam.u8Size - 1,
 | 
				
			||||||
			data_ind->u32Fn,
 | 
								data_ind->u32Fn,
 | 
				
			||||||
			(int8_t) (data_ind->measParam.fRssi));
 | 
								&meas);
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case GsmL1_Sapi_Ptcch:
 | 
						case GsmL1_Sapi_Ptcch:
 | 
				
			||||||
		// FIXME
 | 
							// FIXME
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										83
									
								
								src/tbf.cpp
									
									
									
									
									
								
							
							
						
						
									
										83
									
								
								src/tbf.cpp
									
									
									
									
									
								
							@@ -158,23 +158,11 @@ void gprs_rlcmac_tbf::set_ms(GprsMs *ms)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
 | 
					void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction dir)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (!ms()) {
 | 
						if (!ms())
 | 
				
			||||||
		GprsMs *new_ms = bts->ms_store().get_ms(tlli);
 | 
							return;
 | 
				
			||||||
		if (!new_ms) {
 | 
					
 | 
				
			||||||
			new_ms = bts->ms_store().create_ms(tlli, dir);
 | 
						if (!tlli)
 | 
				
			||||||
			new_ms->set_timeout(bts->bts_data()->ms_idle_sec);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (dir == GPRS_RLCMAC_UL_TBF) {
 | 
					 | 
				
			||||||
			new_ms->set_ta(m_ta);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (m_ms_class)
 | 
					 | 
				
			||||||
			new_ms->set_ms_class(m_ms_class);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		set_ms(new_ms);
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dir == GPRS_RLCMAC_UL_TBF)
 | 
						if (dir == GPRS_RLCMAC_UL_TBF)
 | 
				
			||||||
		ms()->set_tlli(tlli);
 | 
							ms()->set_tlli(tlli);
 | 
				
			||||||
@@ -184,7 +172,7 @@ void gprs_rlcmac_tbf::update_ms(uint32_t tlli, enum gprs_rlcmac_tbf_direction di
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
 | 
					gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	int8_t use_trx, uint8_t ms_class,
 | 
						int8_t use_trx, uint8_t ms_class,
 | 
				
			||||||
	uint32_t tlli, uint8_t ta, struct gprs_rlcmac_tbf *dl_tbf)
 | 
						uint32_t tlli, uint8_t ta, GprsMs *ms)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t trx;
 | 
						uint8_t trx;
 | 
				
			||||||
	struct gprs_rlcmac_ul_tbf *tbf;
 | 
						struct gprs_rlcmac_ul_tbf *tbf;
 | 
				
			||||||
@@ -199,7 +187,7 @@ gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	/* use multislot class of downlink TBF */
 | 
						/* use multislot class of downlink TBF */
 | 
				
			||||||
	tbf = tbf_alloc_ul_tbf(bts, dl_tbf, tfi, trx, ms_class, 0);
 | 
						tbf = tbf_alloc_ul_tbf(bts, ms, tfi, trx, ms_class, 0);
 | 
				
			||||||
	if (!tbf) {
 | 
						if (!tbf) {
 | 
				
			||||||
		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
 | 
							LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
 | 
				
			||||||
		/* FIXME: send reject */
 | 
							/* FIXME: send reject */
 | 
				
			||||||
@@ -274,7 +262,6 @@ void tbf_free(struct gprs_rlcmac_tbf *tbf)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int gprs_rlcmac_tbf::update()
 | 
					int gprs_rlcmac_tbf::update()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gprs_rlcmac_tbf *ul_tbf = NULL;
 | 
					 | 
				
			||||||
	struct gprs_rlcmac_bts *bts_data = bts->bts_data();
 | 
						struct gprs_rlcmac_bts *bts_data = bts->bts_data();
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -283,11 +270,8 @@ int gprs_rlcmac_tbf::update()
 | 
				
			|||||||
	if (direction != GPRS_RLCMAC_DL_TBF)
 | 
						if (direction != GPRS_RLCMAC_DL_TBF)
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ms())
 | 
					 | 
				
			||||||
		ul_tbf = ms()->ul_tbf();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	tbf_unlink_pdch(this);
 | 
						tbf_unlink_pdch(this);
 | 
				
			||||||
	rc = bts_data->alloc_algorithm(bts_data, ul_tbf, this, bts_data->alloc_algorithm_curst, 0);
 | 
						rc = bts_data->alloc_algorithm(bts_data, ms(), this, bts_data->alloc_algorithm_curst, 0);
 | 
				
			||||||
	/* if no resource */
 | 
						/* if no resource */
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		LOGP(DRLCMAC, LOGL_ERROR, "No resource after update???\n");
 | 
							LOGP(DRLCMAC, LOGL_ERROR, "No resource after update???\n");
 | 
				
			||||||
@@ -450,7 +434,7 @@ void gprs_rlcmac_tbf::poll_timeout()
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int setup_tbf(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_bts *bts,
 | 
					static int setup_tbf(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *old_tbf, uint8_t tfi, uint8_t trx,
 | 
						GprsMs *ms, uint8_t tfi, uint8_t trx,
 | 
				
			||||||
	uint8_t ms_class, uint8_t single_slot)
 | 
						uint8_t ms_class, uint8_t single_slot)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
@@ -470,7 +454,7 @@ static int setup_tbf(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
	tbf->trx = &bts->trx[trx];
 | 
						tbf->trx = &bts->trx[trx];
 | 
				
			||||||
	tbf->set_ms_class(ms_class);
 | 
						tbf->set_ms_class(ms_class);
 | 
				
			||||||
	/* select algorithm */
 | 
						/* select algorithm */
 | 
				
			||||||
	rc = bts->alloc_algorithm(bts, old_tbf, tbf, bts->alloc_algorithm_curst,
 | 
						rc = bts->alloc_algorithm(bts, ms, tbf, bts->alloc_algorithm_curst,
 | 
				
			||||||
		single_slot);
 | 
							single_slot);
 | 
				
			||||||
	/* if no resource */
 | 
						/* if no resource */
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
@@ -488,12 +472,14 @@ static int setup_tbf(struct gprs_rlcmac_tbf *tbf, struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
	gettimeofday(&tbf->meas.rssi_tv, NULL);
 | 
						gettimeofday(&tbf->meas.rssi_tv, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tbf->m_llc.init();
 | 
						tbf->m_llc.init();
 | 
				
			||||||
 | 
						tbf->set_ms(ms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 | 
					struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *old_tbf, uint8_t tfi, uint8_t trx,
 | 
						GprsMs *ms, uint8_t tfi, uint8_t trx,
 | 
				
			||||||
	uint8_t ms_class, uint8_t single_slot)
 | 
						uint8_t ms_class, uint8_t single_slot)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gprs_rlcmac_ul_tbf *tbf;
 | 
						struct gprs_rlcmac_ul_tbf *tbf;
 | 
				
			||||||
@@ -512,7 +498,11 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tbf->direction = GPRS_RLCMAC_UL_TBF;
 | 
						tbf->direction = GPRS_RLCMAC_UL_TBF;
 | 
				
			||||||
	rc = setup_tbf(tbf, bts, old_tbf, tfi, trx, ms_class, single_slot);
 | 
					
 | 
				
			||||||
 | 
						if (!ms)
 | 
				
			||||||
 | 
							ms = bts->bts->ms_alloc(ms_class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = setup_tbf(tbf, bts, ms, tfi, trx, ms_class, single_slot);
 | 
				
			||||||
	/* if no resource */
 | 
						/* if no resource */
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		talloc_free(tbf);
 | 
							talloc_free(tbf);
 | 
				
			||||||
@@ -522,17 +512,11 @@ struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
	llist_add(&tbf->list.list, &bts->ul_tbfs);
 | 
						llist_add(&tbf->list.list, &bts->ul_tbfs);
 | 
				
			||||||
	tbf->bts->tbf_ul_created();
 | 
						tbf->bts->tbf_ul_created();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (old_tbf && old_tbf->ms())
 | 
					 | 
				
			||||||
		tbf->set_ms(old_tbf->ms());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (tbf->ms())
 | 
					 | 
				
			||||||
		tbf->ms()->attach_ul_tbf(tbf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return tbf;
 | 
						return tbf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
 | 
					struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *old_tbf, uint8_t tfi, uint8_t trx,
 | 
						GprsMs *ms, uint8_t tfi, uint8_t trx,
 | 
				
			||||||
	uint8_t ms_class, uint8_t single_slot)
 | 
						uint8_t ms_class, uint8_t single_slot)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gprs_rlcmac_dl_tbf *tbf;
 | 
						struct gprs_rlcmac_dl_tbf *tbf;
 | 
				
			||||||
@@ -551,7 +535,11 @@ struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tbf->direction = GPRS_RLCMAC_DL_TBF;
 | 
						tbf->direction = GPRS_RLCMAC_DL_TBF;
 | 
				
			||||||
	rc = setup_tbf(tbf, bts, old_tbf, tfi, trx, ms_class, single_slot);
 | 
					
 | 
				
			||||||
 | 
						if (!ms)
 | 
				
			||||||
 | 
							ms = bts->bts->ms_alloc(ms_class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rc = setup_tbf(tbf, bts, ms, tfi, trx, ms_class, single_slot);
 | 
				
			||||||
	/* if no resource */
 | 
						/* if no resource */
 | 
				
			||||||
	if (rc < 0) {
 | 
						if (rc < 0) {
 | 
				
			||||||
		talloc_free(tbf);
 | 
							talloc_free(tbf);
 | 
				
			||||||
@@ -567,12 +555,6 @@ struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
	gettimeofday(&tbf->m_bw.dl_bw_tv, NULL);
 | 
						gettimeofday(&tbf->m_bw.dl_bw_tv, NULL);
 | 
				
			||||||
	gettimeofday(&tbf->m_bw.dl_loss_tv, NULL);
 | 
						gettimeofday(&tbf->m_bw.dl_loss_tv, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (old_tbf && old_tbf->ms())
 | 
					 | 
				
			||||||
		tbf->set_ms(old_tbf->ms());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (tbf->ms())
 | 
					 | 
				
			||||||
		tbf->ms()->attach_dl_tbf(tbf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return tbf;
 | 
						return tbf;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -847,10 +829,6 @@ void gprs_rlcmac_tbf::free_all(struct gprs_rlcmac_pdch *pdch)
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gprs_rlcmac_tbf::update_tlli(uint32_t tlli)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
 | 
					int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gprs_rlcmac_tbf *dl_tbf = NULL;
 | 
						struct gprs_rlcmac_tbf *dl_tbf = NULL;
 | 
				
			||||||
@@ -860,6 +838,8 @@ int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
 | 
				
			|||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
	GprsMs *old_ms;
 | 
						GprsMs *old_ms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(direction == GPRS_RLCMAC_UL_TBF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* no TLLI yet */
 | 
						/* no TLLI yet */
 | 
				
			||||||
	if (!rh->ti) {
 | 
						if (!rh->ti) {
 | 
				
			||||||
		LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TFI=%d without "
 | 
							LOGP(DRLCMACUL, LOGL_NOTICE, "UL DATA TFI=%d without "
 | 
				
			||||||
@@ -880,15 +860,20 @@ int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
 | 
				
			|||||||
		dl_tbf = old_ms->dl_tbf();
 | 
							dl_tbf = old_ms->dl_tbf();
 | 
				
			||||||
		ul_tbf = old_ms->ul_tbf();
 | 
							ul_tbf = old_ms->ul_tbf();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		set_ms(old_ms);
 | 
							if (!ms())
 | 
				
			||||||
 | 
								set_ms(old_ms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* there might be an active and valid downlink TBF */
 | 
				
			||||||
 | 
							if (!ms()->dl_tbf() && dl_tbf)
 | 
				
			||||||
 | 
								/* Move it to the current MS */
 | 
				
			||||||
 | 
								dl_tbf->set_ms(ms());
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	update_tlli(new_tlli);
 | 
					 | 
				
			||||||
	/* The TLLI has been taken from an UL message */
 | 
						/* The TLLI has been taken from an UL message */
 | 
				
			||||||
	update_ms(new_tlli, GPRS_RLCMAC_UL_TBF);
 | 
						update_ms(new_tlli, GPRS_RLCMAC_UL_TBF);
 | 
				
			||||||
	LOGP(DRLCMACUL, LOGL_INFO, "Decoded premier TLLI=0x%08x of "
 | 
						LOGP(DRLCMACUL, LOGL_INFO, "Decoded premier TLLI=0x%08x of "
 | 
				
			||||||
		"UL DATA TFI=%d.\n", tlli(), rh->tfi);
 | 
							"UL DATA TFI=%d.\n", tlli(), rh->tfi);
 | 
				
			||||||
	if (dl_tbf) {
 | 
						if (dl_tbf && dl_tbf->ms() != ms()) {
 | 
				
			||||||
		LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
 | 
							LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
 | 
				
			||||||
			"TLLI=0x%08x while %s still exists. "
 | 
								"TLLI=0x%08x while %s still exists. "
 | 
				
			||||||
			"Killing pending DL TBF\n", tlli(),
 | 
								"Killing pending DL TBF\n", tlli(),
 | 
				
			||||||
@@ -896,7 +881,7 @@ int gprs_rlcmac_tbf::extract_tlli(const uint8_t *data, const size_t len)
 | 
				
			|||||||
		tbf_free(dl_tbf);
 | 
							tbf_free(dl_tbf);
 | 
				
			||||||
		dl_tbf = NULL;
 | 
							dl_tbf = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (ul_tbf) {
 | 
						if (ul_tbf && ul_tbf->ms() != ms()) {
 | 
				
			||||||
		LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
 | 
							LOGP(DRLCMACUL, LOGL_NOTICE, "Got RACH from "
 | 
				
			||||||
			"TLLI=0x%08x while %s still exists. "
 | 
								"TLLI=0x%08x while %s still exists. "
 | 
				
			||||||
			"Killing pending UL TBF\n", tlli(),
 | 
								"Killing pending UL TBF\n", tlli(),
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										15
									
								
								src/tbf.h
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								src/tbf.h
									
									
									
									
									
								
							@@ -30,6 +30,7 @@
 | 
				
			|||||||
struct bssgp_bvc_ctx;
 | 
					struct bssgp_bvc_ctx;
 | 
				
			||||||
struct rlc_ul_header;
 | 
					struct rlc_ul_header;
 | 
				
			||||||
struct msgb;
 | 
					struct msgb;
 | 
				
			||||||
 | 
					struct pcu_l1_meas;
 | 
				
			||||||
class GprsMs;
 | 
					class GprsMs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
@@ -138,7 +139,6 @@ struct gprs_rlcmac_tbf {
 | 
				
			|||||||
	void poll_timeout();
 | 
						void poll_timeout();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** tlli handling */
 | 
						/** tlli handling */
 | 
				
			||||||
	void update_tlli(uint32_t tlli);
 | 
					 | 
				
			||||||
	uint32_t tlli() const;
 | 
						uint32_t tlli() const;
 | 
				
			||||||
	bool is_tlli_valid() const;
 | 
						bool is_tlli_valid() const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -240,16 +240,15 @@ private:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
 | 
					struct gprs_rlcmac_ul_tbf *tbf_alloc_ul(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	int8_t use_trx, uint8_t ms_class,
 | 
						int8_t use_trx, uint8_t ms_class,
 | 
				
			||||||
	uint32_t tlli, uint8_t ta, struct gprs_rlcmac_tbf *dl_tbf);
 | 
						uint32_t tlli, uint8_t ta, GprsMs *ms);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 | 
					struct gprs_rlcmac_ul_tbf *tbf_alloc_ul_tbf(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *old_tbf,
 | 
						GprsMs *ms,
 | 
				
			||||||
	uint8_t tfi, uint8_t trx,
 | 
						uint8_t tfi, uint8_t trx,
 | 
				
			||||||
	uint8_t ms_class, uint8_t single_slot);
 | 
						uint8_t ms_class, uint8_t single_slot);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
 | 
					struct gprs_rlcmac_dl_tbf *tbf_alloc_dl_tbf(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
	struct gprs_rlcmac_tbf *old_tbf,
 | 
						GprsMs *ms, uint8_t tfi, uint8_t trx,
 | 
				
			||||||
	uint8_t tfi, uint8_t trx,
 | 
					 | 
				
			||||||
	uint8_t ms_class, uint8_t single_slot);
 | 
						uint8_t ms_class, uint8_t single_slot);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void tbf_free(struct gprs_rlcmac_tbf *tbf);
 | 
					void tbf_free(struct gprs_rlcmac_tbf *tbf);
 | 
				
			||||||
@@ -361,9 +360,10 @@ protected:
 | 
				
			|||||||
	int update_window(const uint8_t ssn, const uint8_t *rbb);
 | 
						int update_window(const uint8_t ssn, const uint8_t *rbb);
 | 
				
			||||||
	int maybe_start_new_window();
 | 
						int maybe_start_new_window();
 | 
				
			||||||
	bool dl_window_stalled() const;
 | 
						bool dl_window_stalled() const;
 | 
				
			||||||
	void reuse_tbf(const uint8_t *data, const uint16_t len);
 | 
						void reuse_tbf();
 | 
				
			||||||
	void start_llc_timer();
 | 
						void start_llc_timer();
 | 
				
			||||||
	int analyse_errors(char *show_rbb, uint8_t ssn);
 | 
						int analyse_errors(char *show_rbb, uint8_t ssn);
 | 
				
			||||||
 | 
						void schedule_next_frame();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct osmo_timer_list m_llc_timer;
 | 
						struct osmo_timer_list m_llc_timer;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -372,7 +372,8 @@ struct gprs_rlcmac_ul_tbf : public gprs_rlcmac_tbf {
 | 
				
			|||||||
	struct msgb *create_ul_ack(uint32_t fn);
 | 
						struct msgb *create_ul_ack(uint32_t fn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* blocks were acked */
 | 
						/* blocks were acked */
 | 
				
			||||||
	int rcv_data_block_acknowledged(const uint8_t *data, size_t len, int8_t rssi);
 | 
						int rcv_data_block_acknowledged(const uint8_t *data, size_t len,
 | 
				
			||||||
 | 
							struct pcu_l1_meas *meas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* TODO: extract LLC class? */
 | 
						/* TODO: extract LLC class? */
 | 
				
			||||||
	int assemble_forward_llc(const gprs_rlc_data *data);
 | 
						int assemble_forward_llc(const gprs_rlc_data *data);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										145
									
								
								src/tbf_dl.cpp
									
									
									
									
									
								
							
							
						
						
									
										145
									
								
								src/tbf_dl.cpp
									
									
									
									
									
								
							@@ -99,36 +99,24 @@ int gprs_rlcmac_dl_tbf::append_data(const uint8_t ms_class,
 | 
				
			|||||||
				const uint8_t *data, const uint16_t len)
 | 
									const uint8_t *data, const uint16_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	LOGP(DRLCMAC, LOGL_INFO, "%s append\n", tbf_name(this));
 | 
						LOGP(DRLCMAC, LOGL_INFO, "%s append\n", tbf_name(this));
 | 
				
			||||||
 | 
						gprs_llc_queue::MetaInfo info;
 | 
				
			||||||
 | 
						struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue");
 | 
				
			||||||
 | 
						if (!llc_msg)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gprs_llc_queue::calc_pdu_lifetime(bts, pdu_delay_csec, &info.expire_time);
 | 
				
			||||||
 | 
						gettimeofday(&info.recv_time, NULL);
 | 
				
			||||||
 | 
						memcpy(msgb_put(llc_msg, len), data, len);
 | 
				
			||||||
 | 
						llc_queue()->enqueue(llc_msg, &info);
 | 
				
			||||||
 | 
						tbf_update_ms_class(this, ms_class);
 | 
				
			||||||
 | 
						start_llc_timer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (state_is(GPRS_RLCMAC_WAIT_RELEASE)) {
 | 
						if (state_is(GPRS_RLCMAC_WAIT_RELEASE)) {
 | 
				
			||||||
		LOGP(DRLCMAC, LOGL_DEBUG,
 | 
							LOGP(DRLCMAC, LOGL_DEBUG,
 | 
				
			||||||
			"%s in WAIT RELEASE state "
 | 
								"%s in WAIT RELEASE state "
 | 
				
			||||||
			"(T3193), so reuse TBF\n", tbf_name(this));
 | 
								"(T3193), so reuse TBF\n", tbf_name(this));
 | 
				
			||||||
		tbf_update_ms_class(this, ms_class);
 | 
							tbf_update_ms_class(this, ms_class);
 | 
				
			||||||
		reuse_tbf(data, len);
 | 
							reuse_tbf();
 | 
				
			||||||
	} else if (!have_data()) {
 | 
					 | 
				
			||||||
		m_llc.put_frame(data, len);
 | 
					 | 
				
			||||||
		bts->llc_frame_sched();
 | 
					 | 
				
			||||||
		/* it is no longer drained */
 | 
					 | 
				
			||||||
		m_last_dl_drained_fn = -1;
 | 
					 | 
				
			||||||
		tbf_update_ms_class(this, ms_class);
 | 
					 | 
				
			||||||
		start_llc_timer();
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		/* TODO: put this path into an llc_enqueue method */
 | 
					 | 
				
			||||||
		/* the TBF exists, so we must write it in the queue
 | 
					 | 
				
			||||||
		 * we prepend lifetime in front of PDU */
 | 
					 | 
				
			||||||
		struct timeval *tv;
 | 
					 | 
				
			||||||
		struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv) * 2,
 | 
					 | 
				
			||||||
			"llc_pdu_queue");
 | 
					 | 
				
			||||||
		if (!llc_msg)
 | 
					 | 
				
			||||||
			return -ENOMEM;
 | 
					 | 
				
			||||||
		tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
 | 
					 | 
				
			||||||
		gprs_llc_queue::calc_pdu_lifetime(bts, pdu_delay_csec, tv);
 | 
					 | 
				
			||||||
		tv = (struct timeval *)msgb_put(llc_msg, sizeof(*tv));
 | 
					 | 
				
			||||||
		gettimeofday(tv, NULL);
 | 
					 | 
				
			||||||
		memcpy(msgb_put(llc_msg, len), data, len);
 | 
					 | 
				
			||||||
		llc_queue()->enqueue(llc_msg);
 | 
					 | 
				
			||||||
		tbf_update_ms_class(this, ms_class);
 | 
					 | 
				
			||||||
		start_llc_timer();
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
@@ -149,7 +137,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
				const char *imsi,
 | 
									const char *imsi,
 | 
				
			||||||
				const uint32_t tlli, const uint32_t tlli_old,
 | 
									const uint32_t tlli, const uint32_t tlli_old,
 | 
				
			||||||
				const uint8_t ms_class,
 | 
									const uint8_t ms_class,
 | 
				
			||||||
				const uint8_t *data, const uint16_t len)
 | 
									struct gprs_rlcmac_dl_tbf **tbf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t trx, ss;
 | 
						uint8_t trx, ss;
 | 
				
			||||||
	int8_t use_trx;
 | 
						int8_t use_trx;
 | 
				
			||||||
@@ -167,6 +155,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
		ul_tbf = ms->ul_tbf();
 | 
							ul_tbf = ms->ul_tbf();
 | 
				
			||||||
		ta = ms->ta();
 | 
							ta = ms->ta();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						/* TODO: if (!ms) create MS before tbf_alloc is called? */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (ul_tbf && ul_tbf->m_contention_resolution_done
 | 
						if (ul_tbf && ul_tbf->m_contention_resolution_done
 | 
				
			||||||
	 && !ul_tbf->m_final_ack_sent) {
 | 
						 && !ul_tbf->m_final_ack_sent) {
 | 
				
			||||||
@@ -184,13 +173,10 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
	tfi = bts->bts->tfi_find_free(GPRS_RLCMAC_DL_TBF, &trx, use_trx);
 | 
						tfi = bts->bts->tfi_find_free(GPRS_RLCMAC_DL_TBF, &trx, use_trx);
 | 
				
			||||||
	if (tfi >= 0)
 | 
						if (tfi >= 0)
 | 
				
			||||||
		/* set number of downlink slots according to multislot class */
 | 
							/* set number of downlink slots according to multislot class */
 | 
				
			||||||
		dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf, tfi, trx, ms_class, ss);
 | 
							dl_tbf = tbf_alloc_dl_tbf(bts, ms, tfi, trx, ms_class, ss);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!dl_tbf) {
 | 
						if (!dl_tbf) {
 | 
				
			||||||
		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
 | 
							LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
 | 
				
			||||||
		bssgp_tx_llc_discarded(gprs_bssgp_pcu_current_bctx(), tlli,
 | 
					 | 
				
			||||||
			1, len);
 | 
					 | 
				
			||||||
		bts->bts->llc_dropped_frame();
 | 
					 | 
				
			||||||
		return -EBUSY;
 | 
							return -EBUSY;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
 | 
						dl_tbf->update_ms(tlli, GPRS_RLCMAC_DL_TBF);
 | 
				
			||||||
@@ -198,10 +184,6 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	LOGP(DRLCMAC, LOGL_DEBUG, "%s [DOWNLINK] START\n", tbf_name(dl_tbf));
 | 
						LOGP(DRLCMAC, LOGL_DEBUG, "%s [DOWNLINK] START\n", tbf_name(dl_tbf));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* new TBF, so put first frame */
 | 
					 | 
				
			||||||
	dl_tbf->m_llc.put_frame(data, len);
 | 
					 | 
				
			||||||
	dl_tbf->bts->llc_frame_sched();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Store IMSI for later look-up and PCH retransmission */
 | 
						/* Store IMSI for later look-up and PCH retransmission */
 | 
				
			||||||
	dl_tbf->assign_imsi(imsi);
 | 
						dl_tbf->assign_imsi(imsi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -210,6 +192,7 @@ static int tbf_new_dl_assignment(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
	 * to trigger downlink assignment. if there is no uplink,
 | 
						 * to trigger downlink assignment. if there is no uplink,
 | 
				
			||||||
	 * AGCH is used. */
 | 
						 * AGCH is used. */
 | 
				
			||||||
	dl_tbf->bts->trigger_dl_ass(dl_tbf, old_ul_tbf);
 | 
						dl_tbf->bts->trigger_dl_ass(dl_tbf, old_ul_tbf);
 | 
				
			||||||
 | 
						*tbf = dl_tbf;
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -222,30 +205,40 @@ int gprs_rlcmac_dl_tbf::handle(struct gprs_rlcmac_bts *bts,
 | 
				
			|||||||
		const uint8_t *data, const uint16_t len)
 | 
							const uint8_t *data, const uint16_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct gprs_rlcmac_dl_tbf *dl_tbf;
 | 
						struct gprs_rlcmac_dl_tbf *dl_tbf;
 | 
				
			||||||
 | 
						int rc;
 | 
				
			||||||
 | 
						GprsMs *ms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check for existing TBF */
 | 
						/* check for existing TBF */
 | 
				
			||||||
	dl_tbf = tbf_lookup_dl(bts->bts, tlli, tlli_old, imsi);
 | 
						dl_tbf = tbf_lookup_dl(bts->bts, tlli, tlli_old, imsi);
 | 
				
			||||||
	if (dl_tbf) {
 | 
						if (!dl_tbf) {
 | 
				
			||||||
		int rc = dl_tbf->append_data(ms_class, delay_csec, data, len);
 | 
							rc = tbf_new_dl_assignment(bts, imsi, tlli, tlli_old, ms_class,
 | 
				
			||||||
		if (rc >= 0)
 | 
								&dl_tbf);
 | 
				
			||||||
			dl_tbf->assign_imsi(imsi);
 | 
							if (rc < 0)
 | 
				
			||||||
 | 
								return rc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (dl_tbf->ms())
 | 
						OSMO_ASSERT(dl_tbf->ms() != NULL);
 | 
				
			||||||
			dl_tbf->ms()->confirm_tlli(tlli);
 | 
						ms = dl_tbf->ms();
 | 
				
			||||||
		return rc;
 | 
						GprsMs::Guard guard(ms);
 | 
				
			||||||
	} 
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return tbf_new_dl_assignment(bts, imsi, tlli, tlli_old, ms_class, data, len);
 | 
						rc = dl_tbf->append_data(ms_class, delay_csec, data, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dl_tbf = ms->dl_tbf();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dl_tbf->assign_imsi(imsi);
 | 
				
			||||||
 | 
						ms->confirm_tlli(tlli);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rc;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
 | 
					struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg;
 | 
						struct msgb *msg;
 | 
				
			||||||
	struct timeval *tv_recv, *tv_disc;
 | 
					 | 
				
			||||||
	struct timeval tv_now, tv_now2;
 | 
						struct timeval tv_now, tv_now2;
 | 
				
			||||||
	uint32_t octets = 0, frames = 0;
 | 
						uint32_t octets = 0, frames = 0;
 | 
				
			||||||
	struct timeval hyst_delta = {0, 0};
 | 
						struct timeval hyst_delta = {0, 0};
 | 
				
			||||||
	const unsigned keep_small_thresh = 60;
 | 
						const unsigned keep_small_thresh = 60;
 | 
				
			||||||
 | 
						const gprs_llc_queue::MetaInfo *info;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (bts_data()->llc_discard_csec)
 | 
						if (bts_data()->llc_discard_csec)
 | 
				
			||||||
		csecs_to_timeval(bts_data()->llc_discard_csec, &hyst_delta);
 | 
							csecs_to_timeval(bts_data()->llc_discard_csec, &hyst_delta);
 | 
				
			||||||
@@ -253,11 +246,9 @@ struct msgb *gprs_rlcmac_dl_tbf::llc_dequeue(bssgp_bvc_ctx *bctx)
 | 
				
			|||||||
	gettimeofday(&tv_now, NULL);
 | 
						gettimeofday(&tv_now, NULL);
 | 
				
			||||||
	timeradd(&tv_now, &hyst_delta, &tv_now2);
 | 
						timeradd(&tv_now, &hyst_delta, &tv_now2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while ((msg = llc_queue()->dequeue())) {
 | 
						while ((msg = llc_queue()->dequeue(&info))) {
 | 
				
			||||||
		tv_disc = (struct timeval *)msg->data;
 | 
							const struct timeval *tv_disc = &info->expire_time;
 | 
				
			||||||
		msgb_pull(msg, sizeof(*tv_disc));
 | 
							const struct timeval *tv_recv = &info->recv_time;
 | 
				
			||||||
		tv_recv = (struct timeval *)msg->data;
 | 
					 | 
				
			||||||
		msgb_pull(msg, sizeof(*tv_recv));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		gprs_bssgp_update_queue_delay(tv_recv, &tv_now);
 | 
							gprs_bssgp_update_queue_delay(tv_recv, &tv_now);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -385,22 +376,46 @@ do_resend:
 | 
				
			|||||||
	goto do_resend;
 | 
						goto do_resend;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void gprs_rlcmac_dl_tbf::schedule_next_frame()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (m_llc.frame_length() != 0)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* dequeue next LLC frame, if any */
 | 
				
			||||||
 | 
						msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
 | 
				
			||||||
 | 
						if (!msg)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DRLCMACDL, LOGL_INFO,
 | 
				
			||||||
 | 
							"- Dequeue next LLC for %s (len=%d)\n",
 | 
				
			||||||
 | 
							tbf_name(this), msg->len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m_llc.put_frame(msg->data, msg->len);
 | 
				
			||||||
 | 
						bts->llc_frame_sched();
 | 
				
			||||||
 | 
						msgb_free(msg);
 | 
				
			||||||
 | 
						m_last_dl_drained_fn = -1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t ts)
 | 
					struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t ts)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rlc_dl_header *rh;
 | 
						struct rlc_dl_header *rh;
 | 
				
			||||||
	struct rlc_li_field *li;
 | 
						struct rlc_li_field *li;
 | 
				
			||||||
	struct msgb *msg;
 | 
					 | 
				
			||||||
	uint8_t *delimiter, *data, *e_pointer;
 | 
						uint8_t *delimiter, *data, *e_pointer;
 | 
				
			||||||
	uint16_t space, chunk;
 | 
						uint16_t space, chunk;
 | 
				
			||||||
	gprs_rlc_data *rlc_data;
 | 
						gprs_rlc_data *rlc_data;
 | 
				
			||||||
	const uint16_t bsn = m_window.v_s();
 | 
						const uint16_t bsn = m_window.v_s();
 | 
				
			||||||
	uint8_t cs = 1;
 | 
						uint8_t cs = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d\n",
 | 
						if (m_llc.frame_length() == 0)
 | 
				
			||||||
		m_window.v_s());
 | 
							schedule_next_frame();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cs = current_cs();
 | 
						cs = current_cs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						LOGP(DRLCMACDL, LOGL_DEBUG, "- Sending new block at BSN %d, CS=%d\n",
 | 
				
			||||||
 | 
							m_window.v_s(), cs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	OSMO_ASSERT(cs >= 1);
 | 
						OSMO_ASSERT(cs >= 1);
 | 
				
			||||||
	OSMO_ASSERT(cs <= 4);
 | 
						OSMO_ASSERT(cs <= 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -535,15 +550,7 @@ struct msgb *gprs_rlcmac_dl_tbf::create_new_bsn(const uint32_t fn, const uint8_t
 | 
				
			|||||||
		gprs_rlcmac_dl_bw(this, m_llc.frame_length());
 | 
							gprs_rlcmac_dl_bw(this, m_llc.frame_length());
 | 
				
			||||||
		m_llc.reset();
 | 
							m_llc.reset();
 | 
				
			||||||
		/* dequeue next LLC frame, if any */
 | 
							/* dequeue next LLC frame, if any */
 | 
				
			||||||
		msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
 | 
							schedule_next_frame();
 | 
				
			||||||
		if (msg) {
 | 
					 | 
				
			||||||
			LOGP(DRLCMACDL, LOGL_INFO, "- Dequeue next LLC for "
 | 
					 | 
				
			||||||
				"%s (len=%d)\n", tbf_name(this), msg->len);
 | 
					 | 
				
			||||||
			m_llc.put_frame(msg->data, msg->len);
 | 
					 | 
				
			||||||
			bts->llc_frame_sched();
 | 
					 | 
				
			||||||
			msgb_free(msg);
 | 
					 | 
				
			||||||
			m_last_dl_drained_fn = -1;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		/* if we have more data and we have space left */
 | 
							/* if we have more data and we have space left */
 | 
				
			||||||
		if (space > 0 && (m_llc.frame_length() || keep_open(fn))) {
 | 
							if (space > 0 && (m_llc.frame_length() || keep_open(fn))) {
 | 
				
			||||||
			li->m = 1; /* we indicate more frames to follow */
 | 
								li->m = 1; /* we indicate more frames to follow */
 | 
				
			||||||
@@ -796,7 +803,6 @@ int gprs_rlcmac_dl_tbf::update_window(const uint8_t ssn, const uint8_t *rbb)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
int gprs_rlcmac_dl_tbf::maybe_start_new_window()
 | 
					int gprs_rlcmac_dl_tbf::maybe_start_new_window()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct msgb *msg;
 | 
					 | 
				
			||||||
	uint16_t received;
 | 
						uint16_t received;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
 | 
						LOGP(DRLCMACDL, LOGL_DEBUG, "- Final ACK received.\n");
 | 
				
			||||||
@@ -809,8 +815,7 @@ int gprs_rlcmac_dl_tbf::maybe_start_new_window()
 | 
				
			|||||||
	set_state(GPRS_RLCMAC_WAIT_RELEASE);
 | 
						set_state(GPRS_RLCMAC_WAIT_RELEASE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check for LLC PDU in the LLC Queue */
 | 
						/* check for LLC PDU in the LLC Queue */
 | 
				
			||||||
	msg = llc_dequeue(gprs_bssgp_pcu_current_bctx());
 | 
						if (!have_data()) {
 | 
				
			||||||
	if (!msg) {
 | 
					 | 
				
			||||||
		/* no message, start T3193, change state to RELEASE */
 | 
							/* no message, start T3193, change state to RELEASE */
 | 
				
			||||||
		LOGP(DRLCMACDL, LOGL_DEBUG, "- No new message, so we release.\n");
 | 
							LOGP(DRLCMACDL, LOGL_DEBUG, "- No new message, so we release.\n");
 | 
				
			||||||
		/* start T3193 */
 | 
							/* start T3193 */
 | 
				
			||||||
@@ -822,8 +827,7 @@ int gprs_rlcmac_dl_tbf::maybe_start_new_window()
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* we have more data so we will re-use this tbf */
 | 
						/* we have more data so we will re-use this tbf */
 | 
				
			||||||
	reuse_tbf(msg->data, msg->len);
 | 
						reuse_tbf();
 | 
				
			||||||
	msgb_free(msg);
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -836,7 +840,7 @@ int gprs_rlcmac_dl_tbf::rcvd_dl_ack(uint8_t final_ack, uint8_t ssn, uint8_t *rbb
 | 
				
			|||||||
	return maybe_start_new_window();
 | 
						return maybe_start_new_window();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void gprs_rlcmac_dl_tbf::reuse_tbf(const uint8_t *data, const uint16_t len)
 | 
					void gprs_rlcmac_dl_tbf::reuse_tbf()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint8_t trx;
 | 
						uint8_t trx;
 | 
				
			||||||
	struct gprs_rlcmac_dl_tbf *new_tbf = NULL;
 | 
						struct gprs_rlcmac_dl_tbf *new_tbf = NULL;
 | 
				
			||||||
@@ -851,18 +855,11 @@ void gprs_rlcmac_dl_tbf::reuse_tbf(const uint8_t *data, const uint16_t len)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if (!new_tbf) {
 | 
						if (!new_tbf) {
 | 
				
			||||||
		LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
 | 
							LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH resource\n");
 | 
				
			||||||
		bssgp_tx_llc_discarded(gprs_bssgp_pcu_current_bctx(), tlli(),
 | 
					 | 
				
			||||||
			1, len);
 | 
					 | 
				
			||||||
		bts->llc_dropped_frame();
 | 
					 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	new_tbf->set_ms(ms());
 | 
						new_tbf->set_ms(ms());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Start with the passed frame */
 | 
					 | 
				
			||||||
	new_tbf->m_llc.put_frame(data, len);
 | 
					 | 
				
			||||||
	bts->llc_frame_sched();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* reset rlc states */
 | 
						/* reset rlc states */
 | 
				
			||||||
	m_tx_counter = 0;
 | 
						m_tx_counter = 0;
 | 
				
			||||||
	m_wait_confirm = 0;
 | 
						m_wait_confirm = 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,6 +27,7 @@
 | 
				
			|||||||
#include <gprs_debug.h>
 | 
					#include <gprs_debug.h>
 | 
				
			||||||
#include <gprs_bssgp_pcu.h>
 | 
					#include <gprs_bssgp_pcu.h>
 | 
				
			||||||
#include <decoding.h>
 | 
					#include <decoding.h>
 | 
				
			||||||
 | 
					#include <pcu_l1_if.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
#include <osmocom/core/msgb.h>
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
@@ -261,10 +262,12 @@ struct msgb *gprs_rlcmac_ul_tbf::create_ul_ack(uint32_t fn)
 | 
				
			|||||||
	return msg;
 | 
						return msg;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(const uint8_t *data, size_t len, int8_t rssi)
 | 
					int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(const uint8_t *data,
 | 
				
			||||||
 | 
						size_t len, struct pcu_l1_meas *meas)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
 | 
						struct rlc_ul_header *rh = (struct rlc_ul_header *)data;
 | 
				
			||||||
	int rc;
 | 
						int rc;
 | 
				
			||||||
 | 
						int8_t rssi = meas->have_rssi ? meas->rssi : 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const uint16_t mod_sns = m_window.mod_sns();
 | 
						const uint16_t mod_sns = m_window.mod_sns();
 | 
				
			||||||
	const uint16_t ws = m_window.ws();
 | 
						const uint16_t ws = m_window.ws();
 | 
				
			||||||
@@ -278,6 +281,10 @@ int gprs_rlcmac_ul_tbf::rcv_data_block_acknowledged(const uint8_t *data, size_t
 | 
				
			|||||||
	/* process RSSI */
 | 
						/* process RSSI */
 | 
				
			||||||
	gprs_rlcmac_rssi(this, rssi);
 | 
						gprs_rlcmac_rssi(this, rssi);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* store measurement values */
 | 
				
			||||||
 | 
						if (ms())
 | 
				
			||||||
 | 
							ms()->update_l1_meas(meas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* get TLLI */
 | 
						/* get TLLI */
 | 
				
			||||||
	if (!this->is_tlli_valid()) {
 | 
						if (!this->is_tlli_valid()) {
 | 
				
			||||||
		if (!extract_tlli(data, len))
 | 
							if (!extract_tlli(data, len))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,6 @@
 | 
				
			|||||||
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/
 | 
					AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(LIBOSMOCORE_CFLAGS) $(LIBOSMOGB_CFLAGS) $(LIBOSMOGSM_CFLAGS) -I$(top_srcdir)/src/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest
 | 
					check_PROGRAMS = rlcmac/RLCMACTest alloc/AllocTest tbf/TbfTest types/TypesTest ms/MsTest llist/LListTest llc/LlcTest
 | 
				
			||||||
noinst_PROGRAMS = emu/pcu_emu
 | 
					noinst_PROGRAMS = emu/pcu_emu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp
 | 
					rlcmac_RLCMACTest_SOURCES = rlcmac/RLCMACTest.cpp
 | 
				
			||||||
@@ -54,6 +54,17 @@ ms_MsTest_LDADD = \
 | 
				
			|||||||
ms_MsTest_LDFLAGS = \
 | 
					ms_MsTest_LDFLAGS = \
 | 
				
			||||||
	-Wl,-u,bssgp_prim_cb
 | 
						-Wl,-u,bssgp_prim_cb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					llc_LlcTest_SOURCES = llc/LlcTest.cpp
 | 
				
			||||||
 | 
					llc_LlcTest_LDADD = \
 | 
				
			||||||
 | 
						$(top_builddir)/src/libgprs.la \
 | 
				
			||||||
 | 
						$(LIBOSMOGB_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOGSM_LIBS) \
 | 
				
			||||||
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
 | 
						$(COMMON_LA)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					llc_LlcTest_LDFLAGS = \
 | 
				
			||||||
 | 
						-Wl,-u,bssgp_prim_cb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
llist_LListTest_SOURCES = llist/LListTest.cpp
 | 
					llist_LListTest_SOURCES = llist/LListTest.cpp
 | 
				
			||||||
llist_LListTest_LDADD = \
 | 
					llist_LListTest_LDADD = \
 | 
				
			||||||
	$(LIBOSMOCORE_LIBS) \
 | 
						$(LIBOSMOCORE_LIBS) \
 | 
				
			||||||
@@ -84,6 +95,7 @@ EXTRA_DIST = \
 | 
				
			|||||||
	tbf/TbfTest.ok tbf/TbfTest.err \
 | 
						tbf/TbfTest.ok tbf/TbfTest.err \
 | 
				
			||||||
	types/TypesTest.ok types/TypesTest.err \
 | 
						types/TypesTest.ok types/TypesTest.err \
 | 
				
			||||||
	ms/MsTest.ok ms/MsTest.err \
 | 
						ms/MsTest.ok ms/MsTest.err \
 | 
				
			||||||
 | 
						llc/LlcTest.ok llc/LlcTest.err \
 | 
				
			||||||
	llist/LListTest.ok llist/LListTest.err
 | 
						llist/LListTest.ok llist/LListTest.err
 | 
				
			||||||
 | 
					
 | 
				
			||||||
DISTCLEANFILES = atconfig
 | 
					DISTCLEANFILES = atconfig
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,14 +37,14 @@ void *tall_pcu_ctx;
 | 
				
			|||||||
int16_t spoof_mnc = 0, spoof_mcc = 0;
 | 
					int16_t spoof_mnc = 0, spoof_mcc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_bts *bts,
 | 
					static gprs_rlcmac_tbf *tbf_alloc(struct gprs_rlcmac_bts *bts,
 | 
				
			||||||
		struct gprs_rlcmac_tbf *old_tbf, gprs_rlcmac_tbf_direction dir,
 | 
							GprsMs *ms, gprs_rlcmac_tbf_direction dir,
 | 
				
			||||||
		uint8_t tfi, uint8_t trx,
 | 
							uint8_t tfi, uint8_t trx,
 | 
				
			||||||
		uint8_t ms_class, uint8_t single_slot)
 | 
							uint8_t ms_class, uint8_t single_slot)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (dir == GPRS_RLCMAC_UL_TBF)
 | 
						if (dir == GPRS_RLCMAC_UL_TBF)
 | 
				
			||||||
		return tbf_alloc_ul_tbf(bts, old_tbf, tfi, trx, ms_class, single_slot);
 | 
							return tbf_alloc_ul_tbf(bts, ms, tfi, trx, ms_class, single_slot);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return tbf_alloc_dl_tbf(bts, old_tbf, tfi, trx, ms_class, single_slot);
 | 
							return tbf_alloc_dl_tbf(bts, ms, tfi, trx, ms_class, single_slot);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_alloc_a(gprs_rlcmac_tbf_direction dir, const int count)
 | 
					static void test_alloc_a(gprs_rlcmac_tbf_direction dir, const int count)
 | 
				
			||||||
@@ -152,7 +152,7 @@ static void test_alloc_b(int ms_class)
 | 
				
			|||||||
		/* assume final ack has not been sent */
 | 
							/* assume final ack has not been sent */
 | 
				
			||||||
		tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 | 
							tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 | 
				
			||||||
		OSMO_ASSERT(tfi >= 0);
 | 
							OSMO_ASSERT(tfi >= 0);
 | 
				
			||||||
		dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf, tfi, trx_no, ms_class, 0);
 | 
							dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), tfi, trx_no, ms_class, 0);
 | 
				
			||||||
		OSMO_ASSERT(dl_tbf);
 | 
							OSMO_ASSERT(dl_tbf);
 | 
				
			||||||
		dump_assignment(dl_tbf, "DL");
 | 
							dump_assignment(dl_tbf, "DL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -194,7 +194,7 @@ static void test_alloc_b(int ms_class)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 | 
							tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 | 
				
			||||||
		OSMO_ASSERT(tfi >= 0);
 | 
							OSMO_ASSERT(tfi >= 0);
 | 
				
			||||||
		ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf, tfi, trx_no, ms_class, 0);
 | 
							ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf->ms(), tfi, trx_no, ms_class, 0);
 | 
				
			||||||
		ul_tbf->update_ms(0x23, GPRS_RLCMAC_UL_TBF);
 | 
							ul_tbf->update_ms(0x23, GPRS_RLCMAC_UL_TBF);
 | 
				
			||||||
		ul_tbf->m_contention_resolution_done = 1;
 | 
							ul_tbf->m_contention_resolution_done = 1;
 | 
				
			||||||
		OSMO_ASSERT(ul_tbf);
 | 
							OSMO_ASSERT(ul_tbf);
 | 
				
			||||||
@@ -241,7 +241,7 @@ static void test_alloc_b(int ms_class)
 | 
				
			|||||||
		/* assume final ack has not been sent */
 | 
							/* assume final ack has not been sent */
 | 
				
			||||||
		tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 | 
							tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 | 
				
			||||||
		OSMO_ASSERT(tfi >= 0);
 | 
							OSMO_ASSERT(tfi >= 0);
 | 
				
			||||||
		dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf, tfi, trx_no, ms_class, 0);
 | 
							dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), tfi, trx_no, ms_class, 0);
 | 
				
			||||||
		OSMO_ASSERT(dl_tbf);
 | 
							OSMO_ASSERT(dl_tbf);
 | 
				
			||||||
		dump_assignment(dl_tbf, "DL");
 | 
							dump_assignment(dl_tbf, "DL");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -304,7 +304,7 @@ static void test_alloc_b(bool ts0, bool ts1, bool ts2, bool ts3, bool ts4, bool
 | 
				
			|||||||
		/* assume final ack has not been sent */
 | 
							/* assume final ack has not been sent */
 | 
				
			||||||
		tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 | 
							tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 | 
				
			||||||
		OSMO_ASSERT(tfi >= 0);
 | 
							OSMO_ASSERT(tfi >= 0);
 | 
				
			||||||
		dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf, tfi, trx_no, ms_class, 0);
 | 
							dl_tbf = tbf_alloc_dl_tbf(bts, ul_tbf->ms(), tfi, trx_no, ms_class, 0);
 | 
				
			||||||
		OSMO_ASSERT(dl_tbf);
 | 
							OSMO_ASSERT(dl_tbf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* verify that both are on the same ts */
 | 
							/* verify that both are on the same ts */
 | 
				
			||||||
@@ -348,7 +348,7 @@ static void test_alloc_b(bool ts0, bool ts1, bool ts2, bool ts3, bool ts4, bool
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 | 
							tfi = the_bts.tfi_find_free(GPRS_RLCMAC_UL_TBF, &trx_no, -1);
 | 
				
			||||||
		OSMO_ASSERT(tfi >= 0);
 | 
							OSMO_ASSERT(tfi >= 0);
 | 
				
			||||||
		ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf, tfi, trx_no, ms_class, 0);
 | 
							ul_tbf = tbf_alloc_ul_tbf(bts, dl_tbf->ms(), tfi, trx_no, ms_class, 0);
 | 
				
			||||||
		OSMO_ASSERT(ul_tbf);
 | 
							OSMO_ASSERT(ul_tbf);
 | 
				
			||||||
		ul_tbf->update_ms(0x23, GPRS_RLCMAC_UL_TBF);
 | 
							ul_tbf->update_ms(0x23, GPRS_RLCMAC_UL_TBF);
 | 
				
			||||||
		ul_tbf->m_contention_resolution_done = 1;
 | 
							ul_tbf->m_contention_resolution_done = 1;
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										211
									
								
								tests/llc/LlcTest.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								tests/llc/LlcTest.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,211 @@
 | 
				
			|||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * LlcTest.cpp
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 by Sysmocom s.f.m.c. GmbH
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * All Rights Reserved
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is free software; you can redistribute it and/or modify
 | 
				
			||||||
 | 
					 * it under the terms of the GNU Affero General Public License as published by
 | 
				
			||||||
 | 
					 * the Free Software Foundation; either version 3 of the License, or
 | 
				
			||||||
 | 
					 * (at your option) any later version.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This program is distributed in the hope that it will be useful,
 | 
				
			||||||
 | 
					 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
				
			||||||
 | 
					 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
				
			||||||
 | 
					 * GNU General Public License for more details.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * You should have received a copy of the GNU Affero General Public License
 | 
				
			||||||
 | 
					 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
						#include <osmocom/core/linuxlist.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "llc.h"
 | 
				
			||||||
 | 
					#include "gprs_debug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#include "pcu_vty.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <osmocom/core/application.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/msgb.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/talloc.h>
 | 
				
			||||||
 | 
					#include <osmocom/core/utils.h>
 | 
				
			||||||
 | 
					#include <osmocom/vty/vty.h>
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *tall_pcu_ctx;
 | 
				
			||||||
 | 
					int16_t spoof_mnc = 0, spoof_mcc = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void enqueue_data(gprs_llc_queue *queue, const uint8_t *data, size_t len,
 | 
				
			||||||
 | 
						gprs_llc_queue::MetaInfo *info = 0)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct timeval *tv;
 | 
				
			||||||
 | 
						uint8_t *msg_data;
 | 
				
			||||||
 | 
						struct msgb *llc_msg = msgb_alloc(len + sizeof(*tv) * 2,
 | 
				
			||||||
 | 
							"llc_pdu_queue");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msg_data = (uint8_t *)msgb_put(llc_msg, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						memcpy(msg_data, data, len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queue->enqueue(llc_msg, info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dequeue_and_check(gprs_llc_queue *queue, const uint8_t *exp_data,
 | 
				
			||||||
 | 
						size_t len, const gprs_llc_queue::MetaInfo *exp_info = 0)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct msgb *llc_msg;
 | 
				
			||||||
 | 
						uint8_t *msg_data;
 | 
				
			||||||
 | 
						const gprs_llc_queue::MetaInfo *info_res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						llc_msg = queue->dequeue(&info_res);
 | 
				
			||||||
 | 
						OSMO_ASSERT(llc_msg != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fprintf(stderr, "dequeued msg, length %d (expected %d), data %s\n",
 | 
				
			||||||
 | 
							msgb_length(llc_msg), len, msgb_hexdump(llc_msg));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(msgb_length(llc_msg) == len);
 | 
				
			||||||
 | 
						msg_data = msgb_data(llc_msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(memcmp(msg_data, exp_data, len) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (exp_info)
 | 
				
			||||||
 | 
							OSMO_ASSERT(memcmp(exp_info, info_res, sizeof(*exp_info)) == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_free(llc_msg);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void enqueue_data(gprs_llc_queue *queue, const char *message,
 | 
				
			||||||
 | 
						gprs_llc_queue::MetaInfo *info = 0)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						enqueue_data(queue, (uint8_t *)(message), strlen(message), info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dequeue_and_check(gprs_llc_queue *queue, const char *exp_message,
 | 
				
			||||||
 | 
						const gprs_llc_queue::MetaInfo *exp_info = 0)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						dequeue_and_check(queue,
 | 
				
			||||||
 | 
							(uint8_t *)(exp_message), strlen(exp_message), exp_info);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_llc_queue()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						gprs_llc_queue queue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("=== start %s ===\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queue.init();
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.size() == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.octets() == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enqueue_data(&queue, "LLC message");
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.size() == 1);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.octets() == 11);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enqueue_data(&queue, "other LLC message");
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.size() == 2);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.octets() == 28);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dequeue_and_check(&queue, "LLC message");
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.size() == 1);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.octets() == 17);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dequeue_and_check(&queue, "other LLC message");
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.size() == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.octets() == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enqueue_data(&queue, "LLC");
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.size() == 1);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.octets() == 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queue.clear(NULL);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.size() == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.octets() == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("=== end %s ===\n", __func__);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_llc_meta()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						gprs_llc_queue queue;
 | 
				
			||||||
 | 
						gprs_llc_queue::MetaInfo info1 = {
 | 
				
			||||||
 | 
							.recv_time = {123456777, 123456},
 | 
				
			||||||
 | 
							.expire_time = {123456789, 987654},
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
						gprs_llc_queue::MetaInfo info2 = {
 | 
				
			||||||
 | 
							.recv_time = {987654321, 547352},
 | 
				
			||||||
 | 
							.expire_time = {987654327, 867252},
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("=== start %s ===\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queue.init();
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.size() == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.octets() == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enqueue_data(&queue, "LLC message 1", &info1);
 | 
				
			||||||
 | 
						enqueue_data(&queue, "LLC message 2", &info2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dequeue_and_check(&queue, "LLC message 1", &info1);
 | 
				
			||||||
 | 
						dequeue_and_check(&queue, "LLC message 2", &info2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						queue.clear(NULL);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.size() == 0);
 | 
				
			||||||
 | 
						OSMO_ASSERT(queue.octets() == 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("=== end %s ===\n", __func__);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct log_info_cat default_categories[] = {
 | 
				
			||||||
 | 
						{"DPCU", "", "GPRS Packet Control Unit (PCU)", LOGL_INFO, 1},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int filter_fn(const struct log_context *ctx,
 | 
				
			||||||
 | 
						struct log_target *tar)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct log_info debug_log_info = {
 | 
				
			||||||
 | 
						filter_fn,
 | 
				
			||||||
 | 
						(struct log_info_cat*)default_categories,
 | 
				
			||||||
 | 
						ARRAY_SIZE(default_categories),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct vty_app_info pcu_vty_info = {0};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						tall_pcu_ctx = talloc_named_const(NULL, 1, "LlcTest context");
 | 
				
			||||||
 | 
						if (!tall_pcu_ctx)
 | 
				
			||||||
 | 
							abort();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						msgb_set_talloc_ctx(tall_pcu_ctx);
 | 
				
			||||||
 | 
						osmo_init_logging(&debug_log_info);
 | 
				
			||||||
 | 
						log_set_use_color(osmo_stderr_target, 0);
 | 
				
			||||||
 | 
						log_set_print_filename(osmo_stderr_target, 0);
 | 
				
			||||||
 | 
						log_set_log_level(osmo_stderr_target, LOGL_INFO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vty_init(&pcu_vty_info);
 | 
				
			||||||
 | 
						pcu_vty_init(&debug_log_info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						test_llc_queue();
 | 
				
			||||||
 | 
						test_llc_meta();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (getenv("TALLOC_REPORT_FULL"))
 | 
				
			||||||
 | 
							talloc_report_full(tall_pcu_ctx, stderr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return EXIT_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					void l1if_pdch_req() { abort(); }
 | 
				
			||||||
 | 
					void l1if_connect_pdch() { abort(); }
 | 
				
			||||||
 | 
					void l1if_close_pdch() { abort(); }
 | 
				
			||||||
 | 
					void l1if_open_pdch() { abort(); }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										4
									
								
								tests/llc/LlcTest.err
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tests/llc/LlcTest.err
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					dequeued msg, length 11 (expected 11), data 4c 4c 43 20 6d 65 73 73 61 67 65 
 | 
				
			||||||
 | 
					dequeued msg, length 17 (expected 17), data 6f 74 68 65 72 20 4c 4c 43 20 6d 65 73 73 61 67 65 
 | 
				
			||||||
 | 
					dequeued msg, length 13 (expected 13), data 4c 4c 43 20 6d 65 73 73 61 67 65 20 31 
 | 
				
			||||||
 | 
					dequeued msg, length 13 (expected 13), data 4c 4c 43 20 6d 65 73 73 61 67 65 20 32 
 | 
				
			||||||
							
								
								
									
										4
									
								
								tests/llc/LlcTest.ok
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								tests/llc/LlcTest.ok
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					=== start test_llc_queue ===
 | 
				
			||||||
 | 
					=== end test_llc_queue ===
 | 
				
			||||||
 | 
					=== start test_llc_meta ===
 | 
				
			||||||
 | 
					=== end test_llc_meta ===
 | 
				
			||||||
@@ -24,6 +24,7 @@
 | 
				
			|||||||
#include "gprs_debug.h"
 | 
					#include "gprs_debug.h"
 | 
				
			||||||
#include "gprs_ms.h"
 | 
					#include "gprs_ms.h"
 | 
				
			||||||
#include "gprs_ms_storage.h"
 | 
					#include "gprs_ms_storage.h"
 | 
				
			||||||
 | 
					#include "bts.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
#include "pcu_vty.h"
 | 
					#include "pcu_vty.h"
 | 
				
			||||||
@@ -468,6 +469,42 @@ static void test_ms_timeout()
 | 
				
			|||||||
	printf("=== end %s ===\n", __func__);
 | 
						printf("=== end %s ===\n", __func__);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_ms_cs_selection()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						BTS the_bts;
 | 
				
			||||||
 | 
						gprs_rlcmac_bts *bts = the_bts.bts_data();
 | 
				
			||||||
 | 
						uint32_t tlli = 0xffeeddbb;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gprs_rlcmac_dl_tbf *dl_tbf;
 | 
				
			||||||
 | 
						GprsMs *ms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("=== start %s ===\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bts->initial_cs_dl = 4;
 | 
				
			||||||
 | 
						bts->initial_cs_ul = 1;
 | 
				
			||||||
 | 
						bts->cs_downgrade_threshold = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ms = new GprsMs(&the_bts, tlli);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ms->is_idle());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dl_tbf = talloc_zero(tall_pcu_ctx, struct gprs_rlcmac_dl_tbf);
 | 
				
			||||||
 | 
						dl_tbf->direction = GPRS_RLCMAC_DL_TBF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dl_tbf->set_ms(ms);
 | 
				
			||||||
 | 
						OSMO_ASSERT(!ms->is_idle());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ms->current_cs_dl() == 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bts->cs_downgrade_threshold = 200;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ms->current_cs_dl() == 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						talloc_free(dl_tbf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("=== end %s ===\n", __func__);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct log_info_cat default_categories[] = {
 | 
					static const struct log_info_cat default_categories[] = {
 | 
				
			||||||
	{"DPCU", "", "GPRS Packet Control Unit (PCU)", LOGL_INFO, 1},
 | 
						{"DPCU", "", "GPRS Packet Control Unit (PCU)", LOGL_INFO, 1},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@@ -507,6 +544,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	test_ms_change_tlli();
 | 
						test_ms_change_tlli();
 | 
				
			||||||
	test_ms_storage();
 | 
						test_ms_storage();
 | 
				
			||||||
	test_ms_timeout();
 | 
						test_ms_timeout();
 | 
				
			||||||
 | 
						test_ms_cs_selection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (getenv("TALLOC_REPORT_FULL"))
 | 
						if (getenv("TALLOC_REPORT_FULL"))
 | 
				
			||||||
		talloc_report_full(tall_pcu_ctx, stderr);
 | 
							talloc_report_full(tall_pcu_ctx, stderr);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,3 +54,5 @@ Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000
 | 
				
			|||||||
Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL)
 | 
					Detaching TBF from MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0x00000000 DIR=DL STATE=NULL)
 | 
				
			||||||
Timeout for MS object, TLLI = 0xffeeddbb
 | 
					Timeout for MS object, TLLI = 0xffeeddbb
 | 
				
			||||||
Destroying MS object, TLLI = 0xffeeddbb
 | 
					Destroying MS object, TLLI = 0xffeeddbb
 | 
				
			||||||
 | 
					Creating MS object, TLLI = 0xffeeddbb
 | 
				
			||||||
 | 
					Attaching TBF to MS object, TLLI = 0xffeeddbb, TBF = TBF(TFI=0 TLLI=0xffeeddbb DIR=DL STATE=NULL)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,3 +16,5 @@
 | 
				
			|||||||
  ms_active() was called
 | 
					  ms_active() was called
 | 
				
			||||||
  ms_idle() was called
 | 
					  ms_idle() was called
 | 
				
			||||||
=== end test_ms_timeout ===
 | 
					=== end test_ms_timeout ===
 | 
				
			||||||
 | 
					=== start test_ms_cs_selection ===
 | 
				
			||||||
 | 
					=== end test_ms_cs_selection ===
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -76,14 +76,12 @@ static void test_tbf_tlli_update()
 | 
				
			|||||||
	gprs_rlcmac_tbf *dl_tbf = tbf_alloc_dl_tbf(the_bts.bts_data(),
 | 
						gprs_rlcmac_tbf *dl_tbf = tbf_alloc_dl_tbf(the_bts.bts_data(),
 | 
				
			||||||
						NULL, 0,
 | 
											NULL, 0,
 | 
				
			||||||
						0, 0, 0);
 | 
											0, 0, 0);
 | 
				
			||||||
	dl_tbf->update_tlli(0x2342);
 | 
					 | 
				
			||||||
	dl_tbf->update_ms(0x2342, GPRS_RLCMAC_DL_TBF);
 | 
						dl_tbf->update_ms(0x2342, GPRS_RLCMAC_DL_TBF);
 | 
				
			||||||
	dl_tbf->set_ta(4);
 | 
						dl_tbf->set_ta(4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	gprs_rlcmac_tbf *ul_tbf = tbf_alloc_ul_tbf(the_bts.bts_data(),
 | 
						gprs_rlcmac_tbf *ul_tbf = tbf_alloc_ul_tbf(the_bts.bts_data(),
 | 
				
			||||||
						dl_tbf, 0,
 | 
											dl_tbf->ms(), 0,
 | 
				
			||||||
						0, 0, 0);
 | 
											0, 0, 0);
 | 
				
			||||||
	ul_tbf->update_tlli(0x2342);
 | 
					 | 
				
			||||||
	ul_tbf->update_ms(0x2342, GPRS_RLCMAC_UL_TBF);
 | 
						ul_tbf->update_ms(0x2342, GPRS_RLCMAC_UL_TBF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ms = the_bts.ms_by_tlli(0x2342);
 | 
						ms = the_bts.ms_by_tlli(0x2342);
 | 
				
			||||||
@@ -96,7 +94,6 @@ static void test_tbf_tlli_update()
 | 
				
			|||||||
	 * Now check.. that DL changes and that the timing advance
 | 
						 * Now check.. that DL changes and that the timing advance
 | 
				
			||||||
	 * has changed.
 | 
						 * has changed.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	dl_tbf->update_tlli(0x4232);
 | 
					 | 
				
			||||||
	dl_tbf->update_ms(0x4232, GPRS_RLCMAC_DL_TBF);
 | 
						dl_tbf->update_ms(0x4232, GPRS_RLCMAC_DL_TBF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* It is still there, since the new TLLI has not been used for UL yet */
 | 
						/* It is still there, since the new TLLI has not been used for UL yet */
 | 
				
			||||||
@@ -427,6 +424,75 @@ static void test_tbf_exhaustion()
 | 
				
			|||||||
	gprs_bssgp_destroy();
 | 
						gprs_bssgp_destroy();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void test_tbf_dl_llc_loss()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						BTS the_bts;
 | 
				
			||||||
 | 
						gprs_rlcmac_bts *bts;
 | 
				
			||||||
 | 
						uint8_t ts_no = 4;
 | 
				
			||||||
 | 
						uint8_t ms_class = 45;
 | 
				
			||||||
 | 
						int rc = 0;
 | 
				
			||||||
 | 
						uint32_t tlli = 0xc0123456;
 | 
				
			||||||
 | 
						const char *imsi = "001001000123456";
 | 
				
			||||||
 | 
						unsigned delay_csec = 1000;
 | 
				
			||||||
 | 
						GprsMs *ms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint8_t buf[19];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("=== start %s ===\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bts = the_bts.bts_data();
 | 
				
			||||||
 | 
						setup_bts(&the_bts, ts_no);
 | 
				
			||||||
 | 
						bts->ms_idle_sec = 10; /* keep the MS object */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gprs_bssgp_create_and_connect(bts, 33001, 0, 33001,
 | 
				
			||||||
 | 
							1234, 1234, 1234, 1, 1, 0, 0, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Handle LLC frame 1 */
 | 
				
			||||||
 | 
						memset(buf, 1, sizeof(buf));
 | 
				
			||||||
 | 
						rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class,
 | 
				
			||||||
 | 
							delay_csec, buf, sizeof(buf));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ms = the_bts.ms_store().get_ms(0, 0, imsi);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ms != NULL);
 | 
				
			||||||
 | 
						OSMO_ASSERT(ms->dl_tbf() != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Handle LLC frame 2 */
 | 
				
			||||||
 | 
						memset(buf, 2, sizeof(buf));
 | 
				
			||||||
 | 
						rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class,
 | 
				
			||||||
 | 
							delay_csec, buf, sizeof(buf));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* TBF establishment fails (timeout) */
 | 
				
			||||||
 | 
						tbf_free(ms->dl_tbf());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Handle LLC frame 3 */
 | 
				
			||||||
 | 
						memset(buf, 3, sizeof(buf));
 | 
				
			||||||
 | 
						rc = gprs_rlcmac_dl_tbf::handle(bts, tlli, 0, imsi, ms_class,
 | 
				
			||||||
 | 
							delay_csec, buf, sizeof(buf));
 | 
				
			||||||
 | 
						OSMO_ASSERT(rc >= 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						OSMO_ASSERT(ms->dl_tbf() != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get first BSN */
 | 
				
			||||||
 | 
						struct msgb *msg;
 | 
				
			||||||
 | 
						int fn = 0;
 | 
				
			||||||
 | 
						uint8_t expected_data = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while (ms->dl_tbf()->have_data()) {
 | 
				
			||||||
 | 
							msg = ms->dl_tbf()->create_dl_acked_block(fn += 4, 7);
 | 
				
			||||||
 | 
							fprintf(stderr, "MSG = %s\n", msgb_hexdump(msg));
 | 
				
			||||||
 | 
							OSMO_ASSERT(msgb_length(msg) == 23);
 | 
				
			||||||
 | 
							OSMO_ASSERT(msgb_data(msg)[10] == expected_data);
 | 
				
			||||||
 | 
							expected_data += 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						OSMO_ASSERT(expected_data-1 == 3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("=== end %s ===\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						gprs_bssgp_destroy();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void test_tbf_single_phase()
 | 
					static void test_tbf_single_phase()
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	BTS the_bts;
 | 
						BTS the_bts;
 | 
				
			||||||
@@ -438,6 +504,7 @@ static void test_tbf_single_phase()
 | 
				
			|||||||
	int tfi = 0;
 | 
						int tfi = 0;
 | 
				
			||||||
	gprs_rlcmac_ul_tbf *ul_tbf;
 | 
						gprs_rlcmac_ul_tbf *ul_tbf;
 | 
				
			||||||
	struct gprs_rlcmac_pdch *pdch;
 | 
						struct gprs_rlcmac_pdch *pdch;
 | 
				
			||||||
 | 
						struct pcu_l1_meas meas;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("=== start %s ===\n", __func__);
 | 
						printf("=== start %s ===\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -462,7 +529,7 @@ static void test_tbf_single_phase()
 | 
				
			|||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pdch = &the_bts.bts_data()->trx[trx_no].pdch[ts_no];
 | 
						pdch = &the_bts.bts_data()->trx[trx_no].pdch[ts_no];
 | 
				
			||||||
	pdch->rcv_block(&data_msg[0], sizeof(data_msg), fn, 0);
 | 
						pdch->rcv_block(&data_msg[0], sizeof(data_msg), fn, &meas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ms = the_bts.ms_by_tlli(0xf1223344);
 | 
						ms = the_bts.ms_by_tlli(0xf1223344);
 | 
				
			||||||
	OSMO_ASSERT(ms != NULL);
 | 
						OSMO_ASSERT(ms != NULL);
 | 
				
			||||||
@@ -491,6 +558,8 @@ static void test_tbf_two_phase()
 | 
				
			|||||||
	bitvec *rlc_block;
 | 
						bitvec *rlc_block;
 | 
				
			||||||
	uint8_t buf[64];
 | 
						uint8_t buf[64];
 | 
				
			||||||
	int num_bytes;
 | 
						int num_bytes;
 | 
				
			||||||
 | 
						struct pcu_l1_meas meas;
 | 
				
			||||||
 | 
						meas.set_rssi(31);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("=== start %s ===\n", __func__);
 | 
						printf("=== start %s ===\n", __func__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -520,7 +589,7 @@ static void test_tbf_two_phase()
 | 
				
			|||||||
	bitvec_free(rlc_block);
 | 
						bitvec_free(rlc_block);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pdch = &the_bts.bts_data()->trx[trx_no].pdch[ts_no];
 | 
						pdch = &the_bts.bts_data()->trx[trx_no].pdch[ts_no];
 | 
				
			||||||
	pdch->rcv_block(&buf[0], num_bytes, 2654270, 31);
 | 
						pdch->rcv_block(&buf[0], num_bytes, 2654270, &meas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check the TBF */
 | 
						/* check the TBF */
 | 
				
			||||||
	ul_tbf = the_bts.ul_tbf_by_tfi(tfi, trx_no);
 | 
						ul_tbf = the_bts.ul_tbf_by_tfi(tfi, trx_no);
 | 
				
			||||||
@@ -543,7 +612,7 @@ static void test_tbf_two_phase()
 | 
				
			|||||||
		uint8_t(1), /* BSN:7, E:1 */
 | 
							uint8_t(1), /* BSN:7, E:1 */
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pdch->rcv_block(&data_msg[0], sizeof(data_msg), rts_fn, 31);
 | 
						pdch->rcv_block(&data_msg[0], sizeof(data_msg), rts_fn, &meas);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ms = the_bts.ms_by_tlli(0xf1223344);
 | 
						ms = the_bts.ms_by_tlli(0xf1223344);
 | 
				
			||||||
	OSMO_ASSERT(ms != NULL);
 | 
						OSMO_ASSERT(ms != NULL);
 | 
				
			||||||
@@ -602,6 +671,7 @@ int main(int argc, char **argv)
 | 
				
			|||||||
	test_tbf_delayed_release();
 | 
						test_tbf_delayed_release();
 | 
				
			||||||
	test_tbf_imsi();
 | 
						test_tbf_imsi();
 | 
				
			||||||
	test_tbf_exhaustion();
 | 
						test_tbf_exhaustion();
 | 
				
			||||||
 | 
						test_tbf_dl_llc_loss();
 | 
				
			||||||
	test_tbf_single_phase();
 | 
						test_tbf_single_phase();
 | 
				
			||||||
	test_tbf_two_phase();
 | 
						test_tbf_two_phase();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -4,6 +4,8 @@
 | 
				
			|||||||
=== end test_tbf_imsi ===
 | 
					=== end test_tbf_imsi ===
 | 
				
			||||||
=== start test_tbf_exhaustion ===
 | 
					=== start test_tbf_exhaustion ===
 | 
				
			||||||
=== end test_tbf_exhaustion ===
 | 
					=== end test_tbf_exhaustion ===
 | 
				
			||||||
 | 
					=== start test_tbf_dl_llc_loss ===
 | 
				
			||||||
 | 
					=== end test_tbf_dl_llc_loss ===
 | 
				
			||||||
=== start test_tbf_single_phase ===
 | 
					=== start test_tbf_single_phase ===
 | 
				
			||||||
=== end test_tbf_single_phase ===
 | 
					=== end test_tbf_single_phase ===
 | 
				
			||||||
=== start test_tbf_two_phase ===
 | 
					=== start test_tbf_two_phase ===
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,13 @@ cat $abs_srcdir/ms/MsTest.err > experr
 | 
				
			|||||||
AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/ms/MsTest], [0], [expout], [experr])
 | 
					AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/ms/MsTest], [0], [expout], [experr])
 | 
				
			||||||
AT_CLEANUP
 | 
					AT_CLEANUP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AT_SETUP([llc])
 | 
				
			||||||
 | 
					AT_KEYWORDS([llc])
 | 
				
			||||||
 | 
					cat $abs_srcdir/llc/LlcTest.ok > expout
 | 
				
			||||||
 | 
					cat $abs_srcdir/llc/LlcTest.err > experr
 | 
				
			||||||
 | 
					AT_CHECK([$OSMO_QEMU $abs_top_builddir/tests/llc/LlcTest], [0], [expout], [experr])
 | 
				
			||||||
 | 
					AT_CLEANUP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
AT_SETUP([llist])
 | 
					AT_SETUP([llist])
 | 
				
			||||||
AT_KEYWORDS([llist])
 | 
					AT_KEYWORDS([llist])
 | 
				
			||||||
cat $abs_srcdir/llist/LListTest.ok > expout
 | 
					cat $abs_srcdir/llist/LListTest.ok > expout
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user