From d193cb327a145b5d69953f12c5638eb46997f791 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Mon, 17 May 2010 22:58:03 +0200 Subject: [PATCH] [GPRS] More work on a real SGSN --- openbsc/include/openbsc/gprs_sgsn.h | 104 +++++++++----- openbsc/src/gprs/gprs_gmm.c | 94 +++++++------ openbsc/src/gprs/gprs_sgsn.c | 120 +++++++++++++++- openbsc/src/gprs/sgsn_libgtp.c | 35 +++-- openbsc/src/gprs/sgsn_vty.c | 204 +++++++++++++++++++++++++--- 5 files changed, 448 insertions(+), 109 deletions(-) diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index b9ed1b29e..8ad6ba10d 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -2,6 +2,9 @@ #define _GPRS_SGSN_H #include +#include + +#include #define GSM_IMSI_LENGTH 17 #define GSM_IMEI_LENGTH 17 @@ -72,39 +75,6 @@ struct sgsn_mm_ctx { unsigned int T; }; -enum pdp_ctx_state { - PDP_STAE_NONE, -}; - -enum pdp_type { - PDP_TYPE_NONE, -}; - -struct sgsn_pdp_ctx { - struct llist_head list; - - unsigned int id; - enum pdp_ctx_state state; - enum pdp_type type; - uint32_t address; - char *apn_subscribed; - char *apn_used; - uint16_t nsapi; - uint8_t ti; /* transaction identifier */ - uint32_t ggsn_in_use; - int vplmn_allowed; - uint32_t qos_profile_subscr; - uint32_t qos_profile_req; - uint32_t qos_profile_neg; - uint8_t radio_prio; - uint32_t tx_npdu_nr; - uint32_t rx_npdu_nr; - uint32_t tx_gtp_snd; - uint32_t rx_gtp_snu; - uint32_t charging_id; - int reordering_reqd; -}; - /* look-up a SGSN MM context based on TLLI + RAI */ struct sgsn_mm_ctx *sgsn_mm_ctx_by_tlli(uint32_t tlli, const struct gprs_ra_id *raid); @@ -115,4 +85,72 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_by_imsi(const char *imsi); struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli, const struct gprs_ra_id *raid); + +enum pdp_ctx_state { + PDP_STATE_NONE, +}; + +enum pdp_type { + PDP_TYPE_NONE, +}; + +struct sgsn_pdp_ctx { + struct llist_head list; /* list_head for mmctx->pdp_list */ + struct llist_head g_list; /* list_head for global list */ + struct sgsn_mm_ctx *mm; /* back pointer to MM CTX */ + struct sgsn_ggsn_ctx *ggsn; /* which GGSN serves this PDP */ + + //unsigned int id; + struct pdp_t *lib; /* pointer to libgtp PDP ctx */ + enum pdp_ctx_state state; + enum pdp_type type; + uint32_t address; + char *apn_subscribed; + //char *apn_used; + uint16_t nsapi; + uint8_t ti; /* transaction identifier */ + int vplmn_allowed; + uint32_t qos_profile_subscr; + //uint32_t qos_profile_req; + //uint32_t qos_profile_neg; + uint8_t radio_prio; + uint32_t tx_npdu_nr; + uint32_t rx_npdu_nr; + uint32_t tx_gtp_snd; + uint32_t rx_gtp_snu; + //uint32_t charging_id; + int reordering_reqd; +}; + + +struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm, + uint8_t nsapi); +struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm, + uint8_t nsapi); +void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp); + + +struct ggsn_ctx { + struct llist_head list; + uint32_t id; + unsigned int gtp_version; + struct in_addr remote_addr; + struct gsn_t *gsn; +}; +struct ggsn_ctx *ggsn_ctx_alloc(uint32_t id); +struct ggsn_ctx *ggsn_ctx_by_id(uint32_t id); +struct ggsn_ctx *ggsn_ctx_find_alloc(uint32_t id); + +struct apn_ctx { + struct llist_head list; + struct ggsn_ctx *ggsn; + char *name; + char *description; +}; + +extern struct llist_head sgsn_mm_ctxts; +extern struct llist_head sgsn_ggsn_ctxts; +extern struct llist_head sgsn_apn_ctxts; +extern struct llist_head sgsn_pdp_ctxts; + #endif /* _GPRS_SGSN_H */ diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index fc9d00743..e1a6deaca 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -47,6 +47,9 @@ #include #include #include +#include + +extern struct sgsn_instance *sgsn; /* Protocol related stuff, should go into libosmocore */ @@ -266,20 +269,17 @@ static int gsm48_gmm_authorize(struct sgsn_mm_ctx *ctx, struct msgb *msg) } /* Parse Chapter 9.4.13 Identity Response */ -static int gsm48_rx_gmm_id_resp(struct msgb *msg) +static int gsm48_rx_gmm_id_resp(struct sgsn_mm_ctx *ctx, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; char mi_string[GSM48_MI_SIZE]; struct gprs_ra_id ra_id; - struct sgsn_mm_ctx *ctx; gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]); DEBUGP(DMM, "-> GMM IDENTITY RESPONSE: mi_type=0x%02x MI(%s) ", mi_type, mi_string); - bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); - ctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); if (!ctx) { DEBUGP(DMM, "from unknown TLLI 0x%08x?!?\n", msgb_tlli(msg)); return -EINVAL; @@ -323,7 +323,7 @@ static void schedule_reject(struct sgsn_mm_ctx *ctx) } /* Section 9.4.1 Attach request */ -static int gsm48_rx_gmm_att_req(struct msgb *msg) +static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); uint8_t *cur = gh->data, *msnc, *mi, *old_ra_info; @@ -428,20 +428,10 @@ err_inval: } /* Section 4.7.4.1 / 9.4.5.2 MO Detach request */ -static int gsm48_rx_gmm_det_req(struct msgb *msg) +static int gsm48_rx_gmm_det_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - struct sgsn_mm_ctx *ctx; uint8_t detach_type, power_off; - struct gprs_ra_id ra_id; - - bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); - ctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); - if (!ctx) { - LOGP(DMM, LOGL_NOTICE, "-> GMM DETACH REQUEST for unknown " - "TLLI=0x%08x\n", msgb_tlli(msg)); - /* FIXME: send detach reject */ - } detach_type = gh->data[0] & 0x7; power_off = gh->data[0] & 0x8; @@ -508,10 +498,9 @@ 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 msgb *msg) +static int gsm48_rx_gmm_ra_upd_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); - struct sgsn_mm_ctx *mmctx; uint8_t *cur = gh->data; struct gprs_ra_id old_ra_id; uint8_t upd_type; @@ -543,7 +532,6 @@ static int gsm48_rx_gmm_ra_upd_req(struct msgb *msg) } /* Look-up the MM context based on old RA-ID and TLLI */ - mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &old_ra_id); if (!mmctx || mmctx->mm_state == GMM_DEREGISTERED) { /* The MS has to perform GPRS attach */ DEBUGPC(DMM, " REJECT\n"); @@ -561,7 +549,7 @@ static int gsm48_rx_gmm_ra_upd_req(struct msgb *msg) return gsm48_tx_gmm_ra_upd_ack(msg); } -static int gsm48_rx_gmm_status(struct msgb *msg) +static int gsm48_rx_gmm_status(struct sgsn_mm_ctx *mmctx, struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); @@ -572,26 +560,34 @@ static int gsm48_rx_gmm_status(struct msgb *msg) } /* GPRS Mobility Management */ -static int gsm0408_rcv_gmm(struct msgb *msg) +static int gsm0408_rcv_gmm(struct sgsn_mm_ctx *mmctx, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); int rc; + if (!mmctx && + gh->msg_type != GSM48_MT_GMM_ATTACH_REQ && + gh->msg_type != GSM48_MT_GMM_RA_UPD_REQ) { + LOGP(DMM, LOGL_NOTICE, "Cannot handle GMM for unknown MM CTX\n"); + return -EINVAL; + } + + switch (gh->msg_type) { case GSM48_MT_GMM_RA_UPD_REQ: - rc = gsm48_rx_gmm_ra_upd_req(msg); + rc = gsm48_rx_gmm_ra_upd_req(mmctx, msg); break; case GSM48_MT_GMM_ATTACH_REQ: - rc = gsm48_rx_gmm_att_req(msg); + rc = gsm48_rx_gmm_att_req(mmctx, msg); break; case GSM48_MT_GMM_ID_RESP: - rc = gsm48_rx_gmm_id_resp(msg); + rc = gsm48_rx_gmm_id_resp(mmctx, msg); break; case GSM48_MT_GMM_STATUS: - rc = gsm48_rx_gmm_status(msg); + rc = gsm48_rx_gmm_status(mmctx, msg); break; case GSM48_MT_GMM_DETACH_REQ: - rc = gsm48_rx_gmm_det_req(msg); + rc = gsm48_rx_gmm_det_req(mmctx, msg); break; case GSM48_MT_GMM_RA_UPD_COMPL: /* only in case SGSN offered new P-TMSI */ @@ -666,7 +662,8 @@ static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_c } /* Section 9.5.9: Deactivate PDP Context Accept */ -static int gsm48_tx_gsm_deact_pdp_acc(struct msgb *old_msg) +static int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mmctx, + struct msgb *old_msg) { struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg); struct msgb *msg = gsm48_msgb_alloc(); @@ -685,7 +682,8 @@ static int gsm48_tx_gsm_deact_pdp_acc(struct msgb *old_msg) } /* Section 9.5.1: Activate PDP Context Request */ -static int gsm48_rx_gsm_act_pdp_req(struct msgb *msg) +static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx, + struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); struct gsm48_act_pdp_ctx_req *act_req = (struct gsm48_act_pdp_ctx_req *) gh->data; @@ -743,25 +741,31 @@ static int gsm48_rx_gsm_act_pdp_req(struct msgb *msg) if (TLVP_PRESENT(&tp, GSM48_IE_GSM_APN)) {} if (TLVP_PRESENT(&tp, GSM48_IE_GSM_PROTO_CONF_OPT)) {} -#if 0 - return sgsn_create_pdp_ctx(ggsn, &tp); +#if 1 + { + struct ggsn_ctx ggsn; + ggsn.gtp_version = 1; + inet_aton("192.168.100.239", &ggsn.remote_addr); + ggsn.gsn = sgsn->gsn; + return sgsn_create_pdp_ctx(ggsn, mmctx, 5, &tp); + } #else return gsm48_tx_gsm_act_pdp_acc(msg, act_req); #endif } /* Section 9.5.8: Deactivate PDP Context Request */ -static int gsm48_rx_gsm_deact_pdp_req(struct msgb *msg) +static int gsm48_rx_gsm_deact_pdp_req(struct sgsn_mm_ctx *ctx, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); DEBUGP(DMM, "-> DEACTIVATE PDP CONTEXT REQ (cause: %s)\n", get_value_string(gsm_cause_names, gh->data[0])); - return gsm48_tx_gsm_deact_pdp_acc(msg); + return gsm48_tx_gsm_deact_pdp_acc(ctx, msg); } -static int gsm48_rx_gsm_status(struct msgb *msg) +static int gsm48_rx_gsm_status(struct sgsn_mm_ctx *ctx, struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); @@ -772,19 +776,24 @@ static int gsm48_rx_gsm_status(struct msgb *msg) } /* GPRS Session Management */ -static int gsm0408_rcv_gsm(struct msgb *msg) +static int gsm0408_rcv_gsm(struct sgsn_mm_ctx *mmctx, struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); int rc; + if (!mmctx) { + LOGP(DMM, LOGL_NOTICE, "Cannot handle SM for unknown MM CTX\n"); + return -EINVAL; + } + switch (gh->msg_type) { case GSM48_MT_GSM_ACT_PDP_REQ: - rc = gsm48_rx_gsm_act_pdp_req(msg); + rc = gsm48_rx_gsm_act_pdp_req(mmctx, msg); break; case GSM48_MT_GSM_DEACT_PDP_REQ: - rc = gsm48_rx_gsm_deact_pdp_req(msg); + rc = gsm48_rx_gsm_deact_pdp_req(mmctx, msg); case GSM48_MT_GSM_STATUS: - rc = gsm48_rx_gsm_status(msg); + rc = gsm48_rx_gsm_status(mmctx, msg); break; case GSM48_MT_GSM_REQ_PDP_ACT_REJ: case GSM48_MT_GSM_ACT_AA_PDP_REQ: @@ -807,14 +816,21 @@ int gsm0408_gprs_rcvmsg(struct msgb *msg) { struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_gmmh(msg); uint8_t pdisc = gh->proto_discr & 0x0f; + struct sgsn_mm_ctx *mmctx; + struct gprs_ra_id ra_id; int rc = -EINVAL; + bssgp_parse_cell_id(&ra_id, msgb_bcid(msg)); + mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id); + + /* MMCTX can be NULL */ + switch (pdisc) { case GSM48_PDISC_MM_GPRS: - rc = gsm0408_rcv_gmm(msg); + rc = gsm0408_rcv_gmm(mmctx, msg); break; case GSM48_PDISC_SM_GPRS: - rc = gsm0408_rcv_gsm(msg); + rc = gsm0408_rcv_gsm(mmctx, msg); break; default: DEBUGP(DMM, "Unknown GSM 04.08 discriminator 0x%02x\n", diff --git a/openbsc/src/gprs/gprs_sgsn.c b/openbsc/src/gprs/gprs_sgsn.c index 90ede7651..4e5fb016a 100644 --- a/openbsc/src/gprs/gprs_sgsn.c +++ b/openbsc/src/gprs/gprs_sgsn.c @@ -31,7 +31,10 @@ #include #include -static LLIST_HEAD(sgsn_mm_ctxts); +LLIST_HEAD(sgsn_mm_ctxts); +LLIST_HEAD(sgsn_ggsn_ctxts); +LLIST_HEAD(sgsn_apn_ctxts); +LLIST_HEAD(sgsn_pdp_ctxts); static int ra_id_equals(const struct gprs_ra_id *id1, const struct gprs_ra_id *id2) @@ -95,3 +98,118 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli, return ctx; } + +struct sgsn_pdp_ctx *sgsn_pdp_ctx_by_nsapi(const struct sgsn_mm_ctx *mm, + uint8_t nsapi) +{ + struct sgsn_pdp_ctx *pdp; + + llist_for_each_entry(pdp, &mm->pdp_list, list) { + if (pdp->nsapi == nsapi) + return pdp; + } + return NULL; +} + +struct sgsn_pdp_ctx *sgsn_pdp_ctx_alloc(struct sgsn_mm_ctx *mm, + uint8_t nsapi) +{ + struct sgsn_pdp_ctx *pdp; + + pdp = sgsn_pdp_ctx_by_nsapi(mm, nsapi); + if (pdp) + return NULL; + + pdp = talloc_zero(tall_bsc_ctx, struct sgsn_pdp_ctx); + if (!pdp) + return NULL; + + pdp->mm = mm; + pdp->nsapi = nsapi; + llist_add(&pdp->list, &mm->pdp_list); + llist_add(&pdp->g_list, &sgsn_pdp_ctxts); + + return pdp; +} + +void sgsn_pdp_ctx_free(struct sgsn_pdp_ctx *pdp) +{ + llist_del(&pdp->list); + llist_del(&pdp->g_list); + talloc_free(pdp); +} + +/* GGSN contexts */ + +struct ggsn_ctx *ggsn_ctx_alloc(uint32_t id) +{ + struct ggsn_ctx *ggc; + + ggc = talloc_zero(tall_bsc_ctx, struct ggsn_ctx); + if (!ggc) + return NULL; + + ggc->id = id; + ggc->gtp_version = 1; + + return ggc; +} + +struct ggsn_ctx *ggsn_ctx_by_id(uint32_t id) +{ + struct ggsn_ctx *ggc; + + llist_for_each_entry(ggc, &sgsn_ggsn_ctxts, list) { + if (id == ggc->id) + return ggc; + } + return NULL; +} + +struct ggsn_ctx *ggsn_ctx_find_alloc(uint32_t id) +{ + struct ggsn_ctx *ggc; + + ggc = ggsn_ctx_by_id(id); + if (!ggc) + ggc = ggsn_ctx_alloc(id); + return ggc; +} + +/* APN contexts */ + +#if 0 +struct apn_ctx *apn_ctx_alloc(const char *ap_name) +{ + struct apn_ctx *actx; + + actx = talloc_zero(talloc_bsc_ctx, struct apn_ctx); + if (!actx) + return NULL; + actx->name = talloc_strdup(actx, ap_name); + + return actx; +} + +struct apn_ctx *apn_ctx_by_name(const char *name) +{ + struct apn_ctx *actx; + + llist_for_each_entry(actx, &sgsn_apn_ctxts, list) { + if (!strcmp(name, actx->name)) + return actx; + } + return NULL; +} + +struct apn_ctx *apn_ctx_find_alloc(const char *name) +{ + struct apn_ctx *actx; + + actx = apn_ctx_by_name(name); + if (!actx) + actx = apn_ctx_alloc(name); + + return actx; +} +#endif diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index e99cb6cc8..f6331b9f0 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -49,12 +49,6 @@ #include #include -struct ggsn_ctx { - unsigned int gtp_version; - struct in_addr remote_addr; - struct gsn_t *gsn; -}; - const struct value_string gtp_cause_strs[] = { { GTPCAUSE_REQ_IMSI, "Request IMSI" }, { GTPCAUSE_REQ_IMEI, "Request IMEI" }, @@ -96,18 +90,30 @@ const struct value_string gtp_cause_strs[] = { /* generate a PDP context based on the IE's from the 04.08 message, * and send the GTP create pdp context request to the GGSN */ -int sgsn_create_pdp_ctx(struct ggsn_ctx *ggsn, struct sgsn_mm_ctx *mmctx, - uint16_t nsapi, struct tlv_parsed *tp) +struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct ggsn_ctx *ggsn, + struct sgsn_mm_ctx *mmctx, + uint16_t nsapi, + struct tlv_parsed *tp) { + struct sgsn_pdp_ctx *pctx; struct pdp_t *pdp; uint64_t imsi_ui64; int rc; + pctx = sgsn_pdp_ctx_alloc(mmctx, nsapi); + if (!pctx) { + LOGP(DGPRS, LOGL_ERROR, "Couldn't allocate PDP Ctx\n"); + return NULL; + } + rc = pdp_newpdp(&pdp, imsi_ui64, nsapi, NULL); if (rc) { - LOGP(DGPRS, LOGL_ERROR, "Out of PDP Contexts\n"); - return -ENOMEM; + LOGP(DGPRS, LOGL_ERROR, "Out of libgtp PDP Contexts\n"); + return NULL; } + pctx->lib = pdp; + pctx->ggsn = ggsn; + //pdp->peer = /* sockaddr_in of GGSN (receive) */ //pdp->ipif = /* not used by library */ pdp->version = ggsn->gtp_version; @@ -166,14 +172,16 @@ int sgsn_create_pdp_ctx(struct ggsn_ctx *ggsn, struct sgsn_mm_ctx *mmctx, /* FIXME: change pdp state to 'requested' */ - /* FIXME: pass along a pointer to the MM CTX */ - return gtp_create_context_req(ggsn->gsn, pdp, mmctx); + rc = gtp_create_context_req(ggsn->gsn, pdp, pctx); + /* FIXME */ + + return pctx; } /* The GGSN has confirmed the creation of a PDP Context */ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) { - struct sgsn_mm_ctx *mmctx = cbp; + struct sgsn_pdp_ctx *pctx = cbp; DEBUGP(DGPRS, "Received CREATE PDP CTX CONF, cause=%d(%s)\n", cause, get_value_string(gtp_cause_strs, cause)); @@ -197,7 +205,6 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause) return EOF; } - /* FIXME: Determine MM ctx for the PDP ctx */ /* FIXME: Send PDP CTX ACT ACK/REJ to MS */ return 0; } diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index c16e1912f..b59529c58 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -25,15 +25,19 @@ #include #include +#include #include #include #include +#include #include #include #include +#include + static struct sgsn_config *g_cfg = NULL; static struct cmd_node sgsn_node = { @@ -45,6 +49,7 @@ static struct cmd_node sgsn_node = { static int config_write_sgsn(struct vty *vty) { struct in_addr ia; + struct ggsn_ctx *gctx; vty_out(vty, "sgsn%s", VTY_NEWLINE); @@ -56,27 +61,11 @@ static int config_write_sgsn(struct vty *vty) vty_out(vty, " nsip local port %u%s", g_cfg->nsip_listen_port, VTY_NEWLINE); - return CMD_SUCCESS; -} - -DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn", - SHOW_STR "Display information about the SGSN") -{ - /* FIXME: iterate over list of NS-VC's and display their state */ - struct gprs_ns_inst *nsi = g_cfg->nsi; - struct gprs_nsvc *nsvc; - - llist_for_each_entry(nsvc, &nsi->gprs_nsvcs, list) { - vty_out(vty, "NSEI %5u, NS-VC %5u, %s-mode, %s %s%s", - nsvc->nsei, nsvc->nsvci, - nsvc->remote_end_is_sgsn ? "BSS" : "SGSN", - nsvc->state & NSE_S_ALIVE ? "ALIVE" : "DEAD", - nsvc->state & NSE_S_BLOCKED ? "BLOCKED" : "UNBLOCKED", - VTY_NEWLINE); - if (nsvc->nsi->ll == GPRS_NS_LL_UDP) - vty_out(vty, " remote peer %s:%u%s", - inet_ntoa(nsvc->ip.bts_addr.sin_addr), - ntohs(nsvc->ip.bts_addr.sin_port), VTY_NEWLINE); + llist_for_each_entry(gctx, &sgsn_ggsn_ctxts, list) { + vty_out(vty, " ggsn %u remote-ip %s%s", gctx->id, + inet_ntoa(gctx->remote_addr), VTY_NEWLINE); + vty_out(vty, " ggsn %u gtp-version %u%s", gctx->id, + gctx->gtp_version, VTY_NEWLINE); } return CMD_SUCCESS; @@ -113,15 +102,183 @@ DEFUN(cfg_nsip_local_port, unsigned int port = atoi(argv[0]); g_cfg->nsip_listen_port = port; + return CMD_SUCCESS; } +DEFUN(cfg_ggsn_remote_ip, cfg_ggsn_remote_ip_cmd, + "ggsn <0-255> remote-ip A.B.C.D", + "") +{ + uint32_t id = atoi(argv[0]); + struct ggsn_ctx *ggc = ggsn_ctx_find_alloc(id); + inet_aton(argv[1], &ggc->remote_addr); + return CMD_SUCCESS; +} + +#if 0 +DEFUN(cfg_ggsn_remote_port, cfg_ggsn_remote_port_cmd, + "ggsn <0-255> remote-port <0-65535>", + "") +{ + uint32_t id = atoi(argv[0]); + struct ggsn_ctx *ggc = ggsn_ctx_find_alloc(id); + uint16_t port = atoi(argv[1]); + +} +#endif + +DEFUN(cfg_ggsn_gtp_version, cfg_ggsn_gtp_version_cmd, + "ggsn <0-255> gtp-version (0|1)", + "") +{ + uint32_t id = atoi(argv[0]); + struct ggsn_ctx *ggc = ggsn_ctx_find_alloc(id); + uint16_t port = atoi(argv[1]); + + if (atoi(argv[1])) + ggc->gtp_version = 1; + else + ggc->gtp_version = 0; + + return CMD_SUCCESS; +} + +#if 0 +DEFUN(cfg_apn_ggsn, cfg_apn_ggsn_cmd, + "apn APNAME ggsn <0-255>", + "") +{ + struct apn_ctx ** +} +#endif + +const struct value_string gprs_mm_st_strs[] = { + { GMM_DEREGISTERED, "DEREGISTERED" }, + { GMM_COMMON_PROC_INIT, "COMMON PROCEDURE (INIT)" }, + { GMM_REGISTERED_NORMAL, "REGISTERED (NORMAL)" }, + { GMM_REGISTERED_SUSPENDED, "REGISTeRED (SUSPENDED)" }, + { GMM_DEREGISTERED_INIT, "DEREGISTERED (INIT)" }, + { 0, NULL } +}; + +static void vty_dump_pdp(struct vty *vty, const char *pfx, + struct sgsn_pdp_ctx *pdp) +{ + vty_out(vty, "%sPDP Context IMSI: %s, SAPI: %u, NSAPI: %u%s", + pfx, pdp->mm->imsi, 2342 /* FIXME */, pdp->nsapi, VTY_NEWLINE); + vty_out(vty, "%s APN: %s\n", pfx, pdp->lib->apn_use.v); + /* FIXME: statistics */ +} + +static void vty_dump_mmctx(struct vty *vty, const char *pfx, + struct sgsn_mm_ctx *mm, int pdp) +{ + vty_out(vty, "%sMM Context for IMSI %s, IMEI %s, P-TMSI %08x%s", + pfx, mm->imsi, mm->imei, mm->p_tmsi, VTY_NEWLINE); + vty_out(vty, "%s MSISDN: %s, TLLI: %08x%s", pfx, mm->msisdn, + mm->tlli, VTY_NEWLINE); + vty_out(vty, "%s MM State: %s, Routeing Area: %u-%u-%u-%u, " + "Cell ID: %u%s", pfx, + get_value_string(gprs_mm_st_strs, mm->mm_state), + mm->ra.mcc, mm->ra.mnc, mm->ra.lac, mm->ra.rac, + mm->cell_id, VTY_NEWLINE); + + if (pdp) { + struct sgsn_pdp_ctx *pdp; + + llist_for_each_entry(pdp, &mm->pdp_list, list) + vty_dump_pdp(vty, " ", pdp); + } +} + +DEFUN(show_sgsn, show_sgsn_cmd, "show sgsn", + SHOW_STR "Display information about the SGSN") +{ + /* FIXME: statistics */ + return CMD_SUCCESS; +} + +#define MMCTX_STR "MM Context\n" +#define INCLUDE_PDP_STR "Include PDP Context Information\n" + +#if 0 +DEFUN(show_mmctx_tlli, show_mmctx_tlli_cmd, + "show mm-context tlli HEX [pdp]", + SHOW_STR MMCTX_STR "Identify by TLLI\n" "TLLI\n" INCLUDE_PDP_STR) +{ + uint32_t tlli; + struct sgsn_mm_ctx *mm; + + tlli = strtoul(argv[0], NULL, 16); + mm = sgsn_mm_ctx_by_tlli(tlli); + if (!mm) { + vty_out(vty, "No MM context for TLLI %08x%s", + tlli, VTY_NEWLINE); + return CMD_WARNING; + } + vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0); + return CMD_SUCCESS; +} +#endif + +DEFUN(swow_mmctx_imsi, show_mmctx_imsi_cmd, + "show mm-context imsi IMSI [pdp]", + SHOW_STR MMCTX_STR "Identify by IMSI\n" "IMSI of the MM Context\n" + INCLUDE_PDP_STR) +{ + struct sgsn_mm_ctx *mm; + + mm = sgsn_mm_ctx_by_imsi(argv[0]); + if (!mm) { + vty_out(vty, "No MM context for IMSI %s%s", + argv[0], VTY_NEWLINE); + return CMD_WARNING; + } + vty_dump_mmctx(vty, "", mm, argv[1] ? 1 : 0); + return CMD_SUCCESS; +} + +DEFUN(swow_mmctx_all, show_mmctx_all_cmd, + "show mm-context all [pdp]", + SHOW_STR MMCTX_STR "All MM Contexts\n" INCLUDE_PDP_STR) +{ + struct sgsn_mm_ctx *mm; + + llist_for_each_entry(mm, &sgsn_mm_ctxts, list) + vty_dump_mmctx(vty, "", mm, argv[0] ? 1 : 0); + + return CMD_SUCCESS; +} + +DEFUN(show_ggsn, show_ggsn_cmd, + "show ggsn", + "") +{ + +} + +DEFUN(show_pdpctx_all, show_pdpctx_all_cmd, + "show pdp-context all", + SHOW_STR "Display information on PDP Context\n") +{ + struct sgsn_pdp_ctx *pdp; + + llist_for_each_entry(pdp, &sgsn_pdp_ctxts, g_list) + vty_dump_pdp(vty, "", pdp); + + return CMD_SUCCESS; +} int sgsn_vty_init(void) { - install_element(VIEW_NODE, &show_sgsn_cmd); + install_element_ve(&show_sgsn_cmd); + //install_element_ve(&show_mmctx_tlli_cmd); + install_element_ve(&show_mmctx_imsi_cmd); + install_element_ve(&show_mmctx_all_cmd); + install_element_ve(&show_pdpctx_all_cmd); install_element(CONFIG_NODE, &cfg_sgsn_cmd); install_node(&sgsn_node, config_write_sgsn); @@ -130,6 +287,9 @@ int sgsn_vty_init(void) install_element(SGSN_NODE, &ournode_end_cmd); install_element(SGSN_NODE, &cfg_nsip_local_ip_cmd); install_element(SGSN_NODE, &cfg_nsip_local_port_cmd); + install_element(SGSN_NODE, &cfg_ggsn_remote_ip_cmd); + //install_element(SGSN_NODE, &cfg_ggsn_remote_port_cmd); + install_element(SGSN_NODE, &cfg_ggsn_gtp_version_cmd); return 0; }