TBF acknowledged mode finished for both link directions

This commit is contained in:
Andreas Eversberg 2012-07-03 13:36:03 +02:00
parent 83ced4978a
commit e6228b34a7
12 changed files with 1630 additions and 810 deletions

View File

@ -29,40 +29,31 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
{
struct bssgp_ud_hdr *budh;
int tfi;
uint32_t tlli;
int i = 0;
uint8_t trx, ts;
uint8_t *data;
uint16_t len;
struct gprs_rlcmac_tbf *tbf;
budh = (struct bssgp_ud_hdr *)msgb_bssgph(msg);
struct gprs_rlcmac_tbf *tbf;
// Create new TBF
tfi = tfi_alloc(&trx, &ts);
if (tfi < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return -EBUSY;
}
tbf = tbf_alloc(tfi, trx, ts);
tbf->direction = GPRS_RLCMAC_DL_TBF;
tbf->state = GPRS_RLCMAC_FLOW;
tbf->tlli = ntohl(budh->tlli);
LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] START TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
tlli = ntohl(budh->tlli);
/* LLC_PDU is mandatory IE */
if (!TLVP_PRESENT(tp, BSSGP_IE_LLC_PDU))
{
LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD missing mandatory IE\n", tbf->tlli);
LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD missing mandatory IE\n", tlli);
return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
}
uint8_t *llc_pdu = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
tbf->llc_index = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
LOGP(DBSSGP, LOGL_NOTICE, "LLC PDU = ");
for (i = 0; i < tbf->llc_index; i++)
data = (uint8_t *) TLVP_VAL(tp, BSSGP_IE_LLC_PDU);
len = TLVP_LEN(tp, BSSGP_IE_LLC_PDU);
if (len > sizeof(tbf->llc_frame))
{
tbf->llc_frame[i] = llc_pdu[i];
LOGPC(DBSSGP, LOGL_NOTICE, "%02x", tbf->llc_frame[i]);
LOGP(DBSSGP, LOGL_ERROR, "BSSGP TLLI=0x%08x Rx UL-UD IE_LLC_PDU too large\n", tlli);
return bssgp_tx_status(BSSGP_CAUSE_COND_IE_ERR, NULL, msg);
}
LOGP(DBSSGP, LOGL_NOTICE, "LLC PDU = (TLLI=0x%08x) %s\n", tlli, osmo_hexdump(data, len));
uint16_t imsi_len = 0;
uint8_t *imsi;
@ -79,7 +70,50 @@ int gprs_bssgp_pcu_rx_dl_ud(struct msgb *msg, struct tlv_parsed *tp)
LOGPC(DBSSGP, LOGL_NOTICE, "\n");
}
gprs_rlcmac_packet_downlink_assignment(tbf);
/* check for existing TBF */
if ((tbf = tbf_by_tlli(tlli, GPRS_RLCMAC_DL_TBF))) {
LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] APPEND TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
if (tbf->state == GPRS_RLCMAC_WAIT_RELEASE) {
LOGP(DRLCMAC, LOGL_NOTICE, "TBF in WAIT RELEASE state "
"(T3193), so reuse TBF\n");
memcpy(tbf->llc_frame, data, len);
tbf->llc_length = len;
memset(&tbf->dir.dl, 0, sizeof(tbf->dir.dl)); /* reset
rlc states */
gprs_rlcmac_trigger_downlink_assignment(tbf, 1);
} else {
/* the TBF exists, so we must write it in the queue */
struct msgb *llc_msg = msgb_alloc(len, "llc_pdu_queue");
if (!llc_msg)
return -ENOMEM;
memcpy(msgb_put(llc_msg, len), data, len);
msgb_enqueue(&tbf->llc_queue, llc_msg);
}
} else {
// Create new TBF
tfi = tfi_alloc(&trx, &ts);
if (tfi < 0) {
LOGP(DRLCMAC, LOGL_NOTICE, "No PDCH ressource\n");
/* FIXME: send reject */
return -EBUSY;
}
tbf = tbf_alloc(tfi, trx, ts);
tbf->direction = GPRS_RLCMAC_DL_TBF;
tbf->tlli = tlli;
tbf->tlli_valid = 1;
LOGP(DRLCMAC, LOGL_NOTICE, "TBF: [DOWNLINK] START TFI: %u TLLI: 0x%08x \n", tbf->tfi, tbf->tlli);
/* new TBF, so put first frame */
memcpy(tbf->llc_frame, data, len);
tbf->llc_length = len;
/* trigger downlink assignment and set state to ASSIGN.
* we don't use old_downlink, so the possible uplink is used
* to trigger downlink assignment. if there is no uplink,
* AGCH is used. */
gprs_rlcmac_trigger_downlink_assignment(tbf, 0);
}
return 0;
}

