Introduce libosmo-gprs-sm
This patch itnroduces all the boilerplate required to build and package a new libosmo-gprs-sm.so library, which aims to contain the SM layer implementation. A minimal implementation is provided together with a unit test, showcasing Activation of a PDP Context and requesting implicit GPRS attach to GMM if it is not yet attached. This commit also adds/improves code in GMM layer implementing the GMMSM SAP which is used to interact SM<->GMM. Related: OS#5501 Change-Id: I9b4a9a6364f7799540475e7e1d10ab2310768281changes/54/32154/3
parent
e8b8fb1b60
commit
5e205c8375
|
@ -18,6 +18,7 @@ pkgconfig_DATA = \
|
|||
libosmo-gprs-gmm.pc \
|
||||
libosmo-gprs-llc.pc \
|
||||
libosmo-gprs-rlcmac.pc \
|
||||
libosmo-gprs-sm.pc \
|
||||
libosmo-gprs-sndcp.pc \
|
||||
$(NULL)
|
||||
|
||||
|
|
|
@ -79,6 +79,7 @@ AC_CONFIG_FILES([libosmo-csn1.pc
|
|||
libosmo-gprs-llc.pc
|
||||
libosmo-gprs-rlcmac.pc
|
||||
libosmo-gprs-sndcp.pc
|
||||
libosmo-gprs-sm.pc
|
||||
include/Makefile
|
||||
include/osmocom/Makefile
|
||||
include/osmocom/csn1/Makefile
|
||||
|
@ -87,17 +88,20 @@ AC_CONFIG_FILES([libosmo-csn1.pc
|
|||
include/osmocom/gprs/llc/Makefile
|
||||
include/osmocom/gprs/rlcmac/Makefile
|
||||
include/osmocom/gprs/sndcp/Makefile
|
||||
include/osmocom/gprs/sm/Makefile
|
||||
src/Makefile
|
||||
src/csn1/Makefile
|
||||
src/gmm/Makefile
|
||||
src/llc/Makefile
|
||||
src/rlcmac/Makefile
|
||||
src/sndcp/Makefile
|
||||
src/sm/Makefile
|
||||
tests/Makefile
|
||||
tests/gmm/Makefile
|
||||
tests/llc/Makefile
|
||||
tests/rlcmac/Makefile
|
||||
tests/sndcp/Makefile
|
||||
tests/sm/Makefile
|
||||
Makefile
|
||||
contrib/libosmo-gprs.spec])
|
||||
AC_OUTPUT
|
||||
|
|
|
@ -114,6 +114,24 @@ Requires: libosmo-gprs-sndcp0 = %{version}
|
|||
This package provides development files for compiling a program using
|
||||
libosmo-gprs-sndcp - SNDCP (Subnetwork Dependent Convergence Protocol) layer for (E)GPRS.
|
||||
|
||||
%package -n libosmo-gprs-sm0
|
||||
Summary: Osmocom GPRS SM library
|
||||
License: AGPL-3.0-or-later
|
||||
Group: System/Libraries
|
||||
|
||||
%description -n libosmo-gprs-sm0
|
||||
This package provides SM (Session Management) layer for (E)GPRS.
|
||||
|
||||
%package -n libosmo-gprs-sm-devel
|
||||
Summary: Development files for libosmo-gprs-sm
|
||||
License: AGPL-3.0-or-later
|
||||
Group: Development/Libraries/C and C++
|
||||
Requires: libosmo-gprs-sm0 = %{version}
|
||||
|
||||
%description -n libosmo-gprs-sm-devel
|
||||
This package provides development files for compiling a program using
|
||||
libosmo-gprs-sm - SM (Session Management) layer for (E)GPRS.
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
|
||||
|
@ -140,6 +158,8 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
|
|||
%postun -n libosmo-gprs-rlcmac0 -p /sbin/ldconfig
|
||||
%post -n libosmo-gprs-sndcp0 -p /sbin/ldconfig
|
||||
%postun -n libosmo-gprs-sndcp0 -p /sbin/ldconfig
|
||||
%post -n libosmo-gprs-sm0 -p /sbin/ldconfig
|
||||
%postun -n libosmo-gprs-sm0 -p /sbin/ldconfig
|
||||
|
||||
%files -n libosmo-csn1-0
|
||||
%_libdir/libosmo-csn1.so.0*
|
||||
|
@ -195,4 +215,15 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +)
|
|||
%_libdir/libosmo-gprs-sndcp.so
|
||||
%_libdir/pkgconfig/libosmo-gprs-sndcp.pc
|
||||
|
||||
%files -n libosmo-gprs-sm0
|
||||
%_libdir/libosmo-gprs-sm.so.0*
|
||||
|
||||
%files -n libosmo-gprs-sm-devel
|
||||
%dir %_includedir/%name
|
||||
%dir %_includedir/%name/osmocom
|
||||
%dir %_includedir/%name/osmocom/gprs
|
||||
%_includedir/%name/osmocom/gprs/sm
|
||||
%_libdir/libosmo-gprs-sm.so
|
||||
%_libdir/pkgconfig/libosmo-gprs-sm.pc
|
||||
|
||||
%changelog
|
||||
|
|
|
@ -142,3 +142,28 @@ Section: libdevel
|
|||
Depends: libosmo-gprs-sndcp0 (= ${binary:Version}),
|
||||
${misc:Depends}
|
||||
Description: Development headers and libraries for libosmo-gprs-sndcp
|
||||
|
||||
Package: libosmo-gprs-sm0
|
||||
Section: libs
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Pre-Depends: ${misc:Pre-Depends}
|
||||
Depends: ${misc:Depends},
|
||||
${shlibs:Depends}
|
||||
Description: Osmocom SM (Session Management) layer for GPRS and EGPRS
|
||||
|
||||
Package: libosmo-gprs-sm-dbg
|
||||
Architecture: any
|
||||
Section: debug
|
||||
Multi-Arch: same
|
||||
Depends: libosmo-gprs-sm0 (= ${binary:Version}),
|
||||
${misc:Depends}
|
||||
Description: Debug symbols for libosmo-gprs-sm
|
||||
|
||||
Package: libosmo-gprs-sm-dev
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Section: libdevel
|
||||
Depends: libosmo-gprs-sm0 (= ${binary:Version}),
|
||||
${misc:Depends}
|
||||
Description: Development headers and libraries for libosmo-gprs-sm
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
usr/include/osmocom/gprs/sm
|
||||
usr/lib/*/libosmo-gprs-sm*.a
|
||||
usr/lib/*/libosmo-gprs-sm*.so
|
||||
usr/lib/*/libosmo-gprs-sm*.la
|
||||
usr/lib/*/pkgconfig/libosmo-gprs-sm.pc
|
|
@ -0,0 +1 @@
|
|||
usr/lib/*/libosmo-gprs-sm*.so.*
|
|
@ -3,4 +3,5 @@ SUBDIRS = \
|
|||
llc \
|
||||
rlcmac \
|
||||
sndcp \
|
||||
sm \
|
||||
$(NULL)
|
||||
|
|
|
@ -30,7 +30,7 @@ enum gprs_gmm_ms_fsm_events {
|
|||
GPRS_GMM_MS_EV_ATTACH_REQUESTED,
|
||||
GPRS_GMM_MS_EV_ATTACH_REJECTED,
|
||||
GPRS_GMM_MS_EV_ATTACH_ACCEPTED,
|
||||
GPRS_GMM_MS_EV_DETACH_REQUESTED, /* also network initiated. data: ptr to enum osmo_gprs_gmm_detach_ms_type */
|
||||
GPRS_GMM_MS_EV_DETACH_REQUESTED, /* also network initiated. */
|
||||
GPRS_GMM_MS_EV_DETACH_REQUESTED_POWEROFF,
|
||||
GPRS_GMM_MS_EV_DETACH_ACCEPTED,
|
||||
GPRS_GMM_MS_EV_SR_REQUESTED, /* (Iu only) */
|
||||
|
@ -45,8 +45,23 @@ enum gprs_gmm_ms_fsm_events {
|
|||
struct gprs_gmm_ms_fsm_ctx {
|
||||
struct osmo_fsm_inst *fi;
|
||||
struct gprs_gmm_entity *gmme;
|
||||
/* Type of last initiated detach: */
|
||||
enum osmo_gprs_gmm_detach_ms_type detach_type;
|
||||
|
||||
/* Info about last initiated attach: */
|
||||
struct {
|
||||
enum osmo_gprs_gmm_attach_type type;
|
||||
bool with_imsi;
|
||||
bool explicit_att; /* true if by SMREG-ATTACH.req requested it */
|
||||
bool implicit_att; /* true if GMMSM-ESTABLISH.req requested it */
|
||||
/* Session Ids waiting for attach to happen during implicit_att: */
|
||||
uint32_t sess_id[16];
|
||||
uint8_t num_sess_id;
|
||||
} attach;
|
||||
|
||||
/* Info about last initiated detach: */
|
||||
struct {
|
||||
enum osmo_gprs_gmm_detach_ms_type type;
|
||||
enum osmo_gprs_gmm_detach_poweroff_type poweroff_type;
|
||||
} detach;
|
||||
};
|
||||
|
||||
int gprs_gmm_ms_fsm_init(void);
|
||||
|
@ -54,3 +69,14 @@ void gprs_gmm_ms_fsm_set_log_cat(int logcat);
|
|||
|
||||
int gprs_gmm_ms_fsm_ctx_init(struct gprs_gmm_ms_fsm_ctx *ctx, struct gprs_gmm_entity *gmme);
|
||||
void gprs_gmm_ms_fsm_ctx_release(struct gprs_gmm_ms_fsm_ctx *ctx);
|
||||
|
||||
int gprs_gmm_ms_fsm_ctx_request_attach(struct gprs_gmm_ms_fsm_ctx *ctx,
|
||||
enum osmo_gprs_gmm_attach_type attach_type,
|
||||
bool attach_with_imsi,
|
||||
bool explicit_attach,
|
||||
uint32_t sess_id);
|
||||
|
||||
int gprs_gmm_ms_fsm_ctx_request_detach(struct gprs_gmm_ms_fsm_ctx *ctx,
|
||||
enum osmo_gprs_gmm_detach_ms_type detach_type,
|
||||
enum osmo_gprs_gmm_detach_poweroff_type poweroff_type);
|
||||
|
||||
|
|
|
@ -184,14 +184,30 @@ static inline const char *osmo_gprs_gmm_gmmsm_prim_type_name(enum osmo_gprs_gmm_
|
|||
/* Parameters for OSMO_GPRS_GMM_GMMSM_* prims
|
||||
*/
|
||||
struct osmo_gprs_gmm_gmmsm_prim {
|
||||
/* Common fields (none) */
|
||||
/* Common fields */
|
||||
uint32_t sess_id;
|
||||
union {
|
||||
/* OSMO_GPRS_GMM_GMMSM_ESTABLISH | Req */
|
||||
struct {
|
||||
enum osmo_gprs_gmm_attach_type attach_type;
|
||||
uint32_t ptmsi;
|
||||
bool attach_with_imsi;
|
||||
char imsi[OSMO_IMSI_BUF_SIZE];
|
||||
char imei[GSM23003_IMEI_NUM_DIGITS + 1];
|
||||
char imeisv[GSM23003_IMEISV_NUM_DIGITS+1];
|
||||
/* attach-type, READY-timer, STANDBY-timer */
|
||||
} establish_req;
|
||||
/* OSMO_GPRS_GMM_GMMSM_ESTABLISH | Cnf/Rej */
|
||||
struct {
|
||||
uint8_t cause;
|
||||
bool accepted;
|
||||
union {
|
||||
struct {
|
||||
/* PLMNs MT-caps, attach-type. */
|
||||
} acc;
|
||||
struct {
|
||||
uint8_t cause;
|
||||
} rej;
|
||||
};
|
||||
} establish_cnf;
|
||||
/* OSMO_GPRS_GMM_GMMSM_RELEASE | Ind */
|
||||
struct {
|
||||
|
@ -242,5 +258,5 @@ struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmreg_detach_req(void);
|
|||
struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmrr_page_ind(uint32_t tlli);
|
||||
|
||||
/* Alloc primitive for GMMSM SAP: */
|
||||
struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmsm_establish_req(void);
|
||||
struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmsm_unitdata_req(uint8_t *smpdu, unsigned int smpdu_len);
|
||||
struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmsm_establish_req(uint32_t id);
|
||||
struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmsm_unitdata_req(uint32_t id, uint8_t *smpdu, unsigned int smpdu_len);
|
||||
|
|
|
@ -77,9 +77,9 @@ struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmreg_detach_cnf(void);
|
|||
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmrr_assign_req(uint32_t new_tlli);
|
||||
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmsm_establish_cnf(uint8_t cause);
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmrr_release_ind(void);
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmsm_unitdata_ind(uint8_t *smpdu, unsigned int smpdu_len);
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmsm_establish_cnf(uint32_t id, uint8_t cause);
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmrr_release_ind(uint32_t id);
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmsm_unitdata_ind(uint32_t id, uint8_t *smpdu, unsigned int smpdu_len);
|
||||
|
||||
/* gmm.c: */
|
||||
struct gprs_gmm_entity *gprs_gmm_gmme_alloc(void);
|
||||
|
@ -93,6 +93,9 @@ int gprs_gmm_tx_detach_req(struct gprs_gmm_entity *gmme,
|
|||
enum osmo_gprs_gmm_detach_ms_type detach_type,
|
||||
enum osmo_gprs_gmm_detach_poweroff_type poweroff_type);
|
||||
|
||||
int gprs_gmm_submit_gmmreg_attach_cnf(struct gprs_gmm_entity *gmme, bool accepted, uint8_t cause);
|
||||
int gprs_gmm_submit_gmmsm_establish_cnf(struct gprs_gmm_entity *gmme, uint32_t sess_id, bool accepted, uint8_t cause);
|
||||
|
||||
#define LOGGMME(snme, level, fmt, args...) \
|
||||
LOGGMM(level, "GMME(PTMSI-%08x) " fmt, \
|
||||
gmme->ptmsi, \
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
noinst_HEADERS = \
|
||||
sm_ms_fsm.h \
|
||||
sm_pdu.h \
|
||||
sm_private.h \
|
||||
$(NULL)
|
||||
|
||||
sm_HEADERS = \
|
||||
sm.h \
|
||||
sm_prim.h \
|
||||
$(NULL)
|
||||
|
||||
smdir = $(includedir)/osmocom/gprs/sm
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
/* GPRS Session Management (SM) definitions from 3GPP TS 24.008 */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* 3GPP TS 24.008 10.5.6.1 */
|
||||
#define OSMO_GPRS_SM_APN_MAXLEN 100
|
||||
|
||||
/* Max number of NSAPI */
|
||||
#define OSMO_GPRS_SM_PDP_MAXNSAPI 16
|
||||
|
||||
/* 3GPP TS 24.008 10.5.6.3 Protocol configuration options */
|
||||
#define OSMO_GPRS_SM_PCO_MAXLEN 253
|
||||
|
||||
/* 3GPP TS 24.008 10.5.6.5 Quality of service */
|
||||
#define OSMO_GPRS_SM_QOS_MAXLEN 22
|
||||
|
||||
/* 3GPP TS 24.008 10.5.6.21 NBIFOM container (T=1,L=1,V=255 => 257) */
|
||||
#define OSMO_GPRS_SM_MBIFORM_MAXLEN 255
|
||||
|
||||
/* TS 24.008 10.5.6.9 "LLC service access point identifier" */
|
||||
enum osmo_gprs_sm_llc_sapi {
|
||||
OSMO_GPRS_SM_LLC_SAPI_UNASSIGNED = 0,
|
||||
OSMO_GPRS_SM_LLC_SAPI_SAPI3 = 3,
|
||||
OSMO_GPRS_SM_LLC_SAPI_SAPI5 = 5,
|
||||
OSMO_GPRS_SM_LLC_SAPI_SAPI9 = 9,
|
||||
OSMO_GPRS_SM_LLC_SAPI_SAPI11 = 11,
|
||||
};
|
||||
|
||||
/* 10.5.6.4 Packet data protocol address */
|
||||
enum osmo_gprs_sm_pdp_addr_ietf_type {
|
||||
OSMO_GPRS_SM_PDP_ADDR_IETF_IPV4 = 0x21, /* used in earlier version of this protocol */
|
||||
OSMO_GPRS_SM_PDP_ADDR_IETF_IPV6 = 0x57,
|
||||
OSMO_GPRS_SM_PDP_ADDR_IETF_IPV4V6 = 0x8D,
|
||||
/* All other values shall be interpreted as IPv4 address in this version of the protocol */
|
||||
};
|
||||
|
||||
/* Use stack as MS or as network? */
|
||||
enum osmo_gprs_sm_location {
|
||||
OSMO_GPRS_SM_LOCATION_UNSET,
|
||||
OSMO_GPRS_SM_LOCATION_MS,
|
||||
OSMO_GPRS_SM_LOCATION_NETWORK,
|
||||
};
|
||||
|
||||
int osmo_gprs_sm_init(enum osmo_gprs_sm_location location);
|
||||
|
||||
enum osmo_gprs_sm_log_cat {
|
||||
OSMO_GPRS_SM_LOGC_SM,
|
||||
_OSMO_GPRS_SM_LOGC_MAX,
|
||||
};
|
||||
|
||||
void osmo_gprs_sm_set_log_cat(enum osmo_gprs_sm_log_cat logc, int logc_num);
|
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/gprs/sm/sm_prim.h>
|
||||
|
||||
struct gprs_sm_entity;
|
||||
|
||||
/* 3GPP TS 24.008 § 6.1.2.1 Session management states in the MS */
|
||||
enum gprs_sm_ms_fsm_states {
|
||||
GPRS_SM_MS_ST_PDP_INACTIVE, /* 6.1.2.1.1 */
|
||||
GPRS_SM_MS_ST_PDP_ACTIVE_PENDING, /* 6.1.2.1.2 */
|
||||
GPRS_SM_MS_ST_PDP_ACTIVE, /* 6.1.2.1.4 */
|
||||
GPRS_SM_MS_ST_PDP_MODIFY_PENDING, /* 6.1.2.1.5 */
|
||||
GPRS_SM_MS_ST_PDP_INACTIVE_PENDING, /* 6.1.2.1.3 */
|
||||
//GPRS_SM_MS_ST_MBMS_ACTIVE_PENDING, /* 6.1.2.1.6 */
|
||||
//GPRS_SM_MS_ST_MBMS_ACTIVE, /* 6.1.2.1.7 */
|
||||
};
|
||||
|
||||
enum gprs_sm_ms_fsm_events {
|
||||
GPRS_SM_MS_EV_RX_GMM_ESTABLISH_CNF,
|
||||
GPRS_SM_MS_EV_RX_GMM_ESTABLISH_REJ,
|
||||
GPRS_SM_MS_EV_TX_ACT_PDP_CTX_REQ,
|
||||
GPRS_SM_MS_EV_RX_ACT_PDP_CTX_REJ, /* data: enum gsm48_gsm_cause *cause */
|
||||
GPRS_SM_MS_EV_RX_ACT_PDP_CTX_ACC,
|
||||
GPRS_SM_MS_EV_TX_DEACT_PDP_CTX_REQ,
|
||||
GPRS_SM_MS_EV_RX_DEACT_PDP_CTX_REQ,
|
||||
GPRS_SM_MS_EV_RX_DEACT_PDP_CTX_ACC,
|
||||
GPRS_SM_MS_EV_TX_MOD_PDP_CTX_REQ,
|
||||
GPRS_SM_MS_EV_RX_MOD_PDP_CTX_REJ,
|
||||
GPRS_SM_MS_EV_RX_MOD_PDP_CTX_ACC,
|
||||
};
|
||||
|
||||
struct gprs_sm_ms_fsm_ctx {
|
||||
struct osmo_fsm_inst *fi;
|
||||
struct gprs_sm_entity *sme;
|
||||
/* TS 24.008 6.1.3.1.5 retrans counter for T3380: */
|
||||
uint8_t act_pdp_ctx_attempts;
|
||||
};
|
||||
|
||||
int gprs_sm_ms_fsm_init(void);
|
||||
void gprs_sm_ms_fsm_set_log_cat(int logcat);
|
||||
|
||||
int gprs_sm_ms_fsm_ctx_init(struct gprs_sm_ms_fsm_ctx *ctx, struct gprs_sm_entity *sme);
|
||||
void gprs_sm_ms_fsm_ctx_release(struct gprs_sm_ms_fsm_ctx *ctx);
|
|
@ -0,0 +1,17 @@
|
|||
/* GMM PDUs, 3GPP TS 9.5 24.008 GPRS Session Management Messages */
|
||||
#pragma once
|
||||
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/gsm/tlv.h>
|
||||
|
||||
struct gprs_gmm_entity;
|
||||
|
||||
#define GPRS_SM_ALLOC_SIZE 2048
|
||||
#define GPRS_SM_ALLOC_HEADROOM 256
|
||||
|
||||
extern const struct tlv_definition gprs_sm_att_tlvdef;
|
||||
#define gprs_sm_tlv_parse(dec, buf, len) \
|
||||
tlv_parse(dec, &gprs_sm_att_tlvdef, buf, len, 0, 0)
|
||||
|
||||
int gprs_sm_build_act_pdp_ctx_req(struct gprs_sm_entity *sme,
|
||||
struct msgb *msg);
|
|
@ -0,0 +1,207 @@
|
|||
#pragma once
|
||||
|
||||
/* 3GPP TS 24.007:
|
||||
* section 6.5 "Session Management Services for GPRS-Services"
|
||||
* section 9.4 "Services provided by the LLC entity for GPRS services (GSM only)"
|
||||
* section 9.5 "Services provided by the SM for GPRS services"
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/core/prim.h>
|
||||
#include <osmocom/core/socket.h>
|
||||
#include <osmocom/gsm/protocol/gsm_23_003.h>
|
||||
|
||||
#include <osmocom/gprs/sm/sm.h>
|
||||
|
||||
|
||||
struct osmo_gprs_gmm_prim;
|
||||
|
||||
/* 3GPP TS 24.007 */
|
||||
enum osmo_gprs_sm_prim_sap {
|
||||
OSMO_GPRS_SM_SAP_SMREG, /* 6.5.1 */
|
||||
};
|
||||
extern const struct value_string osmo_gprs_sm_prim_sap_names[];
|
||||
static inline const char *osmo_gprs_sm_prim_sap_name(enum osmo_gprs_sm_prim_sap val)
|
||||
{
|
||||
return get_value_string(osmo_gprs_sm_prim_sap_names, val);
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.007 Section 6.6 Registration Services for GPRS-Services */
|
||||
enum osmo_gprs_sm_smreg_prim_type {
|
||||
OSMO_GPRS_SM_SMREG_PDP_ACTIVATE, /* Req/Cnf/Rej/Ind/Rsp */
|
||||
OSMO_GPRS_SM_SMREG_PDP_DEACTIVATE, /* Req/Cnf/Ind */
|
||||
OSMO_GPRS_SM_SMREG_PDP_MODIFY, /* Req/Ind/Cnf/Rej */
|
||||
OSMO_GPRS_SM_SMREG_PDP_ACTIVATE_SEC, /* Req/Cnf/Rej */
|
||||
OSMO_GPRS_SM_SMREG_MBMS_ACTIVATE, /* Req/Cnf/Rej/Ind */
|
||||
};
|
||||
extern const struct value_string osmo_gprs_sm_smreg_prim_type_names[];
|
||||
static inline const char *osmo_gprs_sm_smreg_prim_type_name(enum osmo_gprs_sm_smreg_prim_type val)
|
||||
{
|
||||
return get_value_string(osmo_gprs_sm_smreg_prim_type_names, val);
|
||||
}
|
||||
|
||||
/* Parameters for OSMO_GPRS_SM_SMREG_* prims */
|
||||
struct osmo_gprs_sm_smreg_prim {
|
||||
/* Common fields */
|
||||
uint32_t ms_id;
|
||||
/* Specific fields */
|
||||
union {
|
||||
/* OSMO_GPRS_SM_SMREG_PDP_ACTIVATE | Req, 6.5.1.1 */
|
||||
struct {
|
||||
uint8_t nsapi;
|
||||
enum osmo_gprs_sm_llc_sapi llc_sapi;
|
||||
enum osmo_gprs_sm_pdp_addr_ietf_type pdp_addr_ietf_type;
|
||||
struct osmo_sockaddr pdp_addr_v4;
|
||||
struct osmo_sockaddr pdp_addr_v6;
|
||||
uint8_t qos[OSMO_GPRS_SM_QOS_MAXLEN];
|
||||
uint8_t qos_len;
|
||||
char apn[OSMO_GPRS_SM_APN_MAXLEN];
|
||||
uint8_t pco[OSMO_GPRS_SM_PCO_MAXLEN];
|
||||
uint8_t pco_len;
|
||||
struct {
|
||||
uint32_t ptmsi;
|
||||
bool attach_with_imsi;
|
||||
char imsi[OSMO_IMSI_BUF_SIZE];
|
||||
char imei[GSM23003_IMEI_NUM_DIGITS + 1];
|
||||
char imeisv[GSM23003_IMEISV_NUM_DIGITS+1];
|
||||
} gmm;
|
||||
} pdp_act_req;
|
||||
|
||||
/* OSMO_GPRS_SM_SMREG_PDP_ACTIVATE | Cnf 6.5.1.2 / Rej 6.5.1.3 */
|
||||
struct {
|
||||
bool accepted;
|
||||
uint8_t nsapi;
|
||||
uint8_t pco[OSMO_GPRS_SM_PCO_MAXLEN];
|
||||
uint8_t pco_len;
|
||||
union {
|
||||
struct {
|
||||
struct osmo_sockaddr pdp_addr;
|
||||
uint8_t qos[OSMO_GPRS_SM_QOS_MAXLEN];
|
||||
uint8_t qos_len;
|
||||
} acc;
|
||||
struct {
|
||||
uint8_t cause;
|
||||
} rej;
|
||||
};
|
||||
} pdp_act_cnf;
|
||||
|
||||
/* OSMO_GPRS_SM_SMREG_PDP_ACTIVATE | Ind, 6.5.1.4 */
|
||||
struct {
|
||||
struct osmo_sockaddr pdp_addr;
|
||||
char apn[OSMO_GPRS_SM_APN_MAXLEN];
|
||||
uint8_t pco[OSMO_GPRS_SM_PCO_MAXLEN];
|
||||
uint8_t pco_len;
|
||||
} pdp_act_ind;
|
||||
|
||||
/* OSMO_GPRS_SM_SMREG_PDP_ACTIVATE | Rsp, 6.5.1.14 */
|
||||
struct {
|
||||
uint8_t cause;
|
||||
struct osmo_sockaddr pdp_addr;
|
||||
char apn[OSMO_GPRS_SM_APN_MAXLEN];
|
||||
uint8_t pco[OSMO_GPRS_SM_PCO_MAXLEN];
|
||||
uint8_t pco_len;
|
||||
/* TODO: MBMS protocol configuration options*/
|
||||
} pdp_act_rej_rsp;
|
||||
|
||||
/* OSMO_GPRS_SM_SMREG_PDP_DEACTIVATE, 6.5.1.5 */
|
||||
struct {
|
||||
uint8_t nsapi[OSMO_GPRS_SM_PDP_MAXNSAPI];
|
||||
uint8_t num_nsapi;
|
||||
uint8_t tear_down_ind;
|
||||
uint8_t cause;
|
||||
uint8_t pco[OSMO_GPRS_SM_PCO_MAXLEN];
|
||||
uint8_t pco_len;
|
||||
/* TODO: MBMS protocol configuration options*/
|
||||
} deact_req;
|
||||
|
||||
|
||||
/* OSMO_GPRS_SM_SMREG_PDP_DEACTIVATE | Cnf, 6.5.1.6 */
|
||||
struct {
|
||||
uint8_t nsapi[OSMO_GPRS_SM_PDP_MAXNSAPI];
|
||||
uint8_t num_nsapi;
|
||||
uint8_t pco[OSMO_GPRS_SM_PCO_MAXLEN];
|
||||
uint8_t pco_len;
|
||||
/* TODO: MBMS protocol configuration options*/
|
||||
} deact_cnf;
|
||||
|
||||
/* OSMO_GPRS_SM_SMREG_PDP_DEACTIVATE | Ind, 6.5.1.7 */
|
||||
struct {
|
||||
uint8_t nsapi[OSMO_GPRS_SM_PDP_MAXNSAPI];
|
||||
uint8_t num_nsapi;
|
||||
uint8_t tear_down_ind;
|
||||
uint8_t cause;
|
||||
uint8_t pco[OSMO_GPRS_SM_PCO_MAXLEN];
|
||||
uint8_t pco_len;
|
||||
/* TODO: MBMS protocol configuration options */
|
||||
} deact_ind;
|
||||
|
||||
/* OSMO_GPRS_SM_SMREG_PDP_MODIFY | Ind, 6.5.1.8 */
|
||||
struct {
|
||||
uint8_t qos[OSMO_GPRS_SM_QOS_MAXLEN];
|
||||
uint8_t qos_len;
|
||||
uint8_t nsapi;
|
||||
uint8_t pco[OSMO_GPRS_SM_PCO_MAXLEN];
|
||||
uint8_t pco_len;
|
||||
} pdp_mod_ind;
|
||||
|
||||
/* OSMO_GPRS_SM_SMREG_PDP_MODIFY | Req 6.5.1.18 */
|
||||
struct {
|
||||
uint8_t qos[OSMO_GPRS_SM_QOS_MAXLEN];
|
||||
uint8_t qos_len;
|
||||
uint8_t nsapi;
|
||||
uint8_t tft; /* TODO */
|
||||
uint8_t pco[OSMO_GPRS_SM_PCO_MAXLEN];
|
||||
uint8_t pco_len;
|
||||
} pdp_mod_req;
|
||||
|
||||
/* OSMO_GPRS_SM_SMREG_PDP_MODIFY | Cnf 6.5.1.19 / Rej 6.5.1.20 */
|
||||
struct {
|
||||
bool accepted;
|
||||
uint8_t nsapi;
|
||||
uint8_t pco[OSMO_GPRS_SM_PCO_MAXLEN];
|
||||
union {
|
||||
struct {
|
||||
uint8_t qos[OSMO_GPRS_SM_QOS_MAXLEN];
|
||||
uint8_t qos_len;
|
||||
} acc;
|
||||
struct {
|
||||
uint8_t cause;
|
||||
} rej;
|
||||
};
|
||||
} pdp_mod_cnf;
|
||||
|
||||
/* TODO:
|
||||
* OSMO_GPRS_SM_SMREG_PDP_ACTIVATE_SEC
|
||||
* OSMO_GPRS_SM_SMREG_MBMS_ACTIVATE
|
||||
*/
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
struct osmo_gprs_sm_prim {
|
||||
struct osmo_prim_hdr oph;
|
||||
union {
|
||||
struct osmo_gprs_sm_smreg_prim smreg;
|
||||
};
|
||||
};
|
||||
|
||||
typedef int (*osmo_gprs_sm_prim_up_cb)(struct osmo_gprs_sm_prim *sm_prim, void *up_user_data);
|
||||
void osmo_gprs_sm_prim_set_up_cb(osmo_gprs_sm_prim_up_cb up_cb, void *up_user_data);
|
||||
|
||||
typedef int (*osmo_gprs_sm_prim_down_cb)(struct osmo_gprs_sm_prim *sm_prim, void *down_user_data);
|
||||
void osmo_gprs_sm_prim_set_down_cb(osmo_gprs_sm_prim_down_cb down_cb, void *down_user_data);
|
||||
|
||||
typedef int (*osmo_gprs_sm_prim_gmm_down_cb)(struct osmo_gprs_gmm_prim *gmm_prim, void *gmm_down_user_data);
|
||||
void osmo_gprs_sm_prim_set_gmm_down_cb(osmo_gprs_sm_prim_gmm_down_cb gmm_down_cb, void *gmm_down_user_data);
|
||||
|
||||
int osmo_gprs_sm_prim_upper_down(struct osmo_gprs_sm_prim *sm_prim);
|
||||
int osmo_gprs_sm_prim_lower_up(struct osmo_gprs_sm_prim *sm_prim);
|
||||
int osmo_gprs_sm_prim_gmm_lower_up(struct osmo_gprs_gmm_prim *gmm_prim);
|
||||
|
||||
const char *osmo_gprs_sm_prim_name(const struct osmo_gprs_sm_prim *sm_prim);
|
||||
|
||||
/* Alloc primitive for SMREG SAP: */
|
||||
struct osmo_gprs_sm_prim *osmo_gprs_sm_prim_alloc_smreg_pdp_act_req(void);
|
|
@ -0,0 +1,180 @@
|
|||
#pragma once
|
||||
|
||||
/* 3GPP TS 24.007, private header */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <osmocom/core/timer.h>
|
||||
#include <osmocom/core/linuxlist.h>
|
||||
#include <osmocom/core/msgb.h>
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/endian.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
|
||||
#include <osmocom/gprs/gmm/gmm_prim.h>
|
||||
#include <osmocom/gprs/sm/sm.h>
|
||||
#include <osmocom/gprs/sm/sm_prim.h>
|
||||
#include <osmocom/gprs/sm/sm_ms_fsm.h>
|
||||
|
||||
extern int g_sm_log_cat[_OSMO_GPRS_SM_LOGC_MAX];
|
||||
|
||||
#define LOGSM(lvl, fmt, args...) LOGP(g_sm_log_cat[OSMO_GPRS_SM_LOGC_SM], lvl, fmt, ## args)
|
||||
|
||||
#define msgb_sm_prim(msg) ((struct osmo_gprs_sm_prim *)(msg)->l1h)
|
||||
|
||||
/* 10.5.6.4 Packet data protocol address */
|
||||
enum gprs_sm_pdp_addr_org {
|
||||
GPRS_SM_PDP_ADDR_ORG_ETSI = 0x00,
|
||||
GPRS_SM_PDP_ADDR_ORG_IETF = 0x01,
|
||||
GPRS_SM_PDP_ADDR_ORG_EMPTY = 0x0f,
|
||||
/* All other values are reserved. */
|
||||
};
|
||||
|
||||
/* 10.5.6.4 Packet data protocol address */
|
||||
enum gprs_sm_pdp_addr_etsi_type {
|
||||
GPRS_SM_PDP_ADDR_ETSI_RESERVED = 00, /* used in earlier version of this protocol */
|
||||
GPRS_SM_PDP_ADDR_ETSI_PPP = 0x01,
|
||||
GPRS_SM_PDP_ADDR_ETSI_NON_IP = 0x02,
|
||||
/* All other values are reserved in this version of the protocol. */
|
||||
};
|
||||
|
||||
struct gprs_sm_pdp_addr {
|
||||
#if OSMO_IS_LITTLE_ENDIAN
|
||||
uint8_t spare:4,
|
||||
organization:4; /* enum gprs_sm_pdp_addr_org */
|
||||
uint8_t type; /* osmo_gprs_sm_pdp_addr_{etsi,ietf}_type */
|
||||
union {
|
||||
/* IPv4 */
|
||||
uint32_t addr;
|
||||
|
||||
/* IPv6 */
|
||||
uint8_t addr6[16];
|
||||
|
||||
/* IPv4v6 */
|
||||
#elif OSMO_IS_BIG_ENDIAN
|
||||
/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
|
||||
uint8_t organization:4, spare:4;
|
||||
uint8_t type;
|
||||
union {
|
||||
uint32_t addr;
|
||||
uint8_t addr6[16];
|
||||
#endif
|
||||
struct {
|
||||
uint32_t addr;
|
||||
uint8_t addr6[16];
|
||||
} __attribute__ ((packed)) both;
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct gprs_sm_ms;
|
||||
|
||||
struct gprs_sm_ctx {
|
||||
enum osmo_gprs_sm_location location;
|
||||
osmo_gprs_sm_prim_up_cb sm_up_cb;
|
||||
void *sm_up_cb_user_data;
|
||||
|
||||
osmo_gprs_sm_prim_down_cb sm_down_cb;
|
||||
void *sm_down_cb_user_data;
|
||||
|
||||
osmo_gprs_sm_prim_gmm_down_cb sm_gmm_down_cb;
|
||||
void *sm_gmm_down_cb_user_data;
|
||||
|
||||
struct osmo_tdef *T_defs; /* timers controlled by SM layer */
|
||||
|
||||
struct llist_head ms_list; /* list of struct gprs_sm_ms->list */
|
||||
|
||||
uint32_t next_sess_id;
|
||||
};
|
||||
|
||||
extern struct gprs_sm_ctx *g_ctx;
|
||||
|
||||
/* SM Entity, PDP CTX */
|
||||
struct gprs_sm_entity {
|
||||
struct gprs_sm_ms *ms; /* backpointer */
|
||||
|
||||
uint32_t sess_id;
|
||||
|
||||
uint8_t nsapi;
|
||||
enum osmo_gprs_sm_llc_sapi llc_sapi;
|
||||
|
||||
enum osmo_gprs_sm_pdp_addr_ietf_type pdp_addr_ietf_type;
|
||||
struct osmo_sockaddr pdp_addr_v4;
|
||||
struct osmo_sockaddr pdp_addr_v6;
|
||||
|
||||
uint8_t qos[OSMO_GPRS_SM_QOS_MAXLEN];
|
||||
uint8_t qos_len;
|
||||
|
||||
char apn[OSMO_GPRS_SM_APN_MAXLEN];
|
||||
|
||||
uint8_t pco[OSMO_GPRS_SM_MBIFORM_MAXLEN];
|
||||
uint8_t pco_len;
|
||||
|
||||
uint8_t ti; /* transaction identifier */
|
||||
|
||||
struct gprs_sm_ms_fsm_ctx ms_fsm;
|
||||
};
|
||||
|
||||
/* Mobile Station: */
|
||||
struct gprs_sm_ms {
|
||||
struct llist_head list; /* item in (struct gprs_sm_ctx)->ms_list */
|
||||
|
||||
uint32_t ms_id;
|
||||
|
||||
struct gprs_sm_entity *pdp[OSMO_GPRS_SM_PDP_MAXNSAPI];
|
||||
|
||||
struct {
|
||||
uint32_t ptmsi;
|
||||
char imsi[OSMO_IMSI_BUF_SIZE];
|
||||
char imei[GSM23003_IMEI_NUM_DIGITS + 1];
|
||||
char imeisv[GSM23003_IMEISV_NUM_DIGITS+1];
|
||||
} gmm;
|
||||
};
|
||||
|
||||
/* 10.5.6.2 Network service access point identifier */
|
||||
static inline bool gprs_sm_nsapi_is_valid(uint8_t nsapi)
|
||||
{
|
||||
return nsapi >= 5 && nsapi <= 15;
|
||||
}
|
||||
|
||||
static inline struct gprs_sm_entity *gprs_sm_ms_get_pdp_ctx(struct gprs_sm_ms *ms,
|
||||
uint8_t nsapi) {
|
||||
OSMO_ASSERT(gprs_sm_nsapi_is_valid(nsapi));
|
||||
return ms->pdp[nsapi];
|
||||
}
|
||||
|
||||
/* sm_prim.c: */
|
||||
int gprs_sm_prim_call_up_cb(struct osmo_gprs_sm_prim *sm_prim);
|
||||
int gprs_sm_prim_call_down_cb(struct osmo_gprs_sm_prim *sm_prim);
|
||||
int gprs_sm_prim_call_gmm_down_cb(struct osmo_gprs_gmm_prim *gmm_prim);
|
||||
|
||||
struct osmo_gprs_sm_prim *gprs_sm_prim_alloc_smreg_pdp_act_cnf(void);
|
||||
struct osmo_gprs_sm_prim *gprs_sm_prim_alloc_smreg_pdp_act_ind(void);
|
||||
|
||||
/* sm.c: */
|
||||
struct gprs_sm_ms *gprs_sm_ms_alloc(uint32_t ms_id);
|
||||
void gprs_sm_ms_free(struct gprs_sm_ms *ms);
|
||||
struct gprs_sm_ms *gprs_sm_find_ms_by_id(uint32_t ms_id);
|
||||
|
||||
struct gprs_sm_entity *gprs_sm_entity_alloc(struct gprs_sm_ms *ms, uint32_t nsapi);
|
||||
void gprs_sm_entity_free(struct gprs_sm_entity *sme);
|
||||
struct gprs_sm_entity *gprs_sm_find_sme_by_sess_id(uint32_t sess_id);
|
||||
|
||||
int gprs_sm_submit_gmmsm_assign_req(const struct gprs_sm_entity *sme);
|
||||
int gprs_sm_submit_smreg_pdp_act_cnf(const struct gprs_sm_entity *sme, enum gsm48_gsm_cause cause);
|
||||
int gprs_sm_tx_act_pdp_ctx_req(struct gprs_sm_entity *sme);
|
||||
int gprs_sm_rx(struct gprs_sm_entity *sme, struct gsm48_hdr *gh, unsigned int len);
|
||||
|
||||
|
||||
#define LOGMS(snme, level, fmt, args...) \
|
||||
LOGSM(level, "MS(ID-%u) " fmt, \
|
||||
ms->ms_id, \
|
||||
## args)
|
||||
|
||||
#define LOGSME(sme, level, fmt, args...) \
|
||||
LOGSM(level, "PDP(ID-%u:NSAPI-%u) " fmt, \
|
||||
sme->ms->ms_id, \
|
||||
sme->nsapi, \
|
||||
## args)
|
|
@ -0,0 +1,12 @@
|
|||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: Osmocom [E]GPRS SM (Session Management) Library
|
||||
Description: C Utility Library
|
||||
Version: @VERSION@
|
||||
Requires: libosmo-gprs-gmm libosmocore
|
||||
Libs: -L${libdir} -losmo-gprs-sm
|
||||
Libs.private: -ltalloc
|
||||
Cflags: -I${includedir}/
|
|
@ -4,4 +4,5 @@ SUBDIRS = \
|
|||
rlcmac \
|
||||
sndcp \
|
||||
gmm \
|
||||
sm \
|
||||
$(NULL)
|
||||
|
|
|
@ -176,7 +176,7 @@ struct gprs_gmm_entity *gprs_gmm_find_gmme_by_tlli(uint32_t tlli)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int gprs_gmm_submit_gmmreg_attach_cnf(struct gprs_gmm_entity *gmme, bool accepted, uint8_t cause)
|
||||
int gprs_gmm_submit_gmmreg_attach_cnf(struct gprs_gmm_entity *gmme, bool accepted, uint8_t cause)
|
||||
{
|
||||
struct osmo_gprs_gmm_prim *gmm_prim_tx;
|
||||
int rc;
|
||||
|
@ -196,7 +196,18 @@ static int gprs_gmm_submit_gmmreg_detach_cnf(struct gprs_gmm_entity *gmme)
|
|||
int rc;
|
||||
|
||||
gmm_prim_tx = gprs_gmm_prim_alloc_gmmreg_detach_cnf();
|
||||
gmm_prim_tx->gmmreg.detach_cnf.detach_type = gmme->ms_fsm.detach_type;
|
||||
gmm_prim_tx->gmmreg.detach_cnf.detach_type = gmme->ms_fsm.detach.type;
|
||||
|
||||
rc = gprs_gmm_prim_call_up_cb(gmm_prim_tx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gprs_gmm_submit_gmmsm_establish_cnf(struct gprs_gmm_entity *gmme, uint32_t sess_id, bool accepted, uint8_t cause)
|
||||
{
|
||||
struct osmo_gprs_gmm_prim *gmm_prim_tx;
|
||||
int rc;
|
||||
|
||||
gmm_prim_tx = gprs_gmm_prim_alloc_gmmsm_establish_cnf(sess_id, cause);
|
||||
|
||||
rc = gprs_gmm_prim_call_up_cb(gmm_prim_tx);
|
||||
return rc;
|
||||
|
@ -435,11 +446,6 @@ static int gprs_gmm_rx_att_ack(struct gprs_gmm_entity *gmme, struct gsm48_hdr *g
|
|||
}
|
||||
}
|
||||
|
||||
/* Submit GMMREG-ATTACH-CNF as per TS 24.007 Annex C.1 */
|
||||
rc = gprs_gmm_submit_gmmreg_attach_cnf(gmme, true, 0);
|
||||
if (rc < 0)
|
||||
goto rejected;
|
||||
|
||||
/* Submit LLGMM-ASSIGN-REQ as per TS 24.007 Annex C.1 */
|
||||
rc = gprs_gmm_submit_llgmm_assing_req(gmme);
|
||||
if (rc < 0)
|
||||
|
|
|
@ -44,13 +44,28 @@ static void st_gmm_ms_null(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
|||
}
|
||||
}
|
||||
|
||||
static void st_gmm_ms_deregistered_on_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gprs_gmm_ms_fsm_ctx *ctx = (struct gprs_gmm_ms_fsm_ctx *)fi->priv;
|
||||
|
||||
memset(&ctx->attach, 0, sizeof(ctx->attach));
|
||||
}
|
||||
|
||||
static void st_gmm_ms_deregistered(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gprs_gmm_ms_fsm_ctx *ctx = (struct gprs_gmm_ms_fsm_ctx *)fi->priv;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case GPRS_GMM_MS_EV_DISABLE_GPRS_MODE:
|
||||
gmm_ms_fsm_state_chg(fi, GPRS_GMM_MS_ST_NULL);
|
||||
break;
|
||||
case GPRS_GMM_MS_EV_ATTACH_REQUESTED:
|
||||
rc = gprs_gmm_tx_att_req(ctx->gmme,
|
||||
ctx->attach.type,
|
||||
ctx->attach.with_imsi);
|
||||
if (rc < 0)
|
||||
return;
|
||||
gmm_ms_fsm_state_chg(fi, GPRS_GMM_MS_ST_REGISTERED_INITIATED);
|
||||
break;
|
||||
default:
|
||||
|
@ -60,12 +75,36 @@ static void st_gmm_ms_deregistered(struct osmo_fsm_inst *fi, uint32_t event, voi
|
|||
|
||||
static void st_gmm_ms_registered_initiated(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gprs_gmm_ms_fsm_ctx *ctx = (struct gprs_gmm_ms_fsm_ctx *)fi->priv;
|
||||
int rc;
|
||||
|
||||
switch (event) {
|
||||
case GPRS_GMM_MS_EV_ATTACH_REQUESTED:
|
||||
/* Upper layers request us to retry attaching: */
|
||||
rc = gprs_gmm_tx_att_req(ctx->gmme,
|
||||
ctx->attach.type,
|
||||
ctx->attach.with_imsi);
|
||||
break;
|
||||
case GPRS_GMM_MS_EV_ATTACH_REJECTED:
|
||||
case GPRS_GMM_MS_EV_LOW_LVL_FAIL:
|
||||
gmm_ms_fsm_state_chg(fi, GPRS_GMM_MS_ST_DEREGISTERED);
|
||||
break;
|
||||
case GPRS_GMM_MS_EV_ATTACH_ACCEPTED:
|
||||
if (ctx->attach.explicit_att) {
|
||||
/* Submit GMMREG-ATTACH-CNF as per TS 24.007 Annex C.1 */
|
||||
rc = gprs_gmm_submit_gmmreg_attach_cnf(ctx->gmme, true, 0);
|
||||
if (rc < 0)
|
||||
return;
|
||||
}
|
||||
if (ctx->attach.implicit_att) {
|
||||
/* Submit GMMSM-ESTABLISH-CNF as per TS 24.007 Annex C.3 */
|
||||
unsigned int i;
|
||||
for (i = 0; i < ctx->attach.num_sess_id; i++) {
|
||||
rc = gprs_gmm_submit_gmmsm_establish_cnf(ctx->gmme, ctx->attach.sess_id[i], true, 0);
|
||||
if (rc < 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
gmm_ms_fsm_state_chg(fi, GPRS_GMM_MS_ST_REGISTERED);
|
||||
break;
|
||||
case GPRS_GMM_MS_EV_DETACH_REQUESTED:
|
||||
|
@ -78,7 +117,6 @@ static void st_gmm_ms_registered_initiated(struct osmo_fsm_inst *fi, uint32_t ev
|
|||
|
||||
static void st_gmm_ms_registered(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
struct gprs_gmm_ms_fsm_ctx *ctx = (struct gprs_gmm_ms_fsm_ctx *)fi->priv;
|
||||
switch (event) {
|
||||
case GPRS_GMM_MS_EV_SR_REQUESTED:
|
||||
gmm_ms_fsm_state_chg(fi, GPRS_GMM_MS_ST_REGISTERED);
|
||||
|
@ -87,7 +125,6 @@ static void st_gmm_ms_registered(struct osmo_fsm_inst *fi, uint32_t event, void
|
|||
gmm_ms_fsm_state_chg(fi, GPRS_GMM_MS_ST_RAU_INITIATED);
|
||||
break;
|
||||
case GPRS_GMM_MS_EV_DETACH_REQUESTED:
|
||||
ctx->detach_type = *((enum osmo_gprs_gmm_detach_ms_type *)data);
|
||||
gmm_ms_fsm_state_chg(fi, GPRS_GMM_MS_ST_DEREGISTERED_INITIATED);
|
||||
break;
|
||||
default:
|
||||
|
@ -170,12 +207,14 @@ static struct osmo_fsm_state gmm_ms_fsm_states[] = {
|
|||
X(GPRS_GMM_MS_ST_REGISTERED_INITIATED)|
|
||||
X(GPRS_GMM_MS_ST_DEREGISTERED),
|
||||
.name = "Deregistered",
|
||||
.onenter = st_gmm_ms_deregistered_on_enter,
|
||||
.action = st_gmm_ms_deregistered,
|
||||
},
|
||||
[GPRS_GMM_MS_ST_REGISTERED_INITIATED] = {
|
||||
.in_event_mask =
|
||||
X(GPRS_GMM_MS_EV_ATTACH_REJECTED) |
|
||||
X(GPRS_GMM_MS_EV_LOW_LVL_FAIL) |
|
||||
X(GPRS_GMM_MS_EV_ATTACH_REQUESTED) |
|
||||
X(GPRS_GMM_MS_EV_ATTACH_ACCEPTED) |
|
||||
X(GPRS_GMM_MS_EV_DETACH_REQUESTED),
|
||||
.out_state_mask =
|
||||
|
@ -294,3 +333,65 @@ void gprs_gmm_ms_fsm_ctx_release(struct gprs_gmm_ms_fsm_ctx *ctx)
|
|||
{
|
||||
osmo_fsm_inst_free(ctx->fi);
|
||||
}
|
||||
|
||||
int gprs_gmm_ms_fsm_ctx_request_attach(struct gprs_gmm_ms_fsm_ctx *ctx,
|
||||
enum osmo_gprs_gmm_attach_type attach_type,
|
||||
bool attach_with_imsi,
|
||||
bool explicit_attach,
|
||||
uint32_t sess_id)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ctx->attach.type = attach_type;
|
||||
ctx->attach.with_imsi = attach_with_imsi;
|
||||
if (explicit_attach)
|
||||
ctx->attach.explicit_att = true;
|
||||
else
|
||||
ctx->attach.implicit_att = true;
|
||||
|
||||
if (!explicit_attach) {
|
||||
unsigned int i;
|
||||
bool found = false;
|
||||
if (ctx->attach.num_sess_id == ARRAY_SIZE(ctx->attach.sess_id))
|
||||
return -ENOMEM;
|
||||
for (i = 0; i < ctx->attach.num_sess_id; i++) {
|
||||
if (sess_id == ctx->attach.sess_id[i]) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
ctx->attach.sess_id[ctx->attach.num_sess_id] = sess_id;
|
||||
ctx->attach.num_sess_id++;
|
||||
}
|
||||
}
|
||||
|
||||
rc = osmo_fsm_inst_dispatch(ctx->fi, GPRS_GMM_MS_EV_ATTACH_REQUESTED, NULL);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gprs_gmm_ms_fsm_ctx_request_detach(struct gprs_gmm_ms_fsm_ctx *ctx,
|
||||
enum osmo_gprs_gmm_detach_ms_type detach_type,
|
||||
enum osmo_gprs_gmm_detach_poweroff_type poweroff_type)
|
||||
{
|
||||
int rc;
|
||||
|
||||
ctx->detach.type = detach_type;
|
||||
ctx->detach.poweroff_type = poweroff_type;
|
||||
|
||||
switch (poweroff_type) {
|
||||
case OSMO_GPRS_GMM_DETACH_POWEROFF_TYPE_NORMAL:
|
||||
/* C.3 MS initiated DETACH, GPRS only */
|
||||
rc = osmo_fsm_inst_dispatch(ctx->fi, GPRS_GMM_MS_EV_DETACH_REQUESTED, NULL);
|
||||
break;
|
||||
case OSMO_GPRS_GMM_DETACH_POWEROFF_TYPE_POWEROFF:
|
||||
/* C.4 POWER-OFF DETACH, GPRS only */
|
||||
rc = osmo_fsm_inst_dispatch(ctx->fi, GPRS_GMM_MS_EV_DETACH_REQUESTED_POWEROFF, NULL);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
|
||||
rc = gprs_gmm_tx_detach_req(ctx->gmme, detach_type, poweroff_type);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -271,45 +271,51 @@ static inline struct osmo_gprs_gmm_prim *gmm_prim_gmmsm_alloc(enum osmo_gprs_gmm
|
|||
}
|
||||
|
||||
/* 3GPP TS 24.007 9.5.1.1 GMMSM-ESTABLISH-REQ:*/
|
||||
struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmsm_establish_req(void)
|
||||
struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmsm_establish_req(uint32_t id)
|
||||
{
|
||||
struct osmo_gprs_gmm_prim *gmm_prim;
|
||||
gmm_prim = gmm_prim_gmmsm_alloc(OSMO_GPRS_GMM_GMMSM_ESTABLISH, PRIM_OP_REQUEST, 0);
|
||||
gmm_prim->gmmsm.sess_id = id;
|
||||
return gmm_prim;
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.007 9.5.1.2 GMMSM-ESTABLISH-CNF:*/
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmsm_establish_cnf(uint8_t cause)
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmsm_establish_cnf(uint32_t id, uint8_t cause)
|
||||
{
|
||||
struct osmo_gprs_gmm_prim *gmm_prim;
|
||||
gmm_prim = gmm_prim_gmmsm_alloc(OSMO_GPRS_GMM_GMMSM_ESTABLISH, PRIM_OP_CONFIRM, 0);
|
||||
gmm_prim->gmmsm.establish_cnf.cause = cause;
|
||||
gmm_prim->gmmsm.sess_id = id;
|
||||
gmm_prim->gmmsm.establish_cnf.accepted = (cause == 0);
|
||||
gmm_prim->gmmsm.establish_cnf.rej.cause = cause;
|
||||
return gmm_prim;
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.007 9.5.1.4 GMMSM-RELEASE-IND:*/
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmsm_release_ind(void)
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmsm_release_ind(uint32_t id)
|
||||
{
|
||||
struct osmo_gprs_gmm_prim *gmm_prim;
|
||||
gmm_prim = gmm_prim_gmmsm_alloc(OSMO_GPRS_GMM_GMMSM_RELEASE, PRIM_OP_INDICATION, 0);
|
||||
gmm_prim->gmmsm.sess_id = id;
|
||||
return gmm_prim;
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.007 9.5.1.5 GMMRSM-UNITDATA-REQ:*/
|
||||
struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmsm_unitdata_req(uint8_t *smpdu, unsigned int smpdu_len)
|
||||
/* 3GPP TS 24.007 9.5.1.5 GMMSM-UNITDATA-REQ:*/
|
||||
struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmsm_unitdata_req(uint32_t id, uint8_t *smpdu, unsigned int smpdu_len)
|
||||
{
|
||||
struct osmo_gprs_gmm_prim *gmm_prim;
|
||||
gmm_prim = gmm_prim_gmmsm_alloc(OSMO_GPRS_GMM_GMMSM_UNITDATA, PRIM_OP_REQUEST, smpdu_len);
|
||||
gmm_prim->gmmsm.sess_id = id;
|
||||
gmm_prim->gmmsm.unitdata_req.smpdu = smpdu;
|
||||
gmm_prim->gmmsm.unitdata_req.smpdu_len = smpdu_len;
|
||||
return gmm_prim;
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.007 9.5.1.6 GMMRSM-UNITDATA-IND:*/
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmsm_unitdata_ind(uint8_t *smpdu, unsigned int smpdu_len)
|
||||
/* 3GPP TS 24.007 9.5.1.6 GMMSM-UNITDATA-IND:*/
|
||||
struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmsm_unitdata_ind(uint32_t id, uint8_t *smpdu, unsigned int smpdu_len)
|
||||
{
|
||||
struct osmo_gprs_gmm_prim *gmm_prim;
|
||||
gmm_prim = gmm_prim_gmmsm_alloc(OSMO_GPRS_GMM_GMMSM_UNITDATA, PRIM_OP_INDICATION, smpdu_len);
|
||||
gmm_prim->gmmsm.sess_id = id;
|
||||
gmm_prim->gmmsm.unitdata_ind.smpdu = smpdu;
|
||||
gmm_prim->gmmsm.unitdata_ind.smpdu_len = smpdu_len;
|
||||
return gmm_prim;
|
||||
|
@ -363,15 +369,10 @@ static int gprs_gmm_prim_handle_gmmreg_attach_req(struct osmo_gprs_gmm_prim *gmm
|
|||
if (gmm_prim->gmmreg.attach_req.imeisv[0] != '\0')
|
||||
OSMO_STRLCPY_ARRAY(gmme->imeisv, gmm_prim->gmmreg.attach_req.imeisv);
|
||||
|
||||
rc = gprs_gmm_tx_att_req(gmme,
|
||||
gmm_prim->gmmreg.attach_req.attach_type,
|
||||
gmm_prim->gmmreg.attach_req.attach_with_imsi);
|
||||
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = osmo_fsm_inst_dispatch(gmme->ms_fsm.fi, GPRS_GMM_MS_EV_ATTACH_REQUESTED, NULL);
|
||||
|
||||
rc = gprs_gmm_ms_fsm_ctx_request_attach(&gmme->ms_fsm,
|
||||
gmm_prim->gmmreg.attach_req.attach_type,
|
||||
gmm_prim->gmmreg.attach_req.attach_with_imsi,
|
||||
true, 0);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -387,23 +388,9 @@ static int gprs_gmm_prim_handle_gmmreg_detach_req(struct osmo_gprs_gmm_prim *gmm
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (gmm_prim->gmmreg.detach_req.poweroff_type) {
|
||||
case OSMO_GPRS_GMM_DETACH_POWEROFF_TYPE_NORMAL:
|
||||
/* C.3 MS initiated DETACH, GPRS only */
|
||||
rc = osmo_fsm_inst_dispatch(gmme->ms_fsm.fi, GPRS_GMM_MS_EV_DETACH_REQUESTED,
|
||||
&gmm_prim->gmmreg.detach_req.detach_type);
|
||||
break;
|
||||
case OSMO_GPRS_GMM_DETACH_POWEROFF_TYPE_POWEROFF:
|
||||
/* C.4 POWER-OFF DETACH, GPRS only */
|
||||
rc = osmo_fsm_inst_dispatch(gmme->ms_fsm.fi, GPRS_GMM_MS_EV_DETACH_REQUESTED_POWEROFF, NULL);
|
||||
break;
|
||||
default:
|
||||
OSMO_ASSERT(0);
|
||||
}
|
||||
|
||||
rc = gprs_gmm_tx_detach_req(gmme,
|
||||
gmm_prim->gmmreg.detach_req.detach_type,
|
||||
gmm_prim->gmmreg.detach_req.poweroff_type);
|
||||
rc = gprs_gmm_ms_fsm_ctx_request_detach(&gmme->ms_fsm,
|
||||
gmm_prim->gmmreg.detach_req.detach_type,
|
||||
gmm_prim->gmmreg.detach_req.poweroff_type);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -428,9 +415,26 @@ static int gprs_gmm_prim_handle_gmmreg(struct osmo_gprs_gmm_prim *gmm_prim)
|
|||
static int gprs_gmm_prim_handle_gmmsm_establish_req(struct osmo_gprs_gmm_prim *gmm_prim)
|
||||
{
|
||||
int rc;
|
||||
struct gprs_gmm_entity *gmme;
|
||||
|
||||
rc = gprs_gmm_prim_handle_unsupported(gmm_prim);
|
||||
gmme = llist_first_entry_or_null(&g_ctx->gmme_list, struct gprs_gmm_entity, list);
|
||||
if (!gmme) {
|
||||
gmme = gprs_gmm_gmme_alloc();
|
||||
OSMO_ASSERT(gmme);
|
||||
}
|
||||
gmme->ptmsi = gmm_prim->gmmsm.establish_req.ptmsi;
|
||||
if (gmm_prim->gmmsm.establish_req.imsi[0] != '\0')
|
||||
OSMO_STRLCPY_ARRAY(gmme->imsi, gmm_prim->gmmsm.establish_req.imsi);
|
||||
if (gmm_prim->gmmsm.establish_req.imei[0] != '\0')
|
||||
OSMO_STRLCPY_ARRAY(gmme->imei, gmm_prim->gmmsm.establish_req.imei);
|
||||
if (gmm_prim->gmmsm.establish_req.imeisv[0] != '\0')
|
||||
OSMO_STRLCPY_ARRAY(gmme->imeisv, gmm_prim->gmmsm.establish_req.imeisv);
|
||||
|
||||
rc = gprs_gmm_ms_fsm_ctx_request_attach(&gmme->ms_fsm,
|
||||
gmm_prim->gmmsm.establish_req.attach_type,
|
||||
gmm_prim->gmmsm.establish_req.attach_with_imsi,
|
||||
false,
|
||||
gmm_prim->gmmsm.sess_id);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# This is _NOT_ the library release version, it's an API version.
|
||||
# Please read Chapter 6 "Library interface versions" of the libtool
|
||||
# documentation before making any modification
|
||||
LIBVERSION=0:0:0
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
$(all_includes) \
|
||||
-I$(top_srcdir)/include \
|
||||
$(NULL)
|
||||
|
||||
AM_CFLAGS = \
|
||||
-Wall \
|
||||
$(LIBOSMOGSM_CFLAGS) \
|
||||
$(LIBOSMOCORE_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libosmo-gprs-sm.la \
|
||||
$(NULL)
|
||||
|
||||
libosmo_gprs_sm_la_SOURCES = \
|
||||
sm.c \
|
||||
sm_ms_fsm.c \
|
||||
sm_pdu.c \
|
||||
sm_prim.c \
|
||||
misc.c \
|
||||
$(NULL)
|
||||
|
||||
libosmo_gprs_sm_la_LDFLAGS = \
|
||||
-export-symbols-regex '^osmo_' \
|
||||
-version-info $(LIBVERSION) \
|
||||
-no-undefined \
|
||||
$(NULL)
|
||||
|
||||
libosmo_gprs_sm_la_LIBADD = \
|
||||
$(top_builddir)/src/gmm/libosmo-gprs-gmm.la \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
-lm \
|
||||
$(NULL)
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <osmocom/gprs/sm/sm.h>
|
||||
#include <osmocom/gprs/sm/sm_ms_fsm.h>
|
||||
|
||||
int g_sm_log_cat[_OSMO_GPRS_SM_LOGC_MAX] = { [0 ... _OSMO_GPRS_SM_LOGC_MAX - 1] = DLGLOBAL };
|
||||
|
||||
void osmo_gprs_sm_set_log_cat(enum osmo_gprs_sm_log_cat logc, int logc_num)
|
||||
{
|
||||
OSMO_ASSERT(logc < _OSMO_GPRS_SM_LOGC_MAX);
|
||||
g_sm_log_cat[logc] = logc_num;
|
||||
|
||||
gprs_sm_ms_fsm_set_log_cat(logc_num);
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
/* GPRS SM as per 3GPP TS 24.008, TS 24.007 */
|
||||
/*
|
||||
* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||
*
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <osmocom/core/tdef.h>
|
||||
#include <osmocom/gsm/protocol/gsm_04_08_gprs.h>
|
||||
|
||||
#include <osmocom/gprs/sm/sm.h>
|
||||
#include <osmocom/gprs/sm/sm_prim.h>
|
||||
#include <osmocom/gprs/sm/sm_private.h>
|
||||
#include <osmocom/gprs/sm/sm_ms_fsm.h>
|
||||
#include <osmocom/gprs/sm/sm_pdu.h>
|
||||
|
||||
struct gprs_sm_ctx *g_ctx;
|
||||
|
||||
/* TS 24.008 */
|
||||
static struct osmo_tdef T_defs_sm[] = {
|
||||
{ .T=3380, .default_val=30, .desc = "" },
|
||||
{ 0 } /* empty item at the end */
|
||||
};
|
||||
|
||||
static void gprs_sm_ctx_free(void)
|
||||
{
|
||||
struct gprs_sm_ms *ms;
|
||||
|
||||
while ((ms = llist_first_entry_or_null(&g_ctx->ms_list, struct gprs_sm_ms, list)))
|
||||
gprs_sm_ms_free(ms);
|
||||
|
||||
talloc_free(g_ctx);
|
||||
}
|
||||
|
||||
int osmo_gprs_sm_init(enum osmo_gprs_sm_location location)
|
||||
{
|
||||
bool first_init = true;
|
||||
int rc;
|
||||
OSMO_ASSERT(location == OSMO_GPRS_SM_LOCATION_MS || location == OSMO_GPRS_SM_LOCATION_NETWORK)
|
||||
|
||||
if (g_ctx) {
|
||||
first_init = false;
|
||||
gprs_sm_ctx_free();
|
||||
}
|
||||
|
||||
g_ctx = talloc_zero(NULL, struct gprs_sm_ctx);
|
||||
g_ctx->location = location;
|
||||
g_ctx->T_defs = T_defs_sm;
|
||||
INIT_LLIST_HEAD(&g_ctx->ms_list);
|
||||
|
||||
osmo_tdefs_reset(g_ctx->T_defs);
|
||||
|
||||
if (first_init) {
|
||||
rc = gprs_sm_ms_fsm_init();
|
||||
if (rc != 0) {
|
||||
TALLOC_FREE(g_ctx);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct gprs_sm_ms *gprs_sm_ms_alloc(uint32_t ms_id)
|
||||
{
|
||||
struct gprs_sm_ms *ms;
|
||||
|
||||
ms = talloc_zero(g_ctx, struct gprs_sm_ms);
|
||||
if (!ms)
|
||||
return NULL;
|
||||
|
||||
ms->ms_id = ms_id;
|
||||
|
||||
llist_add(&ms->list, &g_ctx->ms_list);
|
||||
|
||||
return ms;
|
||||
}
|
||||
|
||||
void gprs_sm_ms_free(struct gprs_sm_ms *ms)
|
||||
{
|
||||
unsigned int i;
|
||||
if (!ms)
|
||||
return;
|
||||
|
||||
LOGMS(ms, LOGL_DEBUG, "free()\n");
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(ms->pdp); i++)
|
||||
gprs_sm_entity_free(ms->pdp[i]);
|
||||
|
||||
llist_del(&ms->list);
|
||||
talloc_free(ms);
|
||||
}
|
||||
|
||||
struct gprs_sm_ms *gprs_sm_find_ms_by_id(uint32_t ms_id)
|
||||
{
|
||||
struct gprs_sm_ms *ms;
|
||||
|
||||
llist_for_each_entry(ms, &g_ctx->ms_list, list) {
|
||||
if (ms->ms_id == ms_id)
|
||||
return ms;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct gprs_sm_entity *gprs_sm_entity_alloc(struct gprs_sm_ms *ms, uint32_t nsapi)
|
||||
{
|
||||
struct gprs_sm_entity *sme;
|
||||
sme = talloc_zero(g_ctx, struct gprs_sm_entity);
|
||||
if (!sme)
|
||||
return NULL;
|
||||
|
||||
sme->ms = ms;
|
||||
sme->sess_id = g_ctx->next_sess_id++;
|
||||
sme->nsapi = nsapi;
|
||||
|
||||
if (gprs_sm_ms_fsm_ctx_init(&sme->ms_fsm, sme) < 0) {
|
||||
talloc_free(sme);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OSMO_ASSERT(sme->ms->pdp[sme->nsapi] == NULL);
|
||||
sme->ms->pdp[sme->nsapi] = sme;
|
||||
return sme;
|
||||
}
|
||||
|
||||
void gprs_sm_entity_free(struct gprs_sm_entity *sme)
|
||||
{
|
||||
if (!sme)
|
||||
return;
|
||||
|
||||
gprs_sm_ms_fsm_ctx_release(&sme->ms_fsm);
|
||||
|
||||
sme->ms->pdp[sme->nsapi] = NULL;
|
||||
talloc_free(sme);
|
||||
}
|
||||
|
||||
struct gprs_sm_entity *gprs_sm_find_sme_by_sess_id(uint32_t sess_id)
|
||||
{
|
||||
struct gprs_sm_ms *ms;
|
||||
unsigned int i;
|
||||
|
||||
llist_for_each_entry(ms, &g_ctx->ms_list, list) {
|
||||
for (i = 0; i < ARRAY_SIZE(ms->pdp); i++) {
|
||||
if (!ms->pdp[i])
|
||||
continue;
|
||||
if (ms->pdp[i]->sess_id != sess_id)
|
||||
continue;
|
||||
return ms->pdp[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int gprs_sm_submit_gmmsm_assign_req(const struct gprs_sm_entity *sme)
|
||||
{
|
||||
struct gprs_sm_ms *ms = sme->ms;
|
||||
struct osmo_gprs_gmm_prim *gmm_prim_tx;
|
||||
int rc;
|
||||
|
||||
gmm_prim_tx = osmo_gprs_gmm_prim_alloc_gmmsm_establish_req(sme->sess_id);
|
||||
gmm_prim_tx->gmmsm.establish_req.attach_type = OSMO_GPRS_GMM_ATTACH_TYPE_GPRS;
|
||||
gmm_prim_tx->gmmsm.establish_req.ptmsi = ms->gmm.ptmsi;
|
||||
OSMO_STRLCPY_ARRAY(gmm_prim_tx->gmmsm.establish_req.imsi, ms->gmm.imsi);
|
||||
OSMO_STRLCPY_ARRAY(gmm_prim_tx->gmmsm.establish_req.imei, ms->gmm.imei);
|
||||
OSMO_STRLCPY_ARRAY(gmm_prim_tx->gmmsm.establish_req.imeisv, ms->gmm.imeisv);
|
||||
|
||||
rc = gprs_sm_prim_call_gmm_down_cb(gmm_prim_tx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int gprs_sm_submit_smreg_pdp_act_cnf(const struct gprs_sm_entity *sme, enum gsm48_gsm_cause cause)
|
||||
{
|
||||
struct osmo_gprs_sm_prim *sm_prim_tx;
|
||||
int rc;
|
||||
|
||||
sm_prim_tx = gprs_sm_prim_alloc_smreg_pdp_act_cnf();
|
||||
sm_prim_tx->smreg.ms_id = sme->ms->ms_id;
|
||||
sm_prim_tx->smreg.pdp_act_cnf.accepted = (cause != 0);
|
||||
sm_prim_tx->smreg.pdp_act_cnf.nsapi = sme->nsapi;
|
||||
if (!sm_prim_tx->smreg.pdp_act_cnf.accepted)
|
||||
sm_prim_tx->smreg.pdp_act_cnf.rej.cause = cause;
|
||||
|
||||
rc = gprs_sm_prim_call_up_cb(sm_prim_tx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Tx SM Activate PDP context request, 9.5.1 */
|
||||
int gprs_sm_tx_act_pdp_ctx_req(struct gprs_sm_entity *sme)
|
||||
{
|
||||
struct osmo_gprs_gmm_prim *gmm_prim;
|
||||
int rc;
|
||||
struct msgb *msg;
|
||||
|
||||
LOGSME(sme, LOGL_INFO, "Tx SM Activate PDP Context Request\n");
|
||||
gmm_prim = osmo_gprs_gmm_prim_alloc_gmmsm_unitdata_req(
|
||||
sme->ms->ms_id, NULL, GPRS_SM_ALLOC_SIZE);
|
||||
msg = gmm_prim->oph.msg;
|
||||
msg->l3h = msg->tail;
|
||||
rc = gprs_sm_build_act_pdp_ctx_req(sme, msg);
|
||||
if (rc < 0) {
|
||||
msgb_free(msg);
|
||||
return -EBADMSG;
|
||||
}
|
||||
gmm_prim->gmmsm.unitdata_req.smpdu = msg->l3h;
|
||||
gmm_prim->gmmsm.unitdata_req.smpdu_len = msgb_l3len(msg);
|
||||
|
||||
rc = gprs_sm_prim_call_gmm_down_cb(gmm_prim);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* 3GPP TS 24.008 § 9.5.2: Activate PDP Context Accept */
|
||||
static int gprs_sm_rx_act_pdp_ack(struct gprs_sm_entity *sme,
|
||||
struct gsm48_hdr *gh,
|
||||
unsigned int len)
|
||||
{
|
||||
struct tlv_parsed tp;
|
||||
int rc;
|
||||