diff options
author | Harald Welte <laforge@gnumonks.org> | 2010-05-18 10:35:06 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2010-05-18 10:35:06 +0200 |
commit | 6abf94e4206fa97c7dfd72f481c278d9e2873958 (patch) | |
tree | b18b638e78d561a77fa0957b56a889559d7a475d /openbsc | |
parent | d2a9ed22859dfc4b99bfac7c0010539db3e12a0d (diff) |
[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
Diffstat (limited to 'openbsc')
-rw-r--r-- | openbsc/include/openbsc/gprs_sgsn.h | 10 | ||||
-rw-r--r-- | openbsc/include/openbsc/gsm_04_08_gprs.h | 4 | ||||
-rw-r--r-- | openbsc/include/openbsc/sgsn.h | 6 | ||||
-rw-r--r-- | openbsc/src/gprs/gprs_gmm.c | 101 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_libgtp.c | 73 | ||||
-rw-r--r-- | openbsc/src/gprs/sgsn_vty.c | 2 |
6 files changed, 168 insertions, 28 deletions
diff --git a/openbsc/include/openbsc/gprs_sgsn.h b/openbsc/include/openbsc/gprs_sgsn.h index 8ad6ba10d..df1ee4724 100644 --- a/openbsc/include/openbsc/gprs_sgsn.h +++ b/openbsc/include/openbsc/gprs_sgsn.h @@ -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; diff --git a/openbsc/include/openbsc/gsm_04_08_gprs.h b/openbsc/include/openbsc/gsm_04_08_gprs.h index d9fb285bf..e314b565c 100644 --- a/openbsc/include/openbsc/gsm_04_08_gprs.h +++ b/openbsc/include/openbsc/gsm_04_08_gprs.h @@ -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 */ diff --git a/openbsc/include/openbsc/sgsn.h b/openbsc/include/openbsc/sgsn.h index b2625dbac..1633b834d 100644 --- a/openbsc/include/openbsc/sgsn.h +++ b/openbsc/include/openbsc/sgsn.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 diff --git a/openbsc/src/gprs/gprs_gmm.c b/openbsc/src/gprs/gprs_gmm.c index e1a6deaca..391a0b11a 100644 --- a/openbsc/src/gprs/gprs_gmm.c +++ b/openbsc/src/gprs/gprs_gmm.c @@ -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; } diff --git a/openbsc/src/gprs/sgsn_libgtp.c b/openbsc/src/gprs/sgsn_libgtp.c index f6331b9f0..78bb57a5a 100644 --- a/openbsc/src/gprs/sgsn_libgtp.c +++ b/openbsc/src/gprs/sgsn_libgtp.c @@ -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; } diff --git a/openbsc/src/gprs/sgsn_vty.c b/openbsc/src/gprs/sgsn_vty.c index b59529c58..55848247d 100644 --- a/openbsc/src/gprs/sgsn_vty.c +++ b/openbsc/src/gprs/sgsn_vty.c @@ -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 */ } |