319 lines
11 KiB
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);
|
|
}
|