[GPRS] More work on a real SGSN

This commit is contained in:
Harald Welte 2010-05-17 22:58:03 +02:00
parent 8fc1a46f28
commit d193cb327a
5 changed files with 448 additions and 109 deletions

View File

@ -2,6 +2,9 @@
#define _GPRS_SGSN_H
#include <stdint.h>
#include <netinet/in.h>
#include <osmocore/gsm48.h>
#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 */

View File

@ -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",

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}