[GPRS] More work on a real SGSN
This commit is contained in:
parent
8fc1a46f28
commit
d193cb327a
|
@ -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 */
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue