libosmo-gprs/tests/sm/sm_prim_test.c

319 lines
11 KiB
C

/* sm_prim tests
*
* (C) 2023 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
* Author: Pau espin Pedrol <pespin@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 <stdio.h>
#include <osmocom/core/application.h>
#include <osmocom/core/logging.h>
#include <osmocom/core/utils.h>
#include <osmocom/core/fsm.h>
#include <osmocom/core/msgb.h>
#include <osmocom/gprs/gmm/gmm_prim.h>
#include <osmocom/gprs/gmm/gmm_private.h>
#include <osmocom/gprs/sndcp/sndcp_prim.h>
#include <osmocom/gprs/sndcp/sndcp_private.h>
#include <osmocom/gprs/sm/sm.h>
#include <osmocom/gprs/sm/sm_prim.h>
static void *tall_ctx = NULL;
static uint32_t last_gmm_establish_sess_id = 0;
/*
GSM A-I/F DTAP - Activate PDP Context Accept
Protocol Discriminator: GPRS session management messages (10)
.... 1010 = Protocol discriminator: GPRS session management messages (0xa)
1... .... = TI flag: allocated by receiver
.000 .... = TIO: 0
01.. .... = Sequence number: 1
DTAP GPRS Session Management Message Type: Activate PDP Context Accept (0x42)
LLC Service Access Point Identifier - Negotiated LLC SAPI
0000 .... = Spare bit(s): 0
.... 0011 = LLC SAPI: SAPI 3 (3)
Quality Of Service - Negotiated QoS
Length: 14
00.. .... = Spare bit(s): 0
..10 0... = Quality of Service Delay class: Delay class 4 (best effort) (4)
.... .011 = Reliability class: Unacknowledged GTP/LLC, Ack RLC, Protected data (3)
0110 .... = Peak throughput: Up to 32 000 octet/s (6)
.... 0... = Spare bit(s): 0
.... .010 = Precedence class: Normal priority (2)
000. .... = Spare bit(s): 0
...1 1111 = Mean throughput: Best effort (31)
011. .... = Traffic class: Interactive class (3)
...1 0... = Delivery order: Without delivery order ('no') (2)
.... .010 = Delivery of erroneous SDUs: Erroneous SDUs are delivered('yes') (2)
Maximum SDU size: 1520 octets (153)
Maximum bitrate for uplink: 63 kbps (63)
Maximum bitrate for downlink: 63 kbps (63)
0001 .... = Residual Bit Error Rate (BER): 5*10-2 (1)
.... 0001 = SDU error ratio: 1*10-2 (1)
0100 00.. = Transfer delay: 200 ms (16)
.... ..11 = Traffic handling priority: Priority level 3 (3)
Guaranteed bitrate for uplink: 0 kbps (255)
Guaranteed bitrate for downlink: 0 kbps (255)
000. .... = Spare bit(s): 0
...0 .... = Signalling indication: Not optimised for signalling traffic
.... 0000 = Source statistics description: unknown (0)
Maximum bitrate for downlink (extended): Use the value indicated by the Maximum bit rate for downlink (0)
Guaranteed bitrate for downlink (extended): Use the value indicated by the Guaranteed bit rate for downlink (0)
Radio Priority
.... .100 = Radio Priority (PDP or SMS): priority level 4 (lowest) (4)
Packet Data Protocol Address - PDP address
Element ID: 0x2b
Length: 6
0000 .... = Spare bit(s): 0
.... 0001 = PDP type organization: IETF allocated address (1)
PDP type number: IPv4 address (33)
IPv4 address: 176.16.222.2
Protocol Configuration Options
Element ID: 0x27
Length: 20
[Link direction: Network to MS (1)]
1... .... = Extension: True
.... .000 = Configuration Protocol: PPP for use with IP PDP type or IP PDN type (0)
Protocol or Container ID: Internet Protocol Control Protocol (0x8021)
Length: 0x10 (16)
PPP IP Control Protocol
Code: Configuration Ack (2)
Identifier: 0 (0x00)
Length: 16
Options: (12 bytes), Primary DNS Server IP Address, Secondary DNS Server IP Address
Primary DNS Server IP Address
Type: Primary DNS Server IP Address (129)
Length: 6
Primary DNS Address: 8.8.8.8
Secondary DNS Server IP Address
Type: Secondary DNS Server IP Address (131)
Length: 6
Secondary DNS Address: 8.8.8.4
*/
static uint8_t pdu_sm_act_pdp_ctx_acc[] = {
0x8a, 0x42, 0x03, 0x0e, 0x23, 0x62, 0x1f, 0x72,
0x99, 0x3f, 0x3f, 0x11, 0x43, 0xff, 0xff, 0x00,
0x00, 0x00, 0x04, 0x2b, 0x06, 0x01, 0x21, 0xb0,
0x10, 0xde, 0x02, 0x27, 0x14, 0x80, 0x80, 0x21,
0x10, 0x02, 0x00, 0x00, 0x10, 0x81, 0x06, 0x08,
0x08, 0x08, 0x08, 0x83, 0x06, 0x08, 0x08, 0x08,
0x04
};
int test_sm_prim_up_cb(struct osmo_gprs_sm_prim *sm_prim, void *user_data)
{
const char *pdu_name = osmo_gprs_sm_prim_name(sm_prim);
switch (sm_prim->oph.sap) {
case OSMO_GPRS_SM_SAP_SMREG:
switch (OSMO_PRIM_HDR(&sm_prim->oph)) {
case OSMO_PRIM(OSMO_GPRS_SM_SMREG_PDP_ACTIVATE, PRIM_OP_CONFIRM):
printf("%s(): Rx %s\n", __func__, pdu_name);
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
}
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
}
return 0;
}
int test_sm_prim_sndcp_up_cb(struct osmo_gprs_sndcp_prim *sndcp_prim, void *user_data)
{
const char *pdu_name = osmo_gprs_sndcp_prim_name(sndcp_prim);
switch (sndcp_prim->oph.sap) {
case OSMO_GPRS_SNDCP_SAP_SNSM:
switch (OSMO_PRIM_HDR(&sndcp_prim->oph)) {
case OSMO_PRIM(OSMO_GPRS_SNDCP_SNSM_ACTIVATE, PRIM_OP_INDICATION):
printf("%s(): Rx %s\n", __func__, pdu_name);
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
}
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
}
return 0;
}
int test_sm_prim_down_cb(struct osmo_gprs_sm_prim *sm_prim, void *user_data)
{
const char *pdu_name = osmo_gprs_sm_prim_name(sm_prim);
switch (sm_prim->oph.sap) {
case OSMO_GPRS_SM_SAP_SMREG:
switch (OSMO_PRIM_HDR(&sm_prim->oph)) {
case OSMO_PRIM(OSMO_GPRS_SM_SMREG_PDP_ACTIVATE, PRIM_OP_REQUEST):
printf("%s(): Rx %s\n", __func__, pdu_name);
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
}
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
}
return 0;
}
int test_sm_prim_gmm_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) {
case OSMO_GPRS_GMM_SAP_GMMSM:
switch (OSMO_PRIM_HDR(&gmm_prim->oph)) {
case OSMO_PRIM(OSMO_GPRS_GMM_GMMSM_ESTABLISH, PRIM_OP_REQUEST):
printf("%s(): Rx %s sess_id=%u\n", __func__, pdu_name,
gmm_prim->gmmsm.sess_id);
last_gmm_establish_sess_id = gmm_prim->gmmsm.sess_id;
break;
case OSMO_PRIM(OSMO_GPRS_GMM_GMMSM_UNITDATA, PRIM_OP_REQUEST):
printf("%s(): Rx %s sess_id=%u SMPDU=[%s]\n", __func__, pdu_name,
gmm_prim->gmmsm.sess_id,
osmo_hexdump(gmm_prim->gmmsm.unitdata_req.smpdu,
gmm_prim->gmmsm.unitdata_req.smpdu_len));
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
}
break;
case OSMO_GPRS_GMM_SAP_GMMRR:
printf("%s(): Rx %s\n", __func__, pdu_name);
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
}
return 0;
}
static void test_sm_prim_ms(void)
{
struct osmo_gprs_sm_prim *sm_prim;
struct osmo_gprs_gmm_prim *gmm_prim;
struct osmo_gprs_sndcp_prim *sndcp_prim;
int rc;
uint8_t nsapi = 6;
enum osmo_gprs_sm_llc_sapi llc_sapi = OSMO_GPRS_SM_LLC_SAPI_SAPI3;
struct osmo_sockaddr pdp_addr_any = {0};
uint8_t qos[OSMO_GPRS_SM_QOS_MAXLEN] = {0};
uint8_t pco[OSMO_GPRS_SM_QOS_MAXLEN] = {0};
char apn[OSMO_GPRS_SM_APN_MAXLEN] = "apn";
uint32_t ptmsi = 0x00000000;
char *imsi = "1234567890";
char *imei = "42342342342342";
char *imeisv = "4234234234234275";
printf("==== %s() [start] ====\n", __func__);
rc = osmo_gprs_sm_init(OSMO_GPRS_SM_LOCATION_MS);
OSMO_ASSERT(rc == 0);
osmo_gprs_sm_prim_set_up_cb(test_sm_prim_up_cb, NULL);
osmo_gprs_sm_prim_set_sndcp_up_cb(test_sm_prim_sndcp_up_cb, NULL);
osmo_gprs_sm_prim_set_down_cb(test_sm_prim_down_cb, NULL);
osmo_gprs_sm_prim_set_gmm_down_cb(test_sm_prim_gmm_down_cb, NULL);
/* MS sends SM PDP Act Req (GMMSM-ESTABLISH.req is submitted down to GMM layer) */
sm_prim = osmo_gprs_sm_prim_alloc_smreg_pdp_act_req();
OSMO_ASSERT(sm_prim);
sm_prim->smreg.pdp_act_req.nsapi = nsapi;
sm_prim->smreg.pdp_act_req.llc_sapi = llc_sapi;
sm_prim->smreg.pdp_act_req.pdp_addr_ietf_type = OSMO_GPRS_SM_PDP_ADDR_IETF_IPV4;
sm_prim->smreg.pdp_act_req.pdp_addr_v4 = pdp_addr_any;
memcpy(sm_prim->smreg.pdp_act_req.qos, qos, sizeof(qos));
sm_prim->smreg.pdp_act_req.qos_len = 1;
memcpy(sm_prim->smreg.pdp_act_req.pco, pco, sizeof(pco));
sm_prim->smreg.pdp_act_req.pco_len = 1;
OSMO_STRLCPY_ARRAY(sm_prim->smreg.pdp_act_req.apn, apn);
sm_prim->smreg.pdp_act_req.gmm.ptmsi = ptmsi;
OSMO_STRLCPY_ARRAY(sm_prim->smreg.pdp_act_req.gmm.imsi, imsi);
OSMO_STRLCPY_ARRAY(sm_prim->smreg.pdp_act_req.gmm.imei, imei);
OSMO_STRLCPY_ARRAY(sm_prim->smreg.pdp_act_req.gmm.imeisv, imeisv);
rc = osmo_gprs_sm_prim_upper_down(sm_prim);
OSMO_ASSERT(rc == 0);
/* GMM internaly does GMM Attach and confirms it is attached to SM: */
gmm_prim = gprs_gmm_prim_alloc_gmmsm_establish_cnf(last_gmm_establish_sess_id, 0);
OSMO_ASSERT(gmm_prim);
rc = osmo_gprs_sm_prim_gmm_lower_up(gmm_prim);
OSMO_ASSERT(rc == 0);
/* SM layer is now sending GMMSM-UNITDATA.req with the Active Pdp Context Req... */
/* Network accepts the pdp ctx req with Activate Pdp Context Accept: */
gmm_prim = gprs_gmm_prim_alloc_gmmsm_unitdata_ind(last_gmm_establish_sess_id,
(uint8_t *)pdu_sm_act_pdp_ctx_acc,
sizeof(pdu_sm_act_pdp_ctx_acc));
OSMO_ASSERT(gmm_prim);
rc = osmo_gprs_sm_prim_gmm_lower_up(gmm_prim);
OSMO_ASSERT(rc == 0);
/* SM layer will trigger SNSM-ACTIVATE.ind to SNDCP layer here. Now,
* SNDCP is expected to do XID config and once done, answer with
* SNSM-ACTIVATE.rsp: */
sndcp_prim = gprs_sndcp_prim_alloc_snsm_activate_rsp(ptmsi, nsapi);
OSMO_ASSERT(sndcp_prim);
rc = osmo_gprs_sm_prim_sndcp_upper_down(sndcp_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:");
osmo_fsm_log_addr(false);
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_sm_prim_ms();
talloc_free(tall_ctx);
}