TBF acknowledged mode finished for both link directions
This commit is contained in:
parent
83ced4978a
commit
e6228b34a7
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
|
|
|
@ -31,6 +31,8 @@ enum {
|
|||
DL1IF,
|
||||
DRLCMAC,
|
||||
DRLCMACDATA,
|
||||
DRLCMACDL,
|
||||
DRLCMACUL,
|
||||
DRLCMACSCHED,
|
||||
DBSSGP,
|
||||
DPCU,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
@ -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 */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
Loading…
Reference in New Issue