diff options
author | Harald Welte <laforge@gnumonks.org> | 2010-06-01 11:53:01 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2010-06-01 11:57:13 +0200 |
commit | 807a5d8264cd18cb2978145944e12017db43e135 (patch) | |
tree | ae9af28a241ad17cf80761b750373bab82dcc889 /openbsc/src | |
parent | 1371f7dd2fca97012869f5cce4867d0133d375da (diff) |
[GPRS] Major LLC / TLLI handling fixes
* separate the LLME and LLE state in the LLC layer
* introduce gprs_llgmm_assign() function for LLGMM-ASSIGN.req primitive
* change QoS profile to match 'real' SGSN
* Update the new TLLI when assigning a P-TMSI
The result now is that the LLC layer is notified of TLLI changes, which in turn
means it doesn't allocate a new LLE structure every TLLI change, which again
in turn means that the UI frame sequence number does not reset to zero.
As a result, MS should no longer ignore frames based on wrong UI sequence number.
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/gprs/gprs_bssgp.c | 2 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_gmm.c | 70 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_llc.c | 155 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_llc_vty.c | 42 |
4 files changed, 199 insertions, 70 deletions
diff --git a/openbsc/src/gprs/gprs_bssgp.c b/openbsc/src/gprs/gprs_bssgp.c index 58ade4d21..89b78662e 100644 --- a/openbsc/src/gprs/gprs_bssgp.c +++ b/openbsc/src/gprs/gprs_bssgp.c @@ -693,7 +693,7 @@ int gprs_bssgp_tx_dl_ud(struct msgb *msg, struct sgsn_mm_ctx *mmctx) uint8_t llc_pdu_tlv_hdr_len = 2; uint8_t *llc_pdu_tlv, *qos_profile; uint16_t pdu_lifetime = 1000; /* centi-seconds */ - uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 }; + uint8_t qos_profile_default[3] = { 0x00, 0x00, 0x20 }; uint16_t msg_len = msg->len; uint16_t bvci = msgb_bvci(msg); uint16_t nsei = msgb_nsei(msg); diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index 5492b1650..ed9f40357 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -416,7 +416,8 @@ static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg) } /* Section 9.4.1 Attach request */ -static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) +static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *ctx, struct msgb *msg, + struct gprs_llc_llme *llme) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); uint8_t *cur = gh->data, *msnc, *mi, *old_ra_info, *ms_ra_acc_cap; @@ -426,7 +427,6 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) char mi_string[GSM48_MI_SIZE]; struct gprs_ra_id ra_id; uint16_t cid; - struct sgsn_mm_ctx *ctx; DEBUGP(DMM, "-> GMM ATTACH REQUEST "); @@ -476,7 +476,8 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) switch (mi_type) { case GSM_MI_TYPE_IMSI: /* Try to find MM context based on IMSI */ - ctx = sgsn_mm_ctx_by_imsi(mi_string); + if (!ctx) + ctx = sgsn_mm_ctx_by_imsi(mi_string); if (!ctx) { #if 0 return gsm48_tx_gmm_att_rej(msg, GMM_CAUSE_IMSI_UNKNOWN); @@ -489,19 +490,22 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) #endif } ctx->tlli = msgb_tlli(msg); + ctx->llme = llme; msgid2mmctx(ctx, msg); break; case GSM_MI_TYPE_TMSI: memcpy(&tmsi, mi+1, 4); tmsi = ntohl(tmsi); /* Try to find MM context based on P-TMSI */ - ctx = sgsn_mm_ctx_by_ptmsi(tmsi); + if (!ctx) + ctx = sgsn_mm_ctx_by_ptmsi(tmsi); if (!ctx) { ctx = sgsn_mm_ctx_alloc(msgb_tlli(msg), &ra_id); - ctx->tlli = msgb_tlli(msg); - msgid2mmctx(ctx, msg); + ctx->p_tmsi = tmsi; } - ctx->p_tmsi = tmsi; + ctx->tlli = msgb_tlli(msg); + ctx->llme = llme; + msgid2mmctx(ctx, msg); break; default: LOGP(DMM, LOGL_NOTICE, "Rejecting ATTACH REQUEST with " @@ -519,14 +523,18 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) memcpy(ctx->ms_network_capa.buf, msnc, msnc_len); #ifdef PTMSI_ALLOC - /* Allocate a new P-TMSI (+ P-TMSI signature) */ + /* Allocate a new P-TMSI (+ P-TMSI signature) and update TLLI */ ctx->p_tmsi_old = ctx->p_tmsi; ctx->p_tmsi = sgsn_alloc_ptmsi(); #endif - /* FIXME: update the TLLI with the new local TLLI based on the P-TMSI */ + /* Even if there is no P-TMSI allocated, the MS will switch from + * foreign TLLI to local TLLI */ + ctx->tlli_new = gprs_tmsi2tlli(ctx->p_tmsi, TLLI_LOCAL); - DEBUGPC(DMM, "\n"); + /* Inform LLC layer about new TLLI but keep old active */ + gprs_llgmm_assign(ctx->llme, ctx->tlli, ctx->tlli_new, 0, NULL); + DEBUGPC(DMM, "\n"); return ctx ? gsm48_gmm_authorize(ctx, GMM_T3350_MODE_ATT) : 0; err_inval: @@ -620,12 +628,14 @@ static int gsm48_tx_gmm_ra_upd_rej(struct msgb *old_msg, uint8_t cause) } /* Chapter 9.4.14: Routing area update request */ -static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) +static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg, + struct gprs_llc_llme *llme) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); uint8_t *cur = gh->data; struct gprs_ra_id old_ra_id; uint8_t upd_type; + int rc; /* Update Type 10.5.5.18 */ upd_type = *cur++ & 0x0f; @@ -678,7 +688,14 @@ static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) mmctx->t3350_mode = GMM_T3350_MODE_RAU; mmctx_timer_start(mmctx, 3350, GSM0408_T3350_SECS); #endif + /* Even if there is no P-TMSI allocated, the MS will switch from + * foreign TLLI to local TLLI */ + mmctx->tlli_new = gprs_tmsi2tlli(mmctx->p_tmsi, TLLI_LOCAL); + /* Inform LLC layer about new TLLI but keep old active */ + gprs_llgmm_assign(mmctx->llme, mmctx->tlli, mmctx->tlli_new, 0, NULL); + + /* Send RA UPDATE ACCEPT */ return gsm48_tx_gmm_ra_upd_ack(mmctx); } @@ -693,11 +710,14 @@ static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg) } /* GPRS Mobility Management */ -static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg) +static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, + struct gprs_llc_llme *llme) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); int rc; + /* MMCTX can be NULL when called */ + if (!mmctx && gh->msg_type != GSM48_MT_GMM_ATTACH_REQ && gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) { @@ -706,13 +726,12 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg) return -EINVAL; } - switch (gh->msg_type) { case GSM48_MT_GMM_RA_UPD_REQ: - rc = gsm48_rx_gmm_ra_upd_req(mmctx, msg); + rc = gsm48_rx_gmm_ra_upd_req(mmctx, msg, llme); break; case GSM48_MT_GMM_ATTACH_REQ: - rc = gsm48_rx_gmm_att_req(mmctx, msg); + rc = gsm48_rx_gmm_att_req(mmctx, msg, llme); break; case GSM48_MT_GMM_ID_RESP: rc = gsm48_rx_gmm_id_resp(mmctx, msg); @@ -728,17 +747,26 @@ static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg) DEBUGP(DMM, "-> ATTACH COMPLETE\n"); mmctx_timer_stop(mmctx, 3350); mmctx->p_tmsi_old = 0; + /* Unassign the old TLLI */ + mmctx->tlli = mmctx->tlli_new; + //gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, 0, NULL); break; case GSM48_MT_GMM_RA_UPD_COMPL: /* only in case SGSN offered new P-TMSI */ DEBUGP(DMM, "-> ROUTEING AREA UPDATE COMPLETE\n"); mmctx_timer_stop(mmctx, 3350); mmctx->p_tmsi_old = 0; + /* Unassign the old TLLI */ + mmctx->tlli = mmctx->tlli_new; + //gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, 0, NULL); break; case GSM48_MT_GMM_PTMSI_REALL_COMPL: DEBUGP(DMM, "-> PTMSI REALLLICATION COMPLETE\n"); mmctx_timer_stop(mmctx, 3350); mmctx->p_tmsi_old = 0; + /* Unassign the old TLLI */ + mmctx->tlli = mmctx->tlli_new; + //gprs_llgmm_assign(mmctx->llme, 0xffffffff, mmctx->tlli_new, 0, NULL); break; case GSM48_MT_GMM_AUTH_CIPH_RESP: DEBUGP(DMM, "Unimplemented GSM 04.08 GMM msg type 0x%02x\n", @@ -1044,11 +1072,14 @@ static int gsm48_rx_gsm_status(struct sgsn_mm_ctx *ctx, struct msgb *msg) } /* GPRS Session Management */ -static int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg) +static int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg, + struct gprs_llc_llme *llme) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); int rc; + /* MMCTX can be NULL when called */ + if (!mmctx) { LOGP(DMM, LOGL_NOTICE, "Cannot handle SM for unknown MM CTX\n"); /* FIXME: return SM / MM STATUS */ @@ -1084,7 +1115,7 @@ static int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg) } /* Main entry point for incoming 04.08 GPRS messages */ -int gsm0408_gprs_rcvmsg(struct msgb *msg) +int gsm0408_gprs_rcvmsg(struct msgb *msg, struct gprs_llc_llme *llme) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); uint8_t pdisc = gh->proto_discr & 0x0f; @@ -1097,16 +1128,17 @@ int gsm0408_gprs_rcvmsg(struct msgb *msg) if (mmctx) { msgid2mmctx(mmctx, msg); rate_ctr_inc(&mmctx->ctrg->ctr[GMM_CTR_PKTS_SIG_IN]); + mmctx->llme = llme; } /* MMCTX can be NULL */ switch (pdisc) { case GSM48_PDISC_MM_GPRS: - rc = gsm0408_rcv_gmm(mmctx, msg); + rc = gsm0408_rcv_gmm(mmctx, msg, llme); break; case GSM48_PDISC_SM_GPRS: - rc = gsm0408_rcv_gsm(mmctx, msg); + rc = gsm0408_rcv_gsm(mmctx, msg, llme); break; default: DEBUGP(DMM, "Unknown GSM 04.08 discriminator 0x%02x\n", diff --git a/openbsc/src/gprs/gprs_llc.c b/openbsc/src/gprs/gprs_llc.c index c13f45f07..26730d4c2 100644 --- a/openbsc/src/gprs/gprs_llc.c +++ b/openbsc/src/gprs/gprs_llc.c @@ -30,39 +30,57 @@ #include <openbsc/gsm_data.h> #include <openbsc/debug.h> +#include <openbsc/gprs_sgsn.h> +#include <openbsc/gprs_gmm.h> #include <openbsc/gprs_bssgp.h> #include <openbsc/gprs_llc.h> #include <openbsc/crc24.h> -LLIST_HEAD(gprs_llc_lles); +LLIST_HEAD(gprs_llc_llmes); void *llc_tall_ctx; /* lookup LLC Entity based on DLCI (TLLI+SAPI tuple) */ static struct gprs_llc_lle *lle_by_tlli_sapi(uint32_t tlli, uint32_t sapi) { - struct gprs_llc_lle *lle; + struct gprs_llc_llme *llme; - llist_for_each_entry(lle, &gprs_llc_lles, list) { - if (lle->tlli == tlli && lle->sapi == sapi) - return lle; + llist_for_each_entry(llme, &gprs_llc_llmes, list) { + if (llme->tlli == tlli || llme->old_tlli == tlli) + return &llme->lle[sapi]; } return NULL; } -static struct gprs_llc_lle *lle_alloc(uint32_t tlli, uint32_t sapi) +static void lle_init(struct gprs_llc_llme *llme, uint32_t sapi) { - struct gprs_llc_lle *lle; + struct gprs_llc_lle *lle = &llme->lle[sapi]; + + lle->llme = llme; + lle->sapi = sapi; + lle->state = GPRS_LLES_UNASSIGNED; + + /* FIXME: Initialize according to parameters from SAPI9 */ + +} - lle = talloc_zero(llc_tall_ctx, struct gprs_llc_lle); - if (!lle) +static struct gprs_llc_llme *llme_alloc(uint32_t tlli) +{ + struct gprs_llc_llme *llme; + uint32_t i; + + llme = talloc_zero(llc_tall_ctx, struct gprs_llc_llme); + if (!llme) return NULL; - lle->tlli = tlli; - lle->sapi = sapi; - lle->state = GPRS_LLS_UNASSIGNED; - llist_add(&lle->list, &gprs_llc_lles); + llme->tlli = tlli; + llme->state = GPRS_LLMS_UNASSIGNED; - return lle; + for (i = 0; i < ARRAY_SIZE(llme->lle); i++) + lle_init(llme, i); + + llist_add(&llme->list, &gprs_llc_llmes); + + return llme; } enum gprs_llc_cmd { @@ -134,16 +152,16 @@ static void t200_expired(void *data) if (lle->retrans_ctr >= lle->n200) { /* FIXME: LLGM-STATUS-IND, LL-RELEASE-IND/CNF */ - lle->state = GPRS_LLS_ASSIGNED_ADM; + lle->state = GPRS_LLES_ASSIGNED_ADM; } switch (lle->state) { - case GPRS_LLS_LOCAL_EST: + case GPRS_LLES_LOCAL_EST: /* FIXME: retransmit SABM */ /* FIXME: re-start T200 */ lle->retrans_ctr++; break; - case GPRS_LLS_LOCAL_REL: + case GPRS_LLES_LOCAL_REL: /* FIXME: retransmit DISC */ /* FIXME: re-start T200 */ lle->retrans_ctr++; @@ -204,9 +222,9 @@ int gprs_llc_tx_u(struct msgb *msg, uint8_t sapi, int command, static int gprs_llc_tx_xid(struct gprs_llc_lle *lle, struct msgb *msg) { /* copy identifiers from LLE to ensure lower layers can route */ - msgb_tlli(msg) = lle->tlli; - msgb_bvci(msg) = lle->bvci; - msgb_nsei(msg) = lle->nsei; + msgb_tlli(msg) = lle->llme->tlli; + msgb_bvci(msg) = lle->llme->bvci; + msgb_nsei(msg) = lle->llme->nsei; return gprs_llc_tx_u(msg, lle->sapi, 0, GPRS_LLC_U_XID, 1); } @@ -225,11 +243,14 @@ int gprs_llc_tx_ui(struct msgb *msg, uint8_t sapi, int command, /* look-up or create the LL Entity for this (TLLI, SAPI) tuple */ lle = lle_by_tlli_sapi(msgb_tlli(msg), sapi); - if (!lle) - lle = lle_alloc(msgb_tlli(msg), sapi); + if (!lle) { + struct gprs_llc_llme *llme; + llme = llme_alloc(msgb_tlli(msg)); + lle = &llme->lle[sapi]; + } /* Update LLE's (BVCI, NSEI) tuple */ - lle->bvci = msgb_bvci(msg); - lle->nsei = msgb_nsei(msg); + lle->llme->bvci = msgb_bvci(msg); + lle->llme->nsei = msgb_nsei(msg); /* Increment V(U) */ nu = lle->vu_send; @@ -285,26 +306,26 @@ static int gprs_llc_hdr_rx(struct gprs_llc_hdr_parsed *gph, switch (gph->cmd) { case GPRS_LLC_SABM: /* Section 6.4.1.1 */ lle->v_sent = lle->v_ack = lle->v_recv = 0; - if (lle->state == GPRS_LLS_ASSIGNED_ADM) { + if (lle->state == GPRS_LLES_ASSIGNED_ADM) { /* start re-establishment (8.7.1) */ } - lle->state = GPRS_LLS_REMOTE_EST; + lle->state = GPRS_LLES_REMOTE_EST; /* FIXME: Send UA */ - lle->state = GPRS_LLS_ABM; + lle->state = GPRS_LLES_ABM; /* FIXME: process data */ break; case GPRS_LLC_DISC: /* Section 6.4.1.2 */ /* FIXME: Send UA */ /* terminate ABM */ - lle->state = GPRS_LLS_ASSIGNED_ADM; + lle->state = GPRS_LLES_ASSIGNED_ADM; break; case GPRS_LLC_UA: /* Section 6.4.1.3 */ - if (lle->state == GPRS_LLS_LOCAL_EST) - lle->state = GPRS_LLS_ABM; + if (lle->state == GPRS_LLES_LOCAL_EST) + lle->state = GPRS_LLES_ABM; break; case GPRS_LLC_DM: /* Section 6.4.1.4: ABM cannot be performed */ - if (lle->state == GPRS_LLS_LOCAL_EST) - lle->state = GPRS_LLS_ASSIGNED_ADM; + if (lle->state == GPRS_LLES_LOCAL_EST) + lle->state = GPRS_LLES_ASSIGNED_ADM; break; case GPRS_LLC_FRMR: /* Section 6.4.1.5 */ break; @@ -514,6 +535,18 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) return -EIO; } + switch (gprs_tlli_type(msgb_tlli(msg))) { + case TLLI_LOCAL: + case TLLI_FOREIGN: + case TLLI_RANDOM: + case TLLI_AUXILIARY: + break; + default: + LOGP(DLLC, LOGL_ERROR, + "Discarding frame with strange TLLI type\n"); + break; + } + /* find the LLC Entity for this TLLI+SAPI tuple */ lle = lle_by_tlli_sapi(msgb_tlli(msg), llhp.sapi); @@ -522,8 +555,10 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) if (!lle) { if (llhp.sapi == GPRS_SAPI_GMM && (llhp.cmd == GPRS_LLC_XID || llhp.cmd == GPRS_LLC_UI)) { + struct gprs_llc_llme *llme; /* FIXME: don't use the TLLI but the 0xFFFF unassigned? */ - lle = lle_alloc(msgb_tlli(msg), llhp.sapi); + llme = llme_alloc(msgb_tlli(msg)); + lle = &llme->lle[llhp.sapi]; } else { LOGP(DLLC, LOGL_NOTICE, "unknown TLLI/SAPI: Silently dropping\n"); @@ -532,8 +567,8 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) } /* Update LLE's (BVCI, NSEI) tuple */ - lle->bvci = msgb_bvci(msg); - lle->nsei = msgb_nsei(msg); + lle->llme->bvci = msgb_bvci(msg); + lle->llme->nsei = msgb_nsei(msg); /* Receive and Process the actual LLC frame */ rc = gprs_llc_hdr_rx(&llhp, lle); @@ -546,7 +581,7 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) switch (llhp.sapi) { case GPRS_SAPI_GMM: /* send LL_UNITDATA_IND to GMM */ - rc = gsm0408_gprs_rcvmsg(msg); + rc = gsm0408_gprs_rcvmsg(msg, lle->llme); break; case GPRS_SAPI_TOM2: case GPRS_SAPI_TOM8: @@ -567,3 +602,51 @@ int gprs_llc_rcvmsg(struct msgb *msg, struct tlv_parsed *tv) return rc; } + +/* 04.64 Chapter 7.2.1.1 LLGMM-ASSIGN */ +int gprs_llgmm_assign(struct gprs_llc_llme *llme, + uint32_t old_tlli, uint32_t new_tlli, + enum gprs_ciph_algo alg, const uint8_t *kc) +{ + unsigned int i; + + if (old_tlli == 0xffffffff && new_tlli != 0xffffffff) { + /* TLLI Assignment 8.3.1 */ + /* New TLLI shall be assigned and used when (re)transmitting LLC frames */ + /* If old TLLI != 0xffffffff was assigned to LLME, then TLLI + * old is unassigned. Only TLLI new shall be accepted when + * received from peer. */ + + /* If TLLI old == 0xffffffff was assigned to LLME, then this is + * TLLI assignmemt according to 8.3.1 */ + llme->old_tlli = 0; + llme->tlli = new_tlli; + llme->state = GPRS_LLMS_ASSIGNED; + /* 8.5.3.1 For all LLE's */ + for (i = 0; i < ARRAY_SIZE(llme->lle); i++) { + struct gprs_llc_lle *l = &llme->lle[i]; + l->vu_send = l->vu_recv = 0; + l->retrans_ctr = 0; + l->state = GPRS_LLES_ASSIGNED_ADM; + /* FIXME Set parameters according to table 9 */ + } + } else if (old_tlli != 0xffffffff && new_tlli != 0xffffffff) { + /* TLLI Change 8.3.2 */ + /* Both TLLI Old and TLLI New are assigned; use New when + * (re)transmitting. Accept toth Old and New on Rx */ + llme->old_tlli = llme->tlli; + llme->tlli = new_tlli; + llme->state = GPRS_LLMS_ASSIGNED; + } else if (old_tlli != 0xffffffff && new_tlli == 0xffffffff) { + /* TLLI Unassignment 8.3.3) */ + llme->tlli = llme->old_tlli = 0; + llme->state = GPRS_LLMS_UNASSIGNED; + for (i = 0; i < ARRAY_SIZE(llme->lle); i++) { + struct gprs_llc_lle *l = &llme->lle[i]; + l->state = GPRS_LLES_UNASSIGNED; + } + } else + return -EINVAL; + + return 0; +} diff --git a/openbsc/src/gprs/gprs_llc_vty.c b/openbsc/src/gprs/gprs_llc_vty.c index 9c7f5568e..6f0de046e 100644 --- a/openbsc/src/gprs/gprs_llc_vty.c +++ b/openbsc/src/gprs/gprs_llc_vty.c @@ -41,34 +41,48 @@ #include <osmocom/vty/command.h> struct value_string gprs_llc_state_strs[] = { - { GPRS_LLS_UNASSIGNED, "TLLI Unassigned" }, - { GPRS_LLS_ASSIGNED_ADM, "Assigned" }, - { GPRS_LLS_LOCAL_EST, "Local Establishment" }, - { GPRS_LLS_REMOTE_EST, "Remote Establishment" }, - { GPRS_LLS_ABM, "Asynchronous Balanced Mode" }, - { GPRS_LLS_LOCAL_REL, "Local Release" }, - { GPRS_LLS_TIMER_REC, "Timer Recovery" }, + { GPRS_LLES_UNASSIGNED, "TLLI Unassigned" }, + { GPRS_LLES_ASSIGNED_ADM, "TLLI Assigned" }, + { GPRS_LLES_LOCAL_EST, "Local Establishment" }, + { GPRS_LLES_REMOTE_EST, "Remote Establishment" }, + { GPRS_LLES_ABM, "Asynchronous Balanced Mode" }, + { GPRS_LLES_LOCAL_REL, "Local Release" }, + { GPRS_LLES_TIMER_REC, "Timer Recovery" }, }; static void vty_dump_lle(struct vty *vty, struct gprs_llc_lle *lle) { - vty_out(vty, "TLLI 0x%08x SAPI %u BVCI=%u NSEI=%u: State %s%s", - lle->tlli, lle->sapi, lle->bvci, lle->nsei, - get_value_string(gprs_llc_state_strs, lle->state), VTY_NEWLINE); - vty_out(vty, " Vsent=%u Vack=%u Vrecv=%u, N200=%u, Retrans Ctr=%u%s", + vty_out(vty, " SAPI %2u State %s VUsend=%u, VUrecv=%u", lle->sapi, + get_value_string(gprs_llc_state_strs, lle->state), + lle->vu_send, lle->vu_recv); + vty_out(vty, " Vsent=%u Vack=%u Vrecv=%u, N200=%u, RetransCtr=%u%s", lle->v_sent, lle->v_ack, lle->v_recv, lle->n200, lle->retrans_ctr, VTY_NEWLINE); } +static void vty_dump_llme(struct vty *vty, struct gprs_llc_llme *llme) +{ + unsigned int i; + + vty_out(vty, "TLLI %08x (Old TLLI %08x) BVCI=%u NSEI=%u: State %s%s", + llme->tlli, llme->old_tlli, llme->bvci, llme->nsei, + get_value_string(gprs_llc_state_strs, llme->state), VTY_NEWLINE); + for (i = 0; i < ARRAY_SIZE(llme->lle); i++) { + struct gprs_llc_lle *lle = &llme->lle[i]; + vty_dump_lle(vty, lle); + } +} + + DEFUN(show_llc, show_llc_cmd, "show llc", SHOW_STR "Display information about the LLC protocol") { - struct gprs_llc_lle *lle; + struct gprs_llc_llme *llme; vty_out(vty, "State of LLC Entities%s", VTY_NEWLINE); - llist_for_each_entry(lle, &gprs_llc_lles, list) { - vty_dump_lle(vty, lle); + llist_for_each_entry(llme, &gprs_llc_llmes, list) { + vty_dump_llme(vty, llme); } return CMD_SUCCESS; } |