[GPRS] Properly connect GPRS SM with LIBGTP for PDP context activation
* store LLC SAPI as part of PDP ctx * store NSEI + BVCI as part of MM ctx * export gsm48_tx_gsm_act_pdp_acc() and call it from sgsn_libgtp.c * create and use gsm48_tx_gsm_act_pdp_rej for error cases * print SAPI as part of VTY show pdp
This commit is contained in:
parent
d2a9ed2285
commit
6abf94e420
|
@ -71,6 +71,8 @@ struct sgsn_mm_ctx {
|
|||
|
||||
/* Additional bits not present in the GSM TS */
|
||||
uint32_t tlli;
|
||||
uint16_t nsei;
|
||||
uint16_t bvci;
|
||||
struct timer_list timer;
|
||||
unsigned int T;
|
||||
};
|
||||
|
@ -88,10 +90,15 @@ struct sgsn_mm_ctx *sgsn_mm_ctx_alloc(uint32_t tlli,
|
|||
|
||||
enum pdp_ctx_state {
|
||||
PDP_STATE_NONE,
|
||||
PDP_STATE_CR_REQ,
|
||||
PDP_STATE_CR_CONF,
|
||||
};
|
||||
|
||||
enum pdp_type {
|
||||
PDP_TYPE_NONE,
|
||||
PDP_TYPE_ETSI_PPP,
|
||||
PDP_TYPE_IANA_IPv4,
|
||||
PDP_TYPE_IANA_IPv6,
|
||||
};
|
||||
|
||||
struct sgsn_pdp_ctx {
|
||||
|
@ -107,7 +114,8 @@ struct sgsn_pdp_ctx {
|
|||
uint32_t address;
|
||||
char *apn_subscribed;
|
||||
//char *apn_used;
|
||||
uint16_t nsapi;
|
||||
uint16_t nsapi; /* SNDCP */
|
||||
uint16_t sapi; /* LLC */
|
||||
uint8_t ti; /* transaction identifier */
|
||||
int vplmn_allowed;
|
||||
uint32_t qos_profile_subscr;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define _GSM48_GPRS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <osmocore/protocol/gsm_04_08.h>
|
||||
|
||||
/* Table 10.4 / 10.4a, GPRS Mobility Management (GMM) */
|
||||
#define GSM48_MT_GMM_ATTACH_REQ 0x01
|
||||
|
@ -358,7 +359,4 @@ struct gsm48_qos {
|
|||
|
||||
int gprs_tlli_type(uint32_t tlli);
|
||||
|
||||
struct gsm_bts *gsm48_bts_by_ra_id(struct gsm_network *net,
|
||||
const uint8_t *buf, unsigned int len);
|
||||
|
||||
#endif /* _GSM48_GPRS_H */
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <osmocore/msgb.h>
|
||||
|
||||
#include <openbsc/gprs_ns.h>
|
||||
#include <openbsc/gprs_sgsn.h>
|
||||
|
||||
struct sgsn_config {
|
||||
/* parsed from config file */
|
||||
|
@ -44,4 +45,9 @@ int sgsn_parse_config(const char *config_file, struct sgsn_config *cfg);
|
|||
/* Main input function for Gb proxy */
|
||||
int sgsn_rcvmsg(struct msgb *msg, struct gprs_nsvc *nsvc, uint16_t ns_bvci);
|
||||
|
||||
|
||||
struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct ggsn_ctx *ggsn,
|
||||
struct sgsn_mm_ctx *mmctx,
|
||||
uint16_t nsapi,
|
||||
struct tlv_parsed *tp);
|
||||
#endif
|
||||
|
|
|
@ -47,8 +47,11 @@
|
|||
#include <openbsc/gprs_bssgp.h>
|
||||
#include <openbsc/gprs_llc.h>
|
||||
#include <openbsc/gprs_sgsn.h>
|
||||
#include <openbsc/gprs_gmm.h>
|
||||
#include <openbsc/sgsn.h>
|
||||
|
||||
#include <pdp.h>
|
||||
|
||||
extern struct sgsn_instance *sgsn;
|
||||
|
||||
/* Protocol related stuff, should go into libosmocore */
|
||||
|
@ -148,6 +151,21 @@ static void gmm_copy_id(struct msgb *msg, const struct msgb *old)
|
|||
msgb_nsei(msg) = msgb_nsei(old);
|
||||
}
|
||||
|
||||
/* Store BVCI/NSEI in MM context */
|
||||
static void msgid2mmctx(struct sgsn_mm_ctx *mm, const struct msgb *msg)
|
||||
{
|
||||
mm->bvci = msgb_bvci(msg);
|
||||
mm->nsei = msgb_nsei(msg);
|
||||
}
|
||||
|
||||
/* Store BVCI/NSEI in MM context */
|
||||
static void mmctx2msgid(struct msgb *msg, const struct sgsn_mm_ctx *mm)
|
||||
{
|
||||
msgb_tlli(msg) = mm->tlli;
|
||||
msgb_bvci(msg) = mm->bvci;
|
||||
msgb_nsei(msg) = mm->nsei;
|
||||
}
|
||||
|
||||
static struct gsm48_qos default_qos = {
|
||||
.delay_class = 4, /* best effort */
|
||||
.reliab_class = GSM48_QOS_RC_LLC_UN_RLC_ACK_DATA_PROT,
|
||||
|
@ -396,6 +414,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
|
|||
/* FIXME: Start some timer */
|
||||
ctx->mm_state = GMM_COMMON_PROC_INIT;
|
||||
ctx->tlli = msgb_tlli(msg);
|
||||
msgid2mmctx(mmctx, msg);
|
||||
break;
|
||||
case GSM_MI_TYPE_TMSI:
|
||||
tmsi = strtoul(mi_string, NULL, 10);
|
||||
|
@ -406,6 +425,7 @@ static int gsm48_rx_gmm_att_req(struct sgsn_mm_ctx *mmctx, struct msgb *msg)
|
|||
/* FIXME: Start some timer */
|
||||
ctx->mm_state = GMM_COMMON_PROC_INIT;
|
||||
ctx->tlli = msgb_tlli(msg);
|
||||
msgid2mmctx(mmctx, msg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -631,36 +651,65 @@ static void msgb_put_pdp_addr_ppp(struct msgb *msg)
|
|||
}
|
||||
|
||||
/* Section 9.5.2: Ativate PDP Context Accept */
|
||||
static int gsm48_tx_gsm_act_pdp_acc(struct msgb *old_msg, struct gsm48_act_pdp_ctx_req *req)
|
||||
int gsm48_tx_gsm_act_pdp_acc(struct sgsn_pdp_ctx *pdp)
|
||||
{
|
||||
struct gsm48_hdr *old_gh = (struct gsm48_hdr *) msgb_gmmh(old_msg);
|
||||
struct msgb *msg = gsm48_msgb_alloc();
|
||||
struct gsm48_act_pdp_ctx_ack *act_ack;
|
||||
struct gsm48_hdr *gh;
|
||||
uint8_t transaction_id = ((old_gh->proto_discr >> 4) ^ 0x8); /* flip */
|
||||
uint8_t transaction_id = pdp->ti ^ 0x8; /* flip */
|
||||
|
||||
DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT ACK\n");
|
||||
|
||||
gmm_copy_id(msg, old_msg);
|
||||
mmctx2msgid(msg, pdp->mm);
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
|
||||
gh->msg_type = GSM48_MT_GSM_ACT_PDP_ACK;
|
||||
|
||||
/* Negotiated LLC SAPI */
|
||||
msgb_v_put(msg, req->req_llc_sapi);
|
||||
msgb_v_put(msg, pdp->sapi);
|
||||
/* copy QoS parameters from original request */
|
||||
msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos);
|
||||
msgb_lv_put(msg, pdp->lib->qos_neg.l, pdp->lib->qos_neg.v);
|
||||
//msgb_lv_put(msg, sizeof(default_qos), (uint8_t *)&default_qos);
|
||||
/* Radio priority 10.5.7.2 */
|
||||
msgb_v_put(msg, 4);
|
||||
msgb_v_put(msg, pdp->lib->radio_pri);
|
||||
/* PDP address */
|
||||
msgb_put_pdp_addr_ipv4(msg, 0x01020304);
|
||||
msgb_tlv_put(msg, GSM48_IE_GSM_PDP_ADDR,
|
||||
pdp->lib->eua.l, pdp->lib->eua.v);
|
||||
//msgb_put_pdp_addr_ipv4(msg, 0x01020304);
|
||||
/* Optional: Protocol configuration options */
|
||||
if (pdp->lib->pco_neg.l && pdp->lib->pco_neg.v)
|
||||
msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT,
|
||||
pdp->lib->pco_neg.l, pdp->lib->pco_neg.v);
|
||||
/* Optional: Packet Flow Identifier */
|
||||
|
||||
return gsm48_gmm_sendmsg(msg, 0);
|
||||
}
|
||||
|
||||
/* Section 9.5.3: Activate PDP Context reject */
|
||||
int gsm48_tx_gsm_act_pdp_rej(struct sgsn_mm_ctx *mm, uint8_t tid,
|
||||
uint8_t cause, uint8_t pco_len, uint8_t *pco_v)
|
||||
{
|
||||
struct msgb *msg = gsm48_msgb_alloc();
|
||||
struct gsm48_act_pdp_ctx_ack *act_ack;
|
||||
struct gsm48_hdr *gh;
|
||||
uint8_t transaction_id = tid ^ 0x8; /* flip */
|
||||
|
||||
DEBUGP(DMM, "<- ACTIVATE PDP CONTEXT ACK\n");
|
||||
|
||||
mmctx2msgid(msg, mm);
|
||||
|
||||
gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh));
|
||||
gh->proto_discr = GSM48_PDISC_SM_GPRS | (transaction_id << 4);
|
||||
gh->msg_type = GSM48_MT_GSM_ACT_PDP_REJ;
|
||||
|
||||
msgb_v_put(msg, cause);
|
||||
if (pco_len && pco_v)
|
||||
msgb_tlv_put(msg, GSM48_IE_GSM_PROTO_CONF_OPT, pco_len, pco_v);
|
||||
|
||||
return gsm48_gmm_sendmsg(msg, 0);
|
||||
}
|
||||
|
||||
/* Section 9.5.9: Deactivate PDP Context Accept */
|
||||
static int gsm48_tx_gsm_deact_pdp_acc(struct sgsn_mm_ctx *mmctx,
|
||||
struct msgb *old_msg)
|
||||
|
@ -691,8 +740,11 @@ static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,
|
|||
uint8_t req_qos_len, req_pdpa_len;
|
||||
uint8_t *req_qos, *req_pdpa;
|
||||
struct tlv_parsed tp;
|
||||
uint8_t transaction_id = (gh->proto_discr >> 4);
|
||||
struct sgsn_pdp_ctx *pdp;
|
||||
|
||||
DEBUGP(DMM, "-> ACTIVATE PDP CONTEXT REQ: ");
|
||||
DEBUGP(DMM, "-> ACTIVATE PDP CONTEXT REQ: SAPI=%u NSAPI=%u ",
|
||||
act_req->req_llc_sapi, act_req->req_nsapi);
|
||||
req_qos_len = act_req->data[0];
|
||||
req_qos = act_req->data + 1; /* 10.5.6.5 */
|
||||
req_pdpa_len = act_req->data[1 + req_qos_len];
|
||||
|
@ -737,9 +789,24 @@ static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,
|
|||
tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].len = req_pdpa_len;
|
||||
tp.lv[OSMO_IE_GSM_REQ_PDP_ADDR].val = req_pdpa;
|
||||
|
||||
/* FIXME: parse TLV for AP name and protocol config options */
|
||||
/* FIXME: determine GGSN based on APN and subscription options */
|
||||
if (TLVP_PRESENT(&tp, GSM48_IE_GSM_APN)) {}
|
||||
if (TLVP_PRESENT(&tp, GSM48_IE_GSM_PROTO_CONF_OPT)) {}
|
||||
|
||||
/* Check if NSAPI is out of range (TS 04.65 / 7.2) */
|
||||
if (act_req->req_nsapi < 5 || act_req->req_nsapi > 15) {
|
||||
/* Send reject with GSM_CAUSE_INV_MAND_INFO */
|
||||
return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
|
||||
GSM_CAUSE_INV_MAND_INFO,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
/* Check if NSAPI is already in use */
|
||||
if (sgsn_pdp_ctx_by_nsapi(mmctx, act_req->req_nsapi)) {
|
||||
/* FIXME: send reject with GSM_CAUSE_NSAPI_IN_USE */
|
||||
return gsm48_tx_gsm_act_pdp_rej(mmctx, transaction_id,
|
||||
GSM_CAUSE_NSAPI_IN_USE,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
#if 1
|
||||
{
|
||||
|
@ -747,10 +814,15 @@ static int gsm48_rx_gsm_act_pdp_req(struct sgsn_mm_ctx *mmctx,
|
|||
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);
|
||||
pdp = sgsn_create_pdp_ctx(&ggsn, mmctx, act_req->req_nsapi, &tp);
|
||||
if (!pdp)
|
||||
return -1;
|
||||
pdp->sapi = act_req->req_llc_sapi;
|
||||
pdp->ti = transaction_id;
|
||||
|
||||
}
|
||||
#else
|
||||
return gsm48_tx_gsm_act_pdp_acc(msg, act_req);
|
||||
return gsm48_tx_gsm_act_pdp_acc(mmctx, transaction_id, act_req);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -822,6 +894,8 @@ int gsm0408_gprs_rcvmsg(struct msgb *msg)
|
|||
|
||||
bssgp_parse_cell_id(&ra_id, msgb_bcid(msg));
|
||||
mmctx = sgsn_mm_ctx_by_tlli(msgb_tlli(msg), &ra_id);
|
||||
if (mmctx)
|
||||
msgid2mmctx(mmctx, msg);
|
||||
|
||||
/* MMCTX can be NULL */
|
||||
|
||||
|
@ -835,6 +909,7 @@ int gsm0408_gprs_rcvmsg(struct msgb *msg)
|
|||
default:
|
||||
DEBUGP(DMM, "Unknown GSM 04.08 discriminator 0x%02x\n",
|
||||
pdisc);
|
||||
/* FIXME: return status message */
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,14 +37,13 @@
|
|||
#include <osmocore/talloc.h>
|
||||
#include <osmocore/select.h>
|
||||
#include <osmocore/rate_ctr.h>
|
||||
#include <openbsc/gsm_04_08_gprs.h>
|
||||
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/sgsn.h>
|
||||
//#include <openbsc/gprs_ns.h>
|
||||
//#include <openbsc/gprs_bssgp.h>
|
||||
#include <openbsc/gprs_sgsn.h>
|
||||
#include <openbsc/gsm_04_08_gprs.h>
|
||||
#include <openbsc/gprs_gmm.h>
|
||||
|
||||
#include <gtp.h>
|
||||
#include <pdp.h>
|
||||
|
@ -170,7 +169,8 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct ggsn_ctx *ggsn,
|
|||
memcpy(pdp->gsnlu.v, &sgsn->cfg.gtp_listenaddr,
|
||||
sizeof(sgsn->cfg.gtp_listenaddr));
|
||||
|
||||
/* FIXME: change pdp state to 'requested' */
|
||||
/* change pdp state to 'requested' */
|
||||
pctx->state = PDP_STATE_CR_REQ;
|
||||
|
||||
rc = gtp_create_context_req(ggsn->gsn, pdp, pctx);
|
||||
/* FIXME */
|
||||
|
@ -178,10 +178,51 @@ struct sgsn_pdp_ctx *sgsn_create_pdp_ctx(struct ggsn_ctx *ggsn,
|
|||
return pctx;
|
||||
}
|
||||
|
||||
|
||||
struct cause_map {
|
||||
uint8_t cause_in;
|
||||
uint8_t cause_out;
|
||||
};
|
||||
|
||||
static uint8_t cause_map(const struct cause_map *map, uint8_t in, uint8_t deflt)
|
||||
{
|
||||
const struct cause_map *m;
|
||||
|
||||
for (m = map; m->cause_in && m->cause_out; m++) {
|
||||
if (m->cause_in == in)
|
||||
return m->cause_out;
|
||||
}
|
||||
return deflt;
|
||||
}
|
||||
|
||||
/* how do we map from gtp cause to SM cause */
|
||||
static const struct cause_map gtp2sm_cause_map[] = {
|
||||
{ GTPCAUSE_NO_RESOURCES, GSM_CAUSE_INSUFF_RSRC },
|
||||
{ GTPCAUSE_NOT_SUPPORTED, GSM_CAUSE_SERV_OPT_NOTSUPP },
|
||||
{ GTPCAUSE_MAN_IE_INCORRECT, GSM_CAUSE_INV_MAND_INFO },
|
||||
{ GTPCAUSE_MAN_IE_MISSING, GSM_CAUSE_INV_MAND_INFO },
|
||||
{ GTPCAUSE_OPT_IE_INCORRECT, GSM_CAUSE_PROTO_ERR_UNSPEC },
|
||||
{ GTPCAUSE_SYS_FAIL, GSM_CAUSE_NET_FAIL },
|
||||
{ GTPCAUSE_ROAMING_REST, GSM_CAUSE_REQ_SERV_OPT_NOTSUB },
|
||||
{ GTPCAUSE_PTIMSI_MISMATCH, GSM_CAUSE_PROTO_ERR_UNSPEC },
|
||||
{ GTPCAUSE_CONN_SUSP, GSM_CAUSE_PROTO_ERR_UNSPEC },
|
||||
{ GTPCAUSE_AUTH_FAIL, GSM_CAUSE_AUTH_FAILED },
|
||||
{ GTPCAUSE_USER_AUTH_FAIL, GSM_CAUSE_ACT_REJ_GGSN },
|
||||
{ GTPCAUSE_CONTEXT_NOT_FOUND, GSM_CAUSE_PROTO_ERR_UNSPEC },
|
||||
{ GTPCAUSE_ADDR_OCCUPIED, GSM_CAUSE_INSUFF_RSRC },
|
||||
{ GTPCAUSE_NO_MEMORY, GSM_CAUSE_INSUFF_RSRC },
|
||||
{ GTPCAUSE_RELOC_FAIL, GSM_CAUSE_PROTO_ERR_UNSPEC },
|
||||
{ GTPCAUSE_UNKNOWN_MAN_EXTHEADER, GSM_CAUSE_PROTO_ERR_UNSPEC },
|
||||
{ GTPCAUSE_MISSING_APN, GSM_CAUSE_MISSING_APN },
|
||||
{ GTPCAUSE_UNKNOWN_PDP, GSM_CAUSE_UNKNOWN_PDP },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
/* 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_pdp_ctx *pctx = cbp;
|
||||
uint8_t reject_cause;
|
||||
|
||||
DEBUGP(DGPRS, "Received CREATE PDP CTX CONF, cause=%d(%s)\n",
|
||||
cause, get_value_string(gtp_cause_strs, cause));
|
||||
|
@ -194,19 +235,30 @@ static int create_pdp_conf(struct pdp_t *pdp, void *cbp, int cause)
|
|||
gtp_create_context_req(sgsn->gsn, pdp, cbp);
|
||||
return 0;
|
||||
} else {
|
||||
pdp_freepdp(pdp);
|
||||
return EOF;
|
||||
reject_cause = GSM_CAUSE_NET_FAIL;
|
||||
goto reject;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for cause value if it was really successful */
|
||||
if (cause != GTPCAUSE_ACC_REQ) {
|
||||
pdp_freepdp(pdp);
|
||||
return EOF;
|
||||
reject_cause = cause_map(gtp2sm_cause_map, cause,
|
||||
GSM_CAUSE_ACT_REJ_GGSN);
|
||||
goto reject;
|
||||
}
|
||||
|
||||
/* FIXME: Send PDP CTX ACT ACK/REJ to MS */
|
||||
return 0;
|
||||
/* Send PDP CTX ACT to MS */
|
||||
return gsm48_tx_gsm_act_pdp_acc(pctx);
|
||||
|
||||
reject:
|
||||
pctx->state = PDP_STATE_NONE;
|
||||
pdp_freepdp(pdp);
|
||||
sgsn_pdp_ctx_free(pctx);
|
||||
/* Send PDP CTX ACT REJ to MS */
|
||||
return gsm48_tx_gsm_act_pdp_rej(pctx->mm, pdp->ti, reject_cause,
|
||||
0, NULL);
|
||||
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* If we receive a 04.08 DEACT PDP CTX REQ or GPRS DETACH, we need to
|
||||
|
@ -289,6 +341,7 @@ static int cb_extheader_ind(struct sockaddr_in *peer)
|
|||
static int cb_data_ind(struct pdp_t *pdp, void *packet, unsigned int len)
|
||||
{
|
||||
DEBUGP(DGPRS, "GTP DATA IND from GGSN, length=%u\n", len);
|
||||
/* FIXME: resolve PDP/MM context, forward to SNDCP layer */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -168,7 +168,7 @@ 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);
|
||||
pfx, pdp->mm->imsi, pdp->sapi, pdp->nsapi, VTY_NEWLINE);
|
||||
vty_out(vty, "%s APN: %s\n", pfx, pdp->lib->apn_use.v);
|
||||
/* FIXME: statistics */
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue