diff --git a/Makefile.am b/Makefile.am index ba84436..4a55859 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,6 +15,7 @@ SUBDIRS = \ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = \ libosmo-csn1.pc \ + libosmo-gprs-gmm.pc \ libosmo-gprs-llc.pc \ libosmo-gprs-rlcmac.pc \ libosmo-gprs-sndcp.pc \ diff --git a/configure.ac b/configure.ac index 9bdee84..4631b8b 100644 --- a/configure.ac +++ b/configure.ac @@ -75,6 +75,7 @@ AC_MSG_RESULT([CPPFLAGS="$CPPFLAGS"]) AC_CONFIG_HEADERS([config.h]) AC_CONFIG_FILES([libosmo-csn1.pc + libosmo-gprs-gmm.pc libosmo-gprs-llc.pc libosmo-gprs-rlcmac.pc libosmo-gprs-sndcp.pc @@ -82,15 +83,18 @@ AC_CONFIG_FILES([libosmo-csn1.pc include/osmocom/Makefile include/osmocom/csn1/Makefile include/osmocom/gprs/Makefile + include/osmocom/gprs/gmm/Makefile include/osmocom/gprs/llc/Makefile include/osmocom/gprs/rlcmac/Makefile include/osmocom/gprs/sndcp/Makefile src/Makefile src/csn1/Makefile + src/gmm/Makefile src/llc/Makefile src/rlcmac/Makefile src/sndcp/Makefile tests/Makefile + tests/gmm/Makefile tests/llc/Makefile tests/rlcmac/Makefile tests/sndcp/Makefile diff --git a/contrib/libosmo-gprs.spec.in b/contrib/libosmo-gprs.spec.in index 2cb8f67..9ad4817 100644 --- a/contrib/libosmo-gprs.spec.in +++ b/contrib/libosmo-gprs.spec.in @@ -41,6 +41,24 @@ Requires: libosmo-csn1-0 = %{version} This package provides development files for compiling a program using libosmo-csn1 - CSN.1 (Concrete Syntax Notation 1) codec. +%package -n libosmo-gprs-gmm0 +Summary: Osmocom GPRS GMM library +License: AGPL-3.0-or-later +Group: System/Libraries + +%description -n libosmo-gprs-gmm0 +This package provides GMM (GPRS Mobility Management) layer for (E)GPRS. + +%package -n libosmo-gprs-gmm-devel +Summary: Development files for libosmo-gprs-gmm +License: AGPL-3.0-or-later +Group: Development/Libraries/C and C++ +Requires: libosmo-gprs-gmm0 = %{version} + +%description -n libosmo-gprs-gmm-devel +This package provides development files for compiling a program using +libosmo-gprs-gmm - GMM (GPRS Mobility Management) layer for (E)GPRS. + %package -n libosmo-gprs-llc0 Summary: Osmocom GPRS LLC library License: AGPL-3.0-or-later @@ -114,6 +132,8 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +) %post -n libosmo-csn1-0 -p /sbin/ldconfig %postun -n libosmo-csn1-0 -p /sbin/ldconfig +%post -n libosmo-gprs-gmm0 -p /sbin/ldconfig +%postun -n libosmo-gprs-gmm0 -p /sbin/ldconfig %post -n libosmo-gprs-llc0 -p /sbin/ldconfig %postun -n libosmo-gprs-llc0 -p /sbin/ldconfig %post -n libosmo-gprs-rlcmac0 -p /sbin/ldconfig @@ -131,6 +151,17 @@ make %{?_smp_mflags} check || (find . -name testsuite.log -exec cat {} +) %_libdir/libosmo-csn1.so %_libdir/pkgconfig/libosmo-csn1.pc +%files -n libosmo-gprs-gmm0 +%_libdir/libosmo-gprs-gmm.so.0* + +%files -n libosmo-gprs-gmm-devel +%dir %_includedir/%name +%dir %_includedir/%name/osmocom +%dir %_includedir/%name/osmocom/gprs +%_includedir/%name/osmocom/gprs/gmm +%_libdir/libosmo-gprs-gmm.so +%_libdir/pkgconfig/libosmo-gprs-gmm.pc + %files -n libosmo-gprs-llc0 %_libdir/libosmo-gprs-llc.so.0* diff --git a/debian/control b/debian/control index d2c3f12..b2a5d5f 100644 --- a/debian/control +++ b/debian/control @@ -43,6 +43,31 @@ Depends: libosmo-csn1-0 (= ${binary:Version}), ${misc:Depends} Description: Development headers and libraries for the Osmocom CSN.1 codec +Package: libosmo-gprs-gmm0 +Section: libs +Architecture: any +Multi-Arch: same +Pre-Depends: ${misc:Pre-Depends} +Depends: ${misc:Depends}, + ${shlibs:Depends} +Description: Osmocom GMM (GPRS Mobility Management) layer for GPRS and EGPRS + +Package: libosmo-gprs-gmm-dbg +Architecture: any +Section: debug +Multi-Arch: same +Depends: libosmo-gprs-gmm0 (= ${binary:Version}), + ${misc:Depends} +Description: Debug symbols for libosmo-gprs-gmm + +Package: libosmo-gprs-gmm-dev +Architecture: any +Multi-Arch: same +Section: libdevel +Depends: libosmo-gprs-gmm0 (= ${binary:Version}), + ${misc:Depends} +Description: Development headers and libraries for libosmo-gprs-gmm + Package: libosmo-gprs-llc0 Section: libs Architecture: any diff --git a/debian/libosmo-gprs-gmm-dev.install b/debian/libosmo-gprs-gmm-dev.install new file mode 100644 index 0000000..3f3a2c5 --- /dev/null +++ b/debian/libosmo-gprs-gmm-dev.install @@ -0,0 +1,5 @@ +usr/include/osmocom/gprs/gmm +usr/lib/*/libosmo-gprs-gmm*.a +usr/lib/*/libosmo-gprs-gmm*.so +usr/lib/*/libosmo-gprs-gmm*.la +usr/lib/*/pkgconfig/libosmo-gprs-gmm.pc diff --git a/debian/libosmo-gprs-gmm0.install b/debian/libosmo-gprs-gmm0.install new file mode 100644 index 0000000..f7375f8 --- /dev/null +++ b/debian/libosmo-gprs-gmm0.install @@ -0,0 +1 @@ +usr/lib/*/libosmo-gprs-gmm*.so.* diff --git a/include/osmocom/gprs/Makefile.am b/include/osmocom/gprs/Makefile.am index 10763fb..bb6c242 100644 --- a/include/osmocom/gprs/Makefile.am +++ b/include/osmocom/gprs/Makefile.am @@ -1,4 +1,5 @@ SUBDIRS = \ + gmm \ llc \ rlcmac \ sndcp \ diff --git a/include/osmocom/gprs/gmm/Makefile.am b/include/osmocom/gprs/gmm/Makefile.am new file mode 100644 index 0000000..c8d9baf --- /dev/null +++ b/include/osmocom/gprs/gmm/Makefile.am @@ -0,0 +1,11 @@ + +noinst_HEADERS = \ + gmm_private.h \ + $(NULL) + +gmm_HEADERS = \ + gmm.h \ + gmm_prim.h \ + $(NULL) + +gmmdir = $(includedir)/osmocom/gprs/gmm diff --git a/include/osmocom/gprs/gmm/gmm.h b/include/osmocom/gprs/gmm/gmm.h new file mode 100644 index 0000000..bbd2213 --- /dev/null +++ b/include/osmocom/gprs/gmm/gmm.h @@ -0,0 +1,22 @@ +#pragma once + +/* GPRS Mobility Management (GMM) definitions from 3GPP TS 24.008 */ + +#include +#include + +/* Use stack as MS or as network? */ +enum osmo_gprs_gmm_location { + OSMO_GPRS_GMM_LOCATION_UNSET, + OSMO_GPRS_GMM_LOCATION_MS, + OSMO_GPRS_GMM_LOCATION_NETWORK, +}; + +int osmo_gprs_gmm_init(enum osmo_gprs_gmm_location location); + +enum osmo_gprs_gmm_log_cat { + OSMO_GPRS_GMM_LOGC_GMM, + _OSMO_GPRS_GMM_LOGC_MAX, +}; + +void osmo_gprs_gmm_set_log_cat(enum osmo_gprs_gmm_log_cat logc, int logc_num); diff --git a/include/osmocom/gprs/gmm/gmm_prim.h b/include/osmocom/gprs/gmm/gmm_prim.h new file mode 100644 index 0000000..a610986 --- /dev/null +++ b/include/osmocom/gprs/gmm/gmm_prim.h @@ -0,0 +1,102 @@ +#pragma once + +/* 3GPP TS 44.065, section 5 "Service primitives and functions" */ + +/* 3GPP TS 24.007: + * section 6.6 "Registration 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 GMM for GPRS services" + */ + +#include +#include + +#include +#include +#include + +/* 3GPP TS 24.007 (index, "GMMR") */ +enum osmo_gprs_gmm_prim_sap { + OSMO_GPRS_GMM_SAP_GMMREG, /* 6.6 */ + OSMO_GPRS_GMM_SAP_GMMRR, /* GSM only */ + OSMO_GPRS_GMM_SAP_GMMAS, /* UMTS only */ + OSMO_GPRS_GMM_SAP_LLGMM, + OSMO_GPRS_GMM_SAP_GMMSM, + OSMO_GPRS_GMM_SAP_GMMSMS, + OSMO_GPRS_GMM_SAP_GMMRABM, /* UMTS only */ + OSMO_GPRS_GMM_SAP_GMMSS, + OSMO_GPRS_GMM_SAP_GMMSS2, +}; +extern const struct value_string osmo_gprs_gmm_prim_sap_names[]; +static inline const char *osmo_gprs_gmm_prim_sap_name(enum osmo_gprs_gmm_prim_sap val) +{ + return get_value_string(osmo_gprs_gmm_prim_sap_names, val); +} + +/* 6.6 Registration Services for GPRS-Services */ +enum osmo_gprs_gmm_gmmreg_prim_type { + OSMO_GPRS_GMM_GMMREG_ATTACH, /* Req/Cnf/Rej */ + OSMO_GPRS_GMM_GMMREG_DETACH, /* Req/Cnf/Ind */ +}; +extern const struct value_string osmo_gprs_gmm_gmmreg_prim_type_names[]; +static inline const char *osmo_gprs_gmm_gmmreg_prim_type_name(enum osmo_gprs_gmm_gmmreg_prim_type val) +{ + return get_value_string(osmo_gprs_gmm_gmmreg_prim_type_names, val); +} + +/* Parameters for OSMO_GPRS_GMM_GMMREG_* prims */ +struct osmo_gprs_gmm_gmmreg_prim { + /* Common fields */ + /* Specific fields */ + union { + /* OSMO_GPRS_GMM_GMMREG_ATTACH | Req, 6.6.1.1 */ + struct { + /* attach-type, READY-timer, STANDBY-timer */ + } attach_req; + /* OSMO_GPRS_GMM_GMMREG_ATTACH | Cnf 6.6.1.2 / Rej 6.6.1.3 */ + struct { + bool accepted; + union { + struct { + /* PLMNs MT-caps, attach-type. */ + } acc; + struct { + uint8_t cause; + } rej; + }; + } attach_cnf; + /* OSMO_GPRS_GMM_GMMREG_DETACH | Req, 6.6.1.4 */ + struct { + /* detach-type, power-off/normal-detach */ + } detach_req; + /* OSMO_GPRS_GMM_GMMREG_DETACH | Cnf, 6.6.1.5 */ + struct { + /* detach-type */ + } detach_cnf; + /* OSMO_GPRS_GMM_GMMREG_DETACH | Ind, , 6.6.1.6 */ + struct { + /* detach-type */ + } detach_ind; + }; +}; + +struct osmo_gprs_gmm_prim { + struct osmo_prim_hdr oph; + union { + struct osmo_gprs_gmm_gmmreg_prim gmmreg; + }; +}; + +typedef int (*osmo_gprs_gmm_prim_up_cb)(struct osmo_gprs_gmm_prim *gmm_prim, void *up_user_data); +void osmo_gprs_gmm_prim_set_up_cb(osmo_gprs_gmm_prim_up_cb up_cb, void *up_user_data); + +typedef int (*osmo_gprs_gmm_prim_down_cb)(struct osmo_gprs_gmm_prim *gmm_prim, void *down_user_data); +void osmo_gprs_gmm_prim_set_down_cb(osmo_gprs_gmm_prim_down_cb down_cb, void *down_user_data); + +int osmo_gprs_gmm_prim_upper_down(struct osmo_gprs_gmm_prim *gmm_prim); +int osmo_gprs_gmm_prim_lower_up(struct osmo_gprs_gmm_prim *gmm_prim); + +const char *osmo_gprs_gmm_prim_name(const struct osmo_gprs_gmm_prim *gmm_prim); + +/* Alloc primitive for GMMREG SAP: */ +struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmreg_attach_req(void); diff --git a/include/osmocom/gprs/gmm/gmm_private.h b/include/osmocom/gprs/gmm/gmm_private.h new file mode 100644 index 0000000..d0a40a7 --- /dev/null +++ b/include/osmocom/gprs/gmm/gmm_private.h @@ -0,0 +1,52 @@ +#pragma once + +/* 3GPP TS 24.008, private header */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +extern int g_gmm_log_cat[_OSMO_GPRS_GMM_LOGC_MAX]; + +#define LOGGMM(lvl, fmt, args...) LOGP(g_gmm_log_cat[OSMO_GPRS_GMM_LOGC_GMM], lvl, fmt, ## args) + +#define msgb_gmm_prim(msg) ((struct osmo_gprs_gmm_prim *)(msg)->l1h) + +struct gprs_gmm_ctx { + enum osmo_gprs_gmm_location location; + osmo_gprs_gmm_prim_up_cb gmm_up_cb; + void *gmm_up_cb_user_data; + + osmo_gprs_gmm_prim_down_cb gmm_down_cb; + void *gmm_down_cb_user_data; + + struct llist_head gmme_list; /* list of struct gprs_gmm_entity->list */ +}; + +extern struct gprs_gmm_ctx *g_ctx; + +/* GMM Entity: */ +struct gprs_gmm_entity { + struct llist_head list; /* item in (struct gprs_gmm_ctx)->gmme_list */ +}; + +/* gmm_prim.c: */ +struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmm_gmmreg_attach_cnf(void); +int gprs_gmm_prim_call_up_cb(struct osmo_gprs_gmm_prim *gmm_prim); +int gprs_gmm_prim_call_down_cb(struct osmo_gprs_gmm_prim *gmm_prim); + +/* gmm.c: */ +struct gprs_gmm_entity *gprs_gmm_gmme_alloc(void); +void gprs_gmm_gmme_free(struct gprs_gmm_entity *gmme); + +#define LOGGMME(snme, level, fmt, args...) \ + LOGGMM(level, "GMME(%08x) " fmt, \ + 23 /*TODO: use ID */, \ + ## args) diff --git a/libosmo-gprs-gmm.pc.in b/libosmo-gprs-gmm.pc.in new file mode 100644 index 0000000..d53adad --- /dev/null +++ b/libosmo-gprs-gmm.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Osmocom [E]GPRS GMM (GPRS Mobility Management) Library +Description: C Utility Library +Version: @VERSION@ +Requires: libosmocore +Libs: -L${libdir} -losmo-gprs-gmm +Libs.private: -ltalloc +Cflags: -I${includedir}/ diff --git a/src/Makefile.am b/src/Makefile.am index 4821c5d..b0b95ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -3,4 +3,5 @@ SUBDIRS = \ llc \ rlcmac \ sndcp \ + gmm \ $(NULL) diff --git a/src/gmm/Makefile.am b/src/gmm/Makefile.am new file mode 100644 index 0000000..7120b1f --- /dev/null +++ b/src/gmm/Makefile.am @@ -0,0 +1,37 @@ +# 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-gmm.la \ + $(NULL) + +libosmo_gprs_gmm_la_SOURCES = \ + gmm.c \ + gmm_prim.c \ + misc.c \ + $(NULL) + +libosmo_gprs_gmm_la_LDFLAGS = \ + -export-symbols-regex '^osmo_' \ + -version-info $(LIBVERSION) \ + -no-undefined \ + $(NULL) + +libosmo_gprs_gmm_la_LIBADD = \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + -lm \ + $(NULL) diff --git a/src/gmm/gmm.c b/src/gmm/gmm.c new file mode 100644 index 0000000..afe0882 --- /dev/null +++ b/src/gmm/gmm.c @@ -0,0 +1,66 @@ +/* GPRS GMM as per 3GPP TS 24.008, TS 24.007 */ +/* + * (C) 2023 by sysmocom - s.f.m.c. GmbH + * + * 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 . + * + */ + +#include +#include +#include + +#include + +#include +#include +#include + +struct gprs_gmm_ctx *g_ctx; + +int osmo_gprs_gmm_init(enum osmo_gprs_gmm_location location) +{ + if (g_ctx) + talloc_free(g_ctx); + + g_ctx = talloc_zero(NULL, struct gprs_gmm_ctx); + g_ctx->location = location; + INIT_LLIST_HEAD(&g_ctx->gmme_list); + return 0; +} + +struct gprs_gmm_entity *gprs_gmm_gmme_alloc(void) +{ + struct gprs_gmm_entity *gmme; + + gmme = talloc_zero(g_ctx, struct gprs_gmm_entity); + if (!gmme) + return NULL; + + llist_add(&gmme->list, &g_ctx->gmme_list); + + return gmme; +} + +void gprs_gmm_gmme_free(struct gprs_gmm_entity *gmme) +{ + if (!gmme) + return; + + LOGGMME(gmme, LOGL_DEBUG, "free()\n"); + llist_del(&gmme->list); + talloc_free(gmme); +} diff --git a/src/gmm/gmm_prim.c b/src/gmm/gmm_prim.c new file mode 100644 index 0000000..87fb6e6 --- /dev/null +++ b/src/gmm/gmm_prim.c @@ -0,0 +1,292 @@ +/* GMM service primitive implementation as per 3GPP TS 44.065 */ +/* + * (C) 2023 by sysmocom - s.f.m.c. GmbH + * + * 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 . + * + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#define GMM_MSGB_HEADROOM 0 + +const struct value_string osmo_gprs_gmm_prim_sap_names[] = { + { OSMO_GPRS_GMM_SAP_GMMREG, "GMMREG" }, + { OSMO_GPRS_GMM_SAP_GMMRR, "GMRR" }, + { OSMO_GPRS_GMM_SAP_GMMAS, "GMMAS" }, + { OSMO_GPRS_GMM_SAP_LLGMM, "LLGMM" }, + { OSMO_GPRS_GMM_SAP_GMMSM, "GMMSM" }, + { OSMO_GPRS_GMM_SAP_GMMSMS, "GMMSMS" }, + { OSMO_GPRS_GMM_SAP_GMMRABM, "GMMRABM" }, + { OSMO_GPRS_GMM_SAP_GMMSS, "GMMSS" }, + { OSMO_GPRS_GMM_SAP_GMMSS2, "GMMSS2" }, + { 0, NULL } +}; + +const struct value_string osmo_gprs_gmm_gmmreg_prim_type_names[] = { + { OSMO_GPRS_GMM_GMMREG_ATTACH, "ATTACH" }, + { OSMO_GPRS_GMM_GMMREG_DETACH, "DETACH" }, + { 0, NULL } +}; + + +const char *osmo_gprs_gmm_prim_name(const struct osmo_gprs_gmm_prim *gmm_prim) +{ + static char name_buf[256]; + const char *sap = osmo_gprs_gmm_prim_sap_name(gmm_prim->oph.sap); + const char *op = get_value_string(osmo_prim_op_names, gmm_prim->oph.operation); + const char *type; + + switch (gmm_prim->oph.sap) { + case OSMO_GPRS_GMM_SAP_GMMREG: + type = osmo_gprs_gmm_gmmreg_prim_type_name(gmm_prim->oph.primitive); + break; + default: + type = "unsupported-gmm-sap"; + } + + snprintf(name_buf, sizeof(name_buf), "%s-%s.%s", sap, type, op); + return name_buf; +} + +static int gmm_up_cb_dummy(struct osmo_gprs_gmm_prim *gmm_prim, void *user_data) +{ + LOGGMM(LOGL_INFO, "gmm_up_cb_dummy(%s)\n", osmo_gprs_gmm_prim_name(gmm_prim)); + return 0; +} + +static int gmm_down_cb_dummy(struct osmo_gprs_gmm_prim *gmm_prim, void *user_data) +{ + LOGGMM(LOGL_INFO, "gmm_down_cb_dummy(%s)\n", osmo_gprs_gmm_prim_name(gmm_prim)); + return 0; +} + +/* Set callback used by GMM layer to push primitives to higher layers in protocol stack */ +void osmo_gprs_gmm_prim_set_up_cb(osmo_gprs_gmm_prim_up_cb up_cb, void *up_user_data) +{ + g_ctx->gmm_up_cb = up_cb; + g_ctx->gmm_up_cb_user_data = up_user_data; +} + +/* Set callback used by GMM layer to push primitives to lower layers in protocol stack */ +void osmo_gprs_gmm_prim_set_down_cb(osmo_gprs_gmm_prim_down_cb down_cb, void *down_user_data) +{ + g_ctx->gmm_down_cb = down_cb; + g_ctx->gmm_down_cb_user_data = down_user_data; +} + +/******************************** + * Primitive allocation: + ********************************/ + +/* allocate a msgb containing a struct osmo_gprs_gmm_prim + optional l3 data */ +static struct msgb *gprs_gmm_prim_msgb_alloc(unsigned int npdu_len) +{ + const int headroom = GMM_MSGB_HEADROOM; + const int size = headroom + sizeof(struct osmo_gprs_gmm_prim) + npdu_len; + struct msgb *msg = msgb_alloc_headroom(size, headroom, "gmm_prim"); + + if (!msg) + return NULL; + + msg->l1h = msgb_put(msg, sizeof(struct osmo_gprs_gmm_prim)); + + return msg; +} + +struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc(unsigned int sap, unsigned int type, + enum osmo_prim_operation operation, + unsigned int extra_size) +{ + struct msgb *msg = gprs_gmm_prim_msgb_alloc(extra_size); + struct osmo_gprs_gmm_prim *gmm_prim = msgb_gmm_prim(msg); + + osmo_prim_init(&gmm_prim->oph, sap, type, operation, msg); + return gmm_prim; +} + +/*** SN ***/ + +static inline struct osmo_gprs_gmm_prim *gmm_prim_gmmreg_alloc(enum osmo_gprs_gmm_gmmreg_prim_type type, + enum osmo_prim_operation operation, + unsigned int extra_size) +{ + return gprs_gmm_prim_alloc(OSMO_GPRS_GMM_SAP_GMMREG, type, operation, extra_size); +} + +/* TS 24.007 6.6.1.1 GMMREG-ATTACH.request */ +struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmreg_attach_req(void) +{ + struct osmo_gprs_gmm_prim *gmm_prim; + gmm_prim = gmm_prim_gmmreg_alloc(OSMO_GPRS_GMM_GMMREG_ATTACH, PRIM_OP_REQUEST, 0); + return gmm_prim; +} + + +/* 6.6.1.2 GMMREG-ATTACH.cnf */ +struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmreg_attach_cnf(void) +{ + struct osmo_gprs_gmm_prim *gmm_prim; + gmm_prim = gmm_prim_gmmreg_alloc(OSMO_GPRS_GMM_GMMREG_ATTACH, PRIM_OP_CONFIRM, 0); + gmm_prim->gmmreg.attach_cnf.accepted = true; + /* TODO: gmm_prim->gmmreg.attach_cnf.acc.* */ + return gmm_prim; +} +/* TODO: 6.6.1.3 GMMREG-ATTACH.rej */ + +/* TS 24.007 6.6.1.4 GMMREG-DETACH.request */ +struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_detach_req(void) +{ + struct osmo_gprs_gmm_prim *gmm_prim; + gmm_prim = gmm_prim_gmmreg_alloc(OSMO_GPRS_GMM_GMMREG_DETACH, PRIM_OP_REQUEST, 0); + return gmm_prim; +} + +/* TS 24.007 6.6.1.5 GMMREG-DETACH.cnf */ +struct osmo_gprs_gmm_prim *gprs_gmm_prim_alloc_gmmreg_detach_cnf(void) +{ + struct osmo_gprs_gmm_prim *gmm_prim; + gmm_prim = gmm_prim_gmmreg_alloc(OSMO_GPRS_GMM_GMMREG_DETACH, PRIM_OP_CONFIRM, 0); + return gmm_prim; +} + +/* TS 24.007 6.6.1.6 GMMREG-DETACH.cnf */ +struct osmo_gprs_gmm_prim *osmo_gprs_gmm_prim_alloc_gmmreg_detach_ind(void) +{ + struct osmo_gprs_gmm_prim *gmm_prim; + gmm_prim = gmm_prim_gmmreg_alloc(OSMO_GPRS_GMM_GMMREG_DETACH, PRIM_OP_INDICATION, 0); + return gmm_prim; +} + +static int gprs_gmm_prim_handle_unsupported(struct osmo_gprs_gmm_prim *gmm_prim) +{ + LOGGMM(LOGL_ERROR, "Unsupported gmm_prim! %s\n", osmo_gprs_gmm_prim_name(gmm_prim)); + msgb_free(gmm_prim->oph.msg); + return -ENOTSUP; +} + +/******************************** + * Handling from/to upper layers: + ********************************/ + +int gprs_gmm_prim_call_up_cb(struct osmo_gprs_gmm_prim *gmm_prim) +{ + int rc; + if (g_ctx->gmm_up_cb) + rc = g_ctx->gmm_up_cb(gmm_prim, g_ctx->gmm_up_cb_user_data); + else + rc = gmm_up_cb_dummy(gmm_prim, g_ctx->gmm_up_cb_user_data); + msgb_free(gmm_prim->oph.msg); + return rc; +} + +/* TS 24.007 6.6.1.1 GMMREG-Attach.request:*/ +static int gprs_gmm_prim_handle_gmmreg_attach_req(struct osmo_gprs_gmm_prim *gmm_prim) +{ + int rc; + + rc = gprs_gmm_prim_handle_unsupported(gmm_prim); + + msgb_free(gmm_prim->oph.msg); + return rc; +} + +/* TS 24.007 6.6.1.4 GMMREG-Detach.request:*/ +static int gprs_gmm_prim_handle_gmmreg_detach_req(struct osmo_gprs_gmm_prim *gmm_prim) +{ + int rc; + + rc = gprs_gmm_prim_handle_unsupported(gmm_prim); + + msgb_free(gmm_prim->oph.msg); + return rc; +} + +/* GMM higher layers push GMM primitive down to GMM layer: */ +int osmo_gprs_gmm_prim_upper_down(struct osmo_gprs_gmm_prim *gmm_prim) +{ + int rc; + OSMO_ASSERT(g_ctx); + + LOGGMM(LOGL_INFO, "Rx from upper layers: %s\n", osmo_gprs_gmm_prim_name(gmm_prim)); + + if (gmm_prim->oph.sap != OSMO_GPRS_GMM_SAP_GMMREG) + return gprs_gmm_prim_handle_unsupported(gmm_prim); + + switch (OSMO_PRIM_HDR(&gmm_prim->oph)) { + case OSMO_PRIM(OSMO_GPRS_GMM_GMMREG_ATTACH, PRIM_OP_REQUEST): + rc = gprs_gmm_prim_handle_gmmreg_attach_req(gmm_prim); + break; + case OSMO_PRIM(OSMO_GPRS_GMM_GMMREG_DETACH, PRIM_OP_REQUEST): + rc = gprs_gmm_prim_handle_gmmreg_detach_req(gmm_prim); + break; + default: + rc = gprs_gmm_prim_handle_unsupported(gmm_prim); + } + return rc; +} + +/******************************** + * Handling from/to lower layers: + ********************************/ + +int gprs_gmm_prim_call_down_cb(struct osmo_gprs_gmm_prim *gmm_prim) +{ + int rc; + if (g_ctx->gmm_down_cb) + rc = g_ctx->gmm_down_cb(gmm_prim, g_ctx->gmm_down_cb_user_data); + else + rc = gmm_down_cb_dummy(gmm_prim, g_ctx->gmm_down_cb_user_data); + msgb_free(gmm_prim->oph.msg); + return rc; +} + +/* GMM lower layers (LLC) push GMM primitive up to GMM layer: */ +int osmo_gprs_gmm_prim_lower_up(struct osmo_gprs_gmm_prim *gmm_prim) +{ + OSMO_ASSERT(g_ctx); + OSMO_ASSERT(gmm_prim); + struct msgb *msg = gmm_prim->oph.msg; + int rc; + + LOGGMM(LOGL_INFO, "Rx from lower layers: %s\n", osmo_gprs_gmm_prim_name(gmm_prim)); + + switch (gmm_prim->oph.sap) { + case OSMO_GPRS_GMM_SAP_LLGMM: + rc = gprs_gmm_prim_handle_unsupported(gmm_prim); + rc = 1; + break; + default: + rc = gprs_gmm_prim_handle_unsupported(gmm_prim); + rc = 1; + } + + /* Special return value '1' means: do not free */ + if (rc != 1) + msgb_free(msg); + else + rc = 0; + return rc; +} diff --git a/src/gmm/misc.c b/src/gmm/misc.c new file mode 100644 index 0000000..ac141ee --- /dev/null +++ b/src/gmm/misc.c @@ -0,0 +1,31 @@ +/* + * (C) 2023 by sysmocom - s.f.m.c. GmbH + * + * 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 . + * + */ + +#include +#include +#include + +int g_gmm_log_cat[_OSMO_GPRS_GMM_LOGC_MAX] = { [0 ... _OSMO_GPRS_GMM_LOGC_MAX - 1] = DLGLOBAL }; + +void osmo_gprs_gmm_set_log_cat(enum osmo_gprs_gmm_log_cat logc, int logc_num) +{ + OSMO_ASSERT(logc < _OSMO_GPRS_GMM_LOGC_MAX); + g_gmm_log_cat[logc] = logc_num; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index 43488b0..9447b2d 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,5 @@ SUBDIRS = \ + gmm \ llc \ rlcmac \ sndcp \ diff --git a/tests/gmm/Makefile.am b/tests/gmm/Makefile.am new file mode 100644 index 0000000..3885fb5 --- /dev/null +++ b/tests/gmm/Makefile.am @@ -0,0 +1,29 @@ +AM_CPPFLAGS = \ + -I$(top_srcdir)/include/ \ + $(NULL) + +AM_CFLAGS = \ + -Wall \ + $(LIBOSMOGSM_CFLAGS) \ + $(LIBOSMOCORE_CFLAGS) \ + $(NULL) + +AM_LDFLAGS = \ + -no-install \ + $(NULL) + +check_PROGRAMS = \ + gmm_prim_test \ + $(NULL) + +EXTRA_DIST = \ + gmm_prim_test.err \ + gmm_prim_test.ok \ + $(NULL) + +gmm_prim_test_SOURCES = gmm_prim_test.c +gmm_prim_test_LDADD = \ + $(top_builddir)/src/gmm/libosmo-gprs-gmm.la \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOGSM_LIBS) \ + $(NULL) diff --git a/tests/gmm/gmm_prim_test.c b/tests/gmm/gmm_prim_test.c new file mode 100644 index 0000000..c282d58 --- /dev/null +++ b/tests/gmm/gmm_prim_test.c @@ -0,0 +1,103 @@ +/* gmm_prim tests + * + * (C) 2023 by sysmocom - s.f.m.c. GmbH + * Author: Pau espin Pedrol + * + * 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 . + * + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include + +static void *tall_ctx = NULL; + +int test_gmm_prim_up_cb(struct osmo_gprs_gmm_prim *gmm_prim, void *user_data) +{ + const char *pdu_name = osmo_gprs_gmm_prim_name(gmm_prim); + + switch (gmm_prim->oph.sap) { + default: + printf("%s(): Unexpected Rx %s\n", __func__, pdu_name); + OSMO_ASSERT(0); + } + return 0; +} + +int test_gmm_prim_down_cb(struct osmo_gprs_gmm_prim *gmm_prim, void *user_data) +{ + const char *pdu_name = osmo_gprs_gmm_prim_name(gmm_prim); + + switch (gmm_prim->oph.sap) { + default: + printf("%s(): Unexpected Rx %s\n", __func__, pdu_name); + OSMO_ASSERT(0); + } + return 0; +} + +static void test_gmm_prim_ms(void) +{ + //struct osmo_gprs_gmm_prim *gmm_prim; + int rc; + + printf("==== %s() [start] ====\n", __func__); + + rc = osmo_gprs_gmm_init(OSMO_GPRS_GMM_LOCATION_MS); + OSMO_ASSERT(rc == 0); + + osmo_gprs_gmm_prim_set_up_cb(test_gmm_prim_up_cb, NULL); + osmo_gprs_gmm_prim_set_down_cb(test_gmm_prim_down_cb, NULL); + + //gmm_prim = osmo_gprs_gmm_prim_alloc_gmmreg_attach_req(); + //OSMO_ASSERT(gmm_prim); + //rc = osmo_gprs_gmm_prim_upper_down(gmm_prim); + //OSMO_ASSERT(rc == 0); + + printf("==== %s() [end] ====\n", __func__); +} + +static const struct log_info_cat test_log_categories[] = { }; +static const struct log_info test_log_info = { + .cat = test_log_categories, + .num_cat = ARRAY_SIZE(test_log_categories), +}; + +int main(int argc, char *argv[]) +{ + tall_ctx = talloc_named_const(NULL, 1, __FILE__); + + osmo_init_logging2(tall_ctx, &test_log_info); + log_parse_category_mask(osmo_stderr_target, "DLGLOBAL,1:"); + + log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE); + log_set_print_category_hex(osmo_stderr_target, 0); + log_set_print_category(osmo_stderr_target, 1); + log_set_print_level(osmo_stderr_target, 1); + log_set_use_color(osmo_stderr_target, 0); + + test_gmm_prim_ms(); + + talloc_free(tall_ctx); +} diff --git a/tests/gmm/gmm_prim_test.err b/tests/gmm/gmm_prim_test.err new file mode 100644 index 0000000..e69de29 diff --git a/tests/gmm/gmm_prim_test.ok b/tests/gmm/gmm_prim_test.ok new file mode 100644 index 0000000..40b5ffc --- /dev/null +++ b/tests/gmm/gmm_prim_test.ok @@ -0,0 +1,2 @@ +==== test_gmm_prim_ms() [start] ==== +==== test_gmm_prim_ms() [end] ==== diff --git a/tests/testsuite.at b/tests/testsuite.at index e27a320..cfe25d4 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -1,6 +1,13 @@ AT_INIT AT_BANNER([Regression tests]) +AT_SETUP([gmm/gmm_prim]) +AT_KEYWORDS([gmm gmm_prim]) +cat $abs_srcdir/gmm/gmm_prim_test.ok > expout +cat $abs_srcdir/gmm/gmm_prim_test.err > experr +AT_CHECK([$abs_top_builddir/tests/gmm/gmm_prim_test], [0], [expout], [experr]) +AT_CLEANUP + AT_SETUP([llc/llc]) AT_KEYWORDS([llc llc]) cat $abs_srcdir/llc/llc_test.ok > expout