View File

@ -37,8 +37,10 @@
static const struct log_info_cat default_categories[] = {
{"DCSN1", "\033[1;31m", "Concrete Syntax Notation One (CSN1)", LOGL_NOTICE, 1},
{"DL1IF", "\033[1;32m", "GPRS PCU L1 interface (L1IF)", LOGL_NOTICE, 1},
{"DRLCMAC", "\033[1;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1},
{"DRLCMACDATA", "\033[1;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1},
{"DRLCMAC", "\033[0;33m", "GPRS RLC/MAC layer (RLCMAC)", LOGL_DEBUG, 1},
{"DRLCMACDATA", "\033[0;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1},
{"DRLCMACDL", "\033[1;33m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1},
{"DRLCMACUL", "\033[1;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1},
{"DRLCMACSCHED", "\033[0;36m", "GPRS RLC/MAC layer Data (RLCMAC)", LOGL_DEBUG, 1},
{"DBSSGP", "\033[1;34m", "GPRS BSS Gateway Protocol (BSSGP)", LOGL_NOTICE , 1},
{"DPCU", "\033[1;35m", "GPRS Packet Control Unit (PCU)", LOGL_NOTICE, 1},

View File

@ -31,6 +31,8 @@ enum {
DL1IF,
DRLCMAC,
DRLCMACDATA,
DRLCMACDL,
DRLCMACUL,
DRLCMACSCHED,
DBSSGP,
DPCU,

File diff suppressed because it is too large Load Diff

View File

@ -29,6 +29,12 @@ extern "C" {
#include <osmocom/core/timer.h>
}
/* This special feature will delay assignment of downlink TBF by one second,
* in case there is already a TBF.
* This is usefull to debug downlink establishment during packet idle mode.
*/
//#define DEBUG_DL_ASS_IDLE
/*
* PDCH instanc
*/
@ -41,6 +47,7 @@ struct gprs_rlcmac_pdch {
uint8_t next_ul_tfi; /* next uplink TBF/TFI to schedule (0..31) */
uint8_t next_dl_tfi; /* next downlink TBF/TFI to schedule (0..31) */
struct gprs_rlcmac_tbf *tbf[32]; /* array of TBF pointers, by TFI */
uint32_t last_rts_fn; /* store last frame number of RTS */
};
struct gprs_rlcmac_trx {
@ -49,6 +56,8 @@ struct gprs_rlcmac_trx {
};
struct gprs_rlcmac_bts {
uint8_t cs; /* block length 1=CS-1, 2=CS-2, 3=CS-3, 4=CS-4 */
uint16_t t3192_msec;
struct gprs_rlcmac_trx trx[8];
};
@ -61,16 +70,25 @@ extern struct gprs_rlcmac_bts *gprs_rlcmac_bts;
#define LLC_MAX_LEN 1543
#define RLC_MAX_SNS 128 /* GPRS, must be power of 2 */
#define RLC_MAX_WS 64 /* max window size */
#define RLC_MAX_LEN 52 /* CS-4 */
#define UL_RLC_DATA_BLOCK_LEN 23
#define RLC_MAX_LEN 54 /* CS-4 including spare bits */
#define T3169 6 /* 5 seconds + one second, because we don't use
#define Tassign_agch 0,500000/* wait for assignment, before transmitting DL */
#define Tassign_pacch 0,100000/* wait for assignment, before transmitting DL */
#define T3169 6,0 /* 5 seconds + one second, because we don't use
* counters before starting timer. */
#define T3191 5,0 /* 5 Seconds */
#define T3193 2,0 /* >T3192, which can be max 1,5s */
#define T3195 5,0 /* 5 Seconds */
//#define N3101_MAX 12 /* how many missed uplink blocks */
#define N3103_MAX 4 /* how many tries to poll PACKET CONTROL ACK */
#define N3105_MAX 4 /* how many tries to poll PACKET DOWNLINK ACK */
enum gprs_rlcmac_tbf_state {
GPRS_RLCMAC_NULL = 0, /* new created TBF */
GPRS_RLCMAC_ASSIGN, /* wait for downlink assignment */
GPRS_RLCMAC_FLOW, /* RLC/MAC flow, ressource needed */
GPRS_RLCMAC_FINISHED, /* flow finished, wait for release */
GPRS_RLCMAC_WAIT_RELEASE,/* wait for release or restart of DL TBF */
GPRS_RLCMAC_RELEASING, /* releasing, wait to free TBI/USF */
};
@ -79,10 +97,22 @@ enum gprs_rlcmac_tbf_poll_state {
GPRS_RLCMAC_POLL_SCHED, /* a polling was scheduled */
};
enum gprs_rlcmac_tbf_ul_substate {
GPRS_RLCMAC_UL_NONE = 0,
GPRS_RLCMAC_UL_SEND_ACK, /* send acknowledge on next RTS */
GPRS_RLCMAC_UL_WAIT_POLL, /* wait for PACKET CONTROL ACK */
enum gprs_rlcmac_tbf_dl_ass_state {
GPRS_RLCMAC_DL_ASS_NONE = 0,
GPRS_RLCMAC_DL_ASS_SEND_ASS, /* send downlink assignment on next RTS */
GPRS_RLCMAC_DL_ASS_WAIT_ACK, /* wait for PACKET CONTROL ACK */
};
enum gprs_rlcmac_tbf_ul_ass_state {
GPRS_RLCMAC_UL_ASS_NONE = 0,
GPRS_RLCMAC_UL_ASS_SEND_ASS, /* send uplink assignment on next RTS */
GPRS_RLCMAC_UL_ASS_WAIT_ACK, /* wait for PACKET CONTROL ACK */
};
enum gprs_rlcmac_tbf_ul_ack_state {
GPRS_RLCMAC_UL_ACK_NONE = 0,
GPRS_RLCMAC_UL_ACK_SEND_ACK, /* send acknowledge on next RTS */
GPRS_RLCMAC_UL_ACK_WAIT_ACK, /* wait for PACKET CONTROL ACK */
};
enum gprs_rlcmac_tbf_direction {
@ -98,30 +128,45 @@ struct gprs_rlcmac_tbf {
uint32_t tlli;
uint8_t tlli_valid;
uint8_t trx, ts, tsc;
struct gprs_rlcmac_pdch *pdch;
uint16_t arfcn, ta;
uint8_t llc_frame[LLC_MAX_LEN];
uint16_t llc_index;
uint8_t llc_frame[LLC_MAX_LEN]; /* current DL or UL frame */
uint16_t llc_index; /* current write/read position of frame */
uint16_t llc_length; /* len of current DL LLC_frame, 0 == no frame */
llist_head llc_queue; /* queued LLC DL data */
enum gprs_rlcmac_tbf_dl_ass_state dl_ass_state;
enum gprs_rlcmac_tbf_ul_ass_state ul_ass_state;
enum gprs_rlcmac_tbf_ul_ack_state ul_ack_state;
enum gprs_rlcmac_tbf_poll_state poll_state;
uint32_t poll_fn;
uint16_t bsn; /* block sequence number */
uint16_t ws; /* window size */
uint16_t sns; /* sequence number space */
/* Please note that all variables here will be reset when changing
* from WAIT RELEASE back to FLOW state (re-use of TBF).
* All states that need reset must be in this struct, so this is why
* variables are in both (dl and ul) structs and not outside union.
*/
union {
struct {
uint16_t bsn; /* block sequence number */
uint16_t v_s; /* send state */
uint16_t v_a; /* ack state */
char v_b[RLC_MAX_SNS/2]; /* acknowledge state array */
int32_t tx_counter; /* count all transmitted blocks */
uint8_t n3105; /* N3105 counter */
} dl;
struct {
uint16_t bsn; /* block sequence number */
uint16_t v_r; /* receive state */
uint16_t v_q; /* receive window state */
char v_n[RLC_MAX_SNS/2]; /* receive state array */
int32_t rx_counter; /* count all received blocks */
enum gprs_rlcmac_tbf_ul_substate substate;
uint8_t usf; /* USF */
uint8_t n3103; /* N3103 counter */
uint8_t usf; /* USF */
} ul;
} dir;
uint8_t rlc_block[RLC_MAX_SNS/2][RLC_MAX_LEN]; /* block history */
@ -142,14 +187,21 @@ int tfi_alloc(uint8_t *_trx, uint8_t *_ts);
struct gprs_rlcmac_tbf *tbf_alloc(uint8_t tfi, uint8_t trx, uint8_t ts);
struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi);
struct gprs_rlcmac_tbf *tbf_by_tfi(uint8_t tfi, int direction);
struct gprs_rlcmac_tbf *tbf_by_tlli(uint8_t tlli);
struct gprs_rlcmac_tbf *tbf_by_tlli(uint32_t tlli, int direction);
struct gprs_rlcmac_tbf *tbf_by_poll_fn(uint32_t fn);
int find_free_usf(uint8_t trx, uint8_t ts);
void tbf_free(struct gprs_rlcmac_tbf *tbf);
void tbf_new_state(struct gprs_rlcmac_tbf *tbf,
enum gprs_rlcmac_tbf_state state);
void tbf_timer_start(struct gprs_rlcmac_tbf *tbf, unsigned int T,
unsigned int seconds);
unsigned int seconds, unsigned int microseconds);
void tbf_timer_stop(struct gprs_rlcmac_tbf *tbf);
@ -161,36 +213,56 @@ enum gprs_rlcmac_block_type {
GPRS_RLCMAC_RESERVED = 0x3
};
void gprs_rlcmac_tx_ul_ack(uint8_t tfi, uint32_t tlli, RlcMacUplinkDataBlock_t * ul_data_block);
void gprs_rlcmac_data_block_parse(gprs_rlcmac_tbf* tbf, RlcMacUplinkDataBlock_t * ul_data_block);
int gprs_rlcmac_rcv_data_block(bitvec *rlc_block);
int gprs_rlcmac_rcv_control_block(bitvec *rlc_block);
int gprs_rlcmac_rcv_block(uint8_t *data, uint8_t len, uint32_t fn);
int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr);
int write_immediate_assignment(bitvec * dest, uint8_t downlink, uint8_t ra,
uint32_t fn, uint8_t ta, uint16_t arfcn, uint8_t ts, uint8_t tsc,
uint8_t tfi, uint8_t usf, uint32_t tlli, uint8_t polling,
uint32_t poll_fn);
int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta);
void write_packet_uplink_assignment(bitvec * dest, uint8_t old_tfi,
uint8_t old_downlink, uint32_t tlli, uint8_t use_tlli, uint8_t new_tfi,
uint8_t usf, uint16_t arfcn, uint8_t tn, uint8_t ta, uint8_t tsc,
uint8_t poll);
void gprs_rlcmac_tx_dl_data_block(uint32_t tlli, uint8_t tfi, uint8_t *pdu, int start_index, int end_index, uint8_t bsn, uint8_t fbi);
void write_packet_downlink_assignment(bitvec * dest, uint8_t old_tfi,
uint8_t old_downlink, uint8_t new_tfi, uint16_t arfcn,
uint8_t tn, uint8_t ta, uint8_t tsc, uint8_t poll);
int gprs_rlcmac_segment_llc_pdu(struct gprs_rlcmac_tbf *tbf);
void write_packet_uplink_ack(bitvec * dest, struct gprs_rlcmac_tbf *tbf,
uint8_t final);
void gprs_rlcmac_tx_ul_ud(gprs_rlcmac_tbf *tbf);
void gprs_rlcmac_downlink_assignment(gprs_rlcmac_tbf *tbf);
void tbf_timer_cb(void *_tbf);
void gprs_rlcmac_packet_downlink_assignment(gprs_rlcmac_tbf *tbf);
int gprs_rlcmac_poll_timeout(struct gprs_rlcmac_tbf *tbf);
void gprs_rlcmac_enqueue_block(bitvec *block, int len);
int gprs_rlcmac_rcv_rach(uint8_t ra, uint32_t Fn, int16_t qta);
int gprs_rlcmac_rcv_control_block(bitvec *rlc_block, uint32_t fn);
struct msgb *gprs_rlcmac_send_packet_uplink_assignment(
struct gprs_rlcmac_tbf *tbf, uint32_t fn);
struct msgb *gprs_rlcmac_send_packet_downlink_assignment(
struct gprs_rlcmac_tbf *tbf, uint32_t fn);
void gprs_rlcmac_trigger_downlink_assignment(gprs_rlcmac_tbf *tbf,
uint8_t old_downlink);
int gprs_rlcmac_downlink_ack(struct gprs_rlcmac_tbf *tbf, uint8_t final,
uint8_t ssn, uint8_t *rbb);
int gprs_rlcmac_rcv_data_block_acknowledged(uint8_t *data, uint8_t len);
struct msgb *gprs_rlcmac_send_data_block_acknowledged(
struct gprs_rlcmac_tbf *tbf, uint32_t fn);
struct msgb *gprs_rlcmac_send_uplink_ack(struct gprs_rlcmac_tbf *tbf,
uint32_t fn);
int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr);
#endif // GPRS_RLCMAC_H

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,9 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
return -EIO;
}
/* store last frame number of RTS */
pdch->last_rts_fn = fn;
/* check uplink ressource for polling */
poll_fn = fn + 4;
if ((block_nr % 3) == 2)
@ -75,8 +78,6 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
"TS=%d FN=%d block_nr=%d scheduling free USF for "
"polling at FN=%d of TFI=%d\n", trx, ts, fn, block_nr,
poll_fn, tfi);
/* reset poll state */
tbf->poll_state = GPRS_RLCMAC_POLL_NONE;
/* use free USF */
/* else, we search for uplink ressource */
} else {
@ -91,40 +92,47 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
if (tbf->direction != GPRS_RLCMAC_UL_TBF)
continue;
/* no UL ressources needed, go next */
/* we don't need to give ressources in FINISHED state,
* because we have received all blocks and only poll
* for packet control ack. */
if (tbf->state != GPRS_RLCMAC_FLOW)
continue;
break;
}
if (i < 32) {
/* use this USF */
usf = tbf->dir.ul.usf;
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Received RTS for PDCH: "
"TRX=%d TS=%d FN=%d block_nr=%d scheduling "
"USF=%d for required uplink ressource of "
"TFB=%d\n", trx, ts, fn, block_nr, usf, tfi);
/* next TFB to handle ressource is the next one */
"TBF=%d\n", trx, ts, fn, block_nr, usf, tfi);
/* next TBF to handle ressource is the next one */
pdch->next_ul_tfi = (tfi + 1) & 31;
break;
}
}
/* Prio 1: select control message */
if (!msg) {
for (tfi = 0; tfi < 32; tfi++) {
tbf = pdch->tbf[tfi];
/* no TBF for this tfi, go next */
if (!tbf)
continue;
/* no UL TBF, go next */
if (tbf->direction != GPRS_RLCMAC_UL_TBF)
continue;
if (tbf->dir.ul.substate == GPRS_RLCMAC_UL_SEND_ACK)
break;
}
if (tfi < 32) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control "
"message at RTS for TFB=%d\n", tfi);
/* generate ack message */
for (tfi = 0; tfi < 32; tfi++) {
tbf = pdch->tbf[tfi];
/* no TBF for this tfi, go next */
if (!tbf)
continue;
/* schedule PACKET DOWNLINK ASSIGNMENT */
if (tbf->dl_ass_state == GPRS_RLCMAC_DL_ASS_SEND_ASS)
msg = gprs_rlcmac_send_packet_downlink_assignment(tbf,
fn);
else
/* schedule PACKET UPLINK ASSIGNMENT */
if (tbf->ul_ass_state == GPRS_RLCMAC_UL_ASS_SEND_ASS)
msg = gprs_rlcmac_send_packet_uplink_assignment(tbf,
fn);
else
/* schedule PACKET UPLINK ACK */
if (tbf->ul_ack_state == GPRS_RLCMAC_UL_ACK_SEND_ACK)
msg = gprs_rlcmac_send_uplink_ack(tbf, fn);
if (msg) {
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling control "
"message at RTS for TBF=%d\n", tfi);
break;
}
}
@ -137,22 +145,22 @@ int gprs_rlcmac_rcv_rts_block(uint8_t trx, uint8_t ts, uint16_t arfcn,
/* no TBF for this tfi, go next */
if (!tbf)
continue;
/* no DD TBF, go next */
/* no DL TBF, go next */
if (tbf->direction != GPRS_RLCMAC_DL_TBF)
continue;
/* FIXME: */
}
if (i < 32) {
/* no DL ressources needed, go next */
if (tbf->state != GPRS_RLCMAC_FLOW
&& tbf->state != GPRS_RLCMAC_FINISHED)
continue;
LOGP(DRLCMACSCHED, LOGL_DEBUG, "Scheduling data "
"message at RTS for TFB=%d\n", tfi);
/* next TFB to handle ressource is the next one */
"message at RTS for TBF=%d\n", tfi);
/* next TBF to handle ressource is the next one */
pdch->next_dl_tfi = (tfi + 1) & 31;
/* generate ack message */
/* FIXME: */
/* generate DL data block */
msg = gprs_rlcmac_send_data_block_acknowledged(tbf, fn);
break;
}
/* FIXME: remove that when DL TBF is finished */
set_current_fn(fn);
msg = msgb_dequeue(&block_queue);
}
/* Prio 3: send dummy contol message */

