aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src/gprs
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc/src/gprs')
-rw-r--r--openbsc/src/gprs/gprs_gmm.c94
-rw-r--r--openbsc/src/gprs/gprs_sgsn.c120
-rw-r--r--openbsc/src/gprs/sgsn_libgtp.c35
-rw-r--r--openbsc/src/gprs/sgsn_vty.c204
4 files changed, 377 insertions, 76 deletions
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 <openbsc/gprs_bssgp.h>
#include <openbsc/gprs_llc.h>
#include <openbsc/gprs_sgsn.h>
+#include <openbsc/sgsn.h>
+
+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 <openbsc/gprs_ns.h>
#include <openbsc/gprs_bssgp.h>
-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 <gtp.h>
#include <pdp.h>
-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 <arpa/inet.h>
#include <osmocore/talloc.h>
+#include <osmocore/utils.h>
#include <openbsc/debug.h>
#include <openbsc/sgsn.h>
#include <openbsc/gprs_ns.h>
+#include <openbsc/gprs_sgsn.h>
#include <openbsc/vty.h>
#include <vty/command.h>
#include <vty/vty.h>
+#include <pdp.h>
+
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;
}