View File

@ -216,6 +216,10 @@ int pcu_l1if_handle_l1prim(struct femtol1_hdl *fl1, struct msgb *msg)
return rc;
}
PCU will currently not work without getting a GSM time or BFI indidication.
In order to fix this, i will discuss this on the mailing list.
Andreas
/* OpenBTS socket functions */
// TODO: We should move this parameters to config file.

View File

@ -30,7 +30,6 @@ extern "C" {
}
int get_current_fn();
void set_current_fn(int fn);
void pcu_l1if_tx_pdtch(msgb *msg, uint8_t trx, uint8_t ts, uint16_t arfcn,
uint32_t fn, uint8_t block_nr);

View File

@ -58,6 +58,7 @@ int main(int argc, char *argv[])
gprs_rlcmac_bts = talloc_zero(NULL, struct gprs_rlcmac_bts);
if (!gprs_rlcmac_bts)
return -ENOMEM;
gprs_rlcmac_bts->cs = 1;
osmo_init_logging(&gprs_log_info);
pcu_l1if_open();

View File

@ -242,6 +242,17 @@ static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind)
if (!(info_ind->flags & PCU_IF_FLAG_ACTIVE)) {
LOGP(DL1IF, LOGL_NOTICE, "BTS not available\n");
/* free all TBF */
for (trx = 0; trx < 8; trx++) {
bts->trx[trx].arfcn = info_ind->trx[trx].arfcn;
for (ts = 0; ts < 8; ts++) {
for (tfi = 0; tfi < 32; tfi++) {
tbf = bts->trx[trx].pdch[ts].tbf[tfi];
if (tbf)
tbf_free(tbf);
}
}
}
return 0;
}
LOGP(DL1IF, LOGL_INFO, "BTS available\n");
@ -280,6 +291,43 @@ static int pcu_rx_info_ind(struct gsm_pcu_if_info_ind *info_ind)
return rc;
}
static int pcu_rx_time_ind(struct gsm_pcu_if_time_ind *time_ind)
{
struct gprs_rlcmac_bts *bts = gprs_rlcmac_bts;
int trx, ts, tfi;
struct gprs_rlcmac_tbf *tbf;
uint32_t elapsed;
uint8_t fn13 = time_ind->fn % 13;
/* omit frame numbers not starting at a MAC block */
if (fn13 != 0 && fn13 != 4 && fn13 != 8)
return 0;
LOGP(DL1IF, LOGL_DEBUG, "Time indication received: %d\n",
time_ind->fn % 52);
set_current_fn(time_ind->fn);
/* check for poll timeout */
for (trx = 0; trx < 8; trx++) {
for (ts = 0; ts < 8; ts++) {
for (tfi = 0; tfi < 32; tfi++) {
tbf = bts->trx[trx].pdch[ts].tbf[tfi];
if (!tbf)
continue;
if (tbf->poll_state != GPRS_RLCMAC_POLL_SCHED)
continue;
elapsed = (frame_number - tbf->poll_fn)
% 2715648;
if (elapsed >= 20 && elapsed < 200)
gprs_rlcmac_poll_timeout(tbf);
}
}
}
return 0;
}
static int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim)
{
int rc = 0;
@ -297,6 +345,9 @@ static int pcu_rx(uint8_t msg_type, struct gsm_pcu_if *pcu_prim)
case PCU_IF_MSG_INFO_IND:
rc = pcu_rx_info_ind(&pcu_prim->u.info_ind);
break;
case PCU_IF_MSG_TIME_IND:
rc = pcu_rx_time_ind(&pcu_prim->u.time_ind);
break;
default:
LOGP(DL1IF, LOGL_ERROR, "Received unknwon PCU msg type %d\n",
msg_type);

111
src/tbf.txt Normal file
View File

@ -0,0 +1,111 @@
This document describes the handling of TBFs
--------------------------------------------
Notes:
TBF
Instance for one temporary block flow.
LLC Frame
Current frame to be transmitted or received. If tbf->llc_length is not 0,
the frame exists, if 0, the frame does not exist. If tbf->llc_index is not
0, parts of the frame have been transmitted or received so far.
LLC Queue
Queue of next frames to be transmitted.
States:
GPRS_RLCMAC_ASSIGN
After a downlink TBF is created, it resides in this state until the
block flow can start. This is required to give the mobile time to listen
to connect to downlink PDCH.
GPRS_RLCMAC_FLOW,
During packet flow, this state indicates downlink and uplink TBF block
flow.
GPRS_RLCMAC_FINISHED,
Uplink TBF:
After final block is received AND all other blocks are completely
received, the state is entered. The PACKET CONTROL ACK is still not
received. (Counter N3103 is counted on each poll request.)
Downlink TBF:
All blocks including the final block has been transmitted. Not all
downlink blocks are acknowledged yet. (Counter N3015 is counted on each
poll request.)
GPRS_RLCMAC_WAIT_RELEASE,
The all blocks on downlink TBF have been acked by mobile. The penalty
timer T3192 is running on mobile.
GPRS_RLCMAC_RELEASING,
Wait for TFI/USF to be re-used. This state is entered when a counter
reaches it's maximum and T3169 is running.
When downlink LLC PDU is received:
If downlink TBF exists for given TLLI, but not in RELEASING state:
If downlink TBF is in FLOW or FINISHED state:
Enqueue PDU to LLC Queue of TBF.
Done.
If downlink TBF is in WAIT RELEASE state:
Attach PDU to LLC Frame of TBF.
Put TBF back into FLOW state.
Done.
If dowlink TBF does not exists for given TLLI, or in RELEASING state:
Create new downlink TBF.
Attach PDU to LLC Frame of TBF.
If uplink TBF exists for given TLLI, but not in RELEASING state:
Assign packet channel PACCH.
Done.
If uplink TBF does not exists for given TLLI, or in RELEASING state:
Assign packet channel AGCH.
Done.
When channel request for uplink TBF is received:
Create new uplink TBF.
If channel request was received on RACH
Assign packet channel AGCH.
Done
If channel request was received on PACCH
Assign packet channel PACCH.
Done
Handling of LLC Frame of downlink TBF and LLC Queue of downlink TBF:
If a downlink TBF is created, the LLC PDU is attached to LLC Frame of TBF
(downlink flow is assigned to MS).
If a downlink TBF exists, the LLC PDU is enqueued to LLC Queue of TBF.
During transfer of downlink blocks, the LLC Queue is dequeued whenever all
segments of LLC Frame were used for generation of downlink blocks. (If a
block is partly filled with LLC Frame segment, its remaining space is filled
with the next LLC Frame from the Queue.)
If the transfer is finished, no more LLC Frames are dequeued from the LLC
Queue, in case a new frame has arrived during lifetime of TBF.
If the all downlink blocks have been acknowledged, the LLC Queue is
dequeued and an existing frame is attached to LLC Frame. If so, the new
state is FLOW (downlink flow is assigned to MS), otherwise WAIT RELEASE.
If a new LLC PDU is attached to LLC Frame during WAIT RELEASE state, the
state is changed to FLOW (downlink flow is assigned to MS).
Handling of LLC Frame on uplink TBF:
Received uplink blocks are appended to LLC Frame of TBF. If the PDU is
complete, it is forwarded to the upper layer.
Polling:
In order to poll uplink control block from MS, a special poll state and
frame number is stored at TBF. The scheduler reads that value and will not
assign uplink ressource for other TBFs at that frame number.
When there is no uplink transmission received on the block, a timeout is
indicated by layer 1 interface. There are two ways of checking timeout:
- The received frame is bad (BFI).
- The GSM indicates that the block should have been already received.