libosmo-gprs/tests/llc/llc_prim_test.c

351 lines
13 KiB
C

/* llc_prim tests
*
* (C) 2022 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/msgb.h>
#include <osmocom/gprs/llc/llc_prim.h>
static void *tall_ctx = NULL;
/* stub to get reproducible output, since llme->iov_ui is printed: */
int osmo_get_rand_id(uint8_t *out, size_t len)
{
memset(out, 0x2b, len);
return 0;
}
int test_llc_prim_up_cb(struct osmo_gprs_llc_prim *llc_prim, void *user_data)
{
const char *pdu_name = osmo_gprs_llc_prim_name(llc_prim);
switch (llc_prim->oph.sap) {
case OSMO_GPRS_LLC_SAP_LLGMM:
printf("%s(): Rx %s TLLI=0x%08x\n", __func__, pdu_name, llc_prim->llgmm.tlli);
break;
case OSMO_GPRS_LLC_SAP_LL:
switch (OSMO_PRIM_HDR(&llc_prim->oph)) {
case OSMO_PRIM(OSMO_GPRS_LLC_LL_ASSIGN, PRIM_OP_INDICATION):
printf("%s(): Rx %s TLLI=0x%08x NEW_TLLI=x%08x\n", __func__, pdu_name,
llc_prim->ll.tlli, llc_prim->ll.assign_ind.tlli_new);
break;
default:
printf("%s(): Rx %s TLLI=0x%08x SAPI=%s l3=[%s]\n", __func__, pdu_name,
llc_prim->ll.tlli, osmo_gprs_llc_sapi_name(llc_prim->ll.sapi),
osmo_hexdump(llc_prim->ll.l3_pdu, llc_prim->ll.l3_pdu_len));
break;
}
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
}
return 0;
}
int test_llc_prim_down_cb(struct osmo_gprs_llc_prim *llc_prim, void *user_data)
{
const char *pdu_name = osmo_gprs_llc_prim_name(llc_prim);
switch (llc_prim->oph.sap) {
case OSMO_GPRS_LLC_SAP_GRR:
printf("%s(): Rx %s l3=[%s]\n", __func__, pdu_name,
osmo_hexdump(llc_prim->grr.ll_pdu, llc_prim->grr.ll_pdu_len));
break;
case OSMO_GPRS_LLC_SAP_BSSGP:
printf("%s(): Rx %s TLLI=0x%08x l3=[%s]\n", __func__, pdu_name,
llc_prim->bssgp.tlli, osmo_hexdump(llc_prim->bssgp.ll_pdu, llc_prim->bssgp.ll_pdu_len));
break;
default:
printf("%s(): Unexpected Rx %s\n", __func__, pdu_name);
OSMO_ASSERT(0);
}
return 0;
}
/*
GSM A-I/F DTAP - Attach Request
Protocol Discriminator: GPRS mobility management messages (8)
DTAP GPRS Mobility Management Message Type: Attach Request (0x01)
MS Network Capability
Length: 2
1... .... = GEA/1: Encryption algorithm available
.1.. .... = SM capabilities via dedicated channels: Mobile station supports mobile terminated point to point SMS via dedicated signalling channels
..1. .... = SM capabilities via GPRS channels: Mobile station supports mobile terminated point to point SMS via GPRS packet data channels
...0 .... = UCS2 support: The ME has a preference for the default alphabet (defined in 3GPP TS 23.038 [8b]) over UCS2
.... 01.. = SS Screening Indicator: capability of handling of ellipsis notation and phase 2 error handling (0x1)
.... ..0. = SoLSA Capability: The ME does not support SoLSA
.... ...1 = Revision level indicator: Used by a mobile station supporting R99 or later versions of the protocol
1... .... = PFC feature mode: Mobile station does support BSS packet flow procedures
.110 000. = Extended GEA bits: 0x30
.... ...0 = LCS VA capability: LCS value added location request notification capability not supported
Attach Type
Ciphering Key Sequence Number
DRX Parameter
Mobile Identity - TMSI/P-TMSI (0xf43cec71)
Routing Area Identification - Old routing area identification - RAI: 234-70-5-0
MS Radio Access Capability
GPRS Timer - Ready Timer
Element ID: 0x17
GPRS Timer: 10 sec
000. .... = Unit: value is incremented in multiples of 2 seconds (0)
...0 0101 = Timer value: 5
*/
static uint8_t pdu_gmmm_attach_req[] = {
0x08, 0x01, 0x02, 0xe5, 0xe0, 0x01, 0x0a, 0x00, 0x05, 0xf4, 0xf4, 0x3c, 0xec, 0x71, 0x32, 0xf4,
0x07, 0x00, 0x05, 0x00, 0x17, 0x19, 0x33, 0x43, 0x2b, 0x37, 0x15, 0x9e, 0xf9, 0x88, 0x79, 0xcb,
0xa2, 0x8c, 0x66, 0x21, 0xe7, 0x26, 0x88, 0xb1, 0x98, 0x87, 0x9c, 0x00, 0x17, 0x05
};
/**
MS-SGSN LLC (Mobile Station - Serving GPRS Support Node Logical Link Control) SAPI: GPRS Mobility Management
Address field SAPI: LLGMM
0... .... = Protocol Discriminator_bit: OK
.0.. .... = Command/Response bit: DownLink/UpLink = Response/Command
.... 0001 = SAPI: GPRS Mobility Management (1)
Unconfirmed Information format - UI: UI format: 0x6, Spare bits: 0x0, N(U): 0, E bit: non encrypted frame, PM bit: FCS covers only the frame header and first N202 octets of the information field
110. .... .... .... = UI format: 0x6
...0 0... .... .... = Spare bits: 0x0
.... .000 0000 00.. = N(U): 0
.... .... .... ..0. = E bit: non encrypted frame
.... .... .... ...0 = PM bit: FCS covers only the frame header and first N202 octets of the information field
FCS: 0xf218e2 (correct)
GSM A-I/F DTAP - Attach Request
Protocol Discriminator: GPRS mobility management messages (8)
DTAP GPRS Mobility Management Message Type: Attach Request (0x01)
MS Network Capability
Attach Type
Ciphering Key Sequence Number
DRX Parameter
Mobile Identity - IMSI (262420000000017)
Routing Area Identification - Old routing area identification - RAI: 262-42-27780-68
MS Radio Access Capability
*/
static uint8_t pdu_llc_gmm_att_req[] = {
0x01, 0xc0, 0x00, 0x08, 0x01, 0x01, 0xd5, 0x71, 0x00, 0x00, 0x08, 0x29, 0x26,
0x24, 0x00, 0x00, 0x00, 0x00, 0x71, 0x62, 0xf2, 0x24, 0x6c, 0x84, 0x44, 0x04,
0x11, 0xe5, 0x10, 0x00, 0xe2, 0x18, 0xf2
};
/*
GSM A-I/F DTAP - Identity Request
Protocol Discriminator: GPRS mobility management messages (8)
DTAP GPRS Mobility Management Message Type: Identity Request (0x15)
Identity Type 2
Force to Standby
*/
static uint8_t pdu_gmm_id_req[] = { 0x08, 0x15, 0x02 };
/*
MS-SGSN LLC (Mobile Station - Serving GPRS Support Node Logical Link Control) SAPI: User data 3
Address field SAPI: LL3
0... .... = Protocol Discriminator_bit: OK
.1.. .... = Command/Response bit: DownLink/UpLink = Command/Response
.... 0011 = SAPI: User data 3 (3)
Unnumbered frame: XID
111. .... = U format: 0x7
...1 .... = P/F bit: True
.... 1011 = Command/Response: XID (0xb)
FCS: 0x4e7c8c (correct)
Information Field: Length = 8
XID Parameter Type: Version (LLC version number) - Value: 0
0... .... = XL Bit: 0x0
.000 00.. = Type: 0
.... ..01 = Length: 1
0000 0000 = Parameter Byte: 0x00
XID Parameter Type: N201-U (max info field length for U and UI frames) - Value: 500
0... .... = XL Bit: 0x0
.001 01.. = Type: 5
.... ..10 = Length: 2
0000 0001 = Parameter Byte: 0x01
1111 0100 = Parameter Byte: 0xf4
XID Parameter Type: N201-I (max info field length for I frames) - Value: 1503
0... .... = XL Bit: 0x0
.001 10.. = Type: 6
.... ..10 = Length: 2
0000 0101 = Parameter Byte: 0x05
1101 1111 = Parameter Byte: 0xdf
*/
static uint8_t pdu_llc_xid_cmd_dl[] = {
0x43, 0xfb, 0x01, 0x00, 0x16, 0x01, 0xf4, 0x1a, 0x05, 0xdf, 0x8c, 0x7c, 0x4e };
static void test_llc_prim_ms(void)
{
struct osmo_gprs_llc_prim *llc_prim;
uint32_t tlli = 0xf43cec71;
int rc;
printf("==== %s() [start] ====\n", __func__);
rc = osmo_gprs_llc_init(OSMO_GPRS_LLC_LOCATION_MS, NULL);
OSMO_ASSERT(rc == 0);
osmo_gprs_llc_prim_set_up_cb(test_llc_prim_up_cb, NULL);
osmo_gprs_llc_prim_set_down_cb(test_llc_prim_down_cb, NULL);
/* Tx GMM Attach Request */
llc_prim = osmo_gprs_llc_prim_alloc_ll_unitdata_req(tlli, OSMO_GPRS_LLC_SAPI_GMM, (uint8_t *)pdu_gmmm_attach_req, sizeof(pdu_gmmm_attach_req));
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_upper_down(llc_prim);
OSMO_ASSERT(rc == 0);
/* Rx LLC-GMM-Attach-Accept at MS from SGSN (should be a response message
* but we don't care about upper layers here): */
llc_prim = osmo_gprs_llc_prim_alloc_grr_unitdata_ind(tlli, pdu_llc_gmm_att_req, sizeof(pdu_llc_gmm_att_req));
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_lower_up(llc_prim);
OSMO_ASSERT(rc == 0);
/* 3GPP TS 24.007 Appendix C.6: PDP Act Req + Acc happens here in upper
layers ... as a result, SNDCP submits LL-ESTABLISH-REQ: */
char xid_l3_pars[] = "xid-l3-dummy-buffer";
llc_prim = osmo_gprs_llc_prim_alloc_ll_establish_req(tlli, OSMO_GPRS_LLC_SAPI_SNDCP3, (uint8_t *)xid_l3_pars, sizeof(xid_l3_pars));
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_upper_down(llc_prim);
OSMO_ASSERT(rc == -ENOTSUP); /* ABM mode not supported yet. */
/* Networks sends us a XID command: */
llc_prim = osmo_gprs_llc_prim_alloc_grr_unitdata_ind(tlli, pdu_llc_xid_cmd_dl, sizeof(pdu_llc_xid_cmd_dl));
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_lower_up(llc_prim);
OSMO_ASSERT(rc == 0);
/* Test GMM asking LLC to transmit a response for a Paging Request: */
llc_prim = osmo_gprs_llc_prim_alloc_llgmm_trigger_req(tlli, OSMO_GPRS_LLC_LLGM_TRIGGER_PAGE_RESP);
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_upper_down(llc_prim);
OSMO_ASSERT(rc == 0);
/* Test GMM asking LLC to transmit for Cell Update: */
llc_prim = osmo_gprs_llc_prim_alloc_llgmm_trigger_req(tlli, OSMO_GPRS_LLC_LLGM_TRIGGER_CELL_UPDATE);
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_upper_down(llc_prim);
OSMO_ASSERT(rc == 0);
/* Test GMM asking LLC to transmit for Cell Notification: */
llc_prim = osmo_gprs_llc_prim_alloc_llgmm_trigger_req(tlli, OSMO_GPRS_LLC_LLGM_TRIGGER_CELL_NOTIFICATION);
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_upper_down(llc_prim);
OSMO_ASSERT(rc == 0);
printf("==== %s() [end] ====\n", __func__);
}
static void test_llc_prim_sgsn(void)
{
struct osmo_gprs_llc_prim *llc_prim;
const uint32_t tlli = 0xe1c5d364;
int rc;
struct osmo_gprs_llc_bssgp_prim_cell_id cell_id = {
.rai = {
.mcc = 901,
.mnc = 70,
.mnc_3_digits = false,
.lac = 0x0304,
.rac = 0x01,
},
.ci = 0x9876,
};
printf("==== %s() [start] ====\n", __func__);
rc = osmo_gprs_llc_init(OSMO_GPRS_LLC_LOCATION_SGSN, NULL);
OSMO_ASSERT(rc == 0);
osmo_gprs_llc_prim_set_up_cb(test_llc_prim_up_cb, NULL);
osmo_gprs_llc_prim_set_down_cb(test_llc_prim_down_cb, NULL);
/* Rx LLC-GMM-Attach-Req at SGSN from MS: */
llc_prim = osmo_gprs_llc_prim_alloc_bssgp_ul_unitdata_ind(tlli, pdu_llc_gmm_att_req, sizeof(pdu_llc_gmm_att_req));
llc_prim->bssgp.ul_unitdata_ind.cell_id = cell_id;
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_lower_up(llc_prim);
OSMO_ASSERT(rc == 0);
/* SGSN wants to submit GMM Id Req: */
llc_prim = osmo_gprs_llc_prim_alloc_ll_unitdata_req(tlli, OSMO_GPRS_LLC_SAPI_GMM, (uint8_t *)pdu_gmm_id_req, sizeof(pdu_gmm_id_req));
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_upper_down(llc_prim);
OSMO_ASSERT(rc == 0);
llc_prim = osmo_gprs_llc_prim_alloc_llgmm_assign_req(tlli);
OSMO_ASSERT(llc_prim);
llc_prim->llgmm.assign_req.tlli_new = tlli;
rc = osmo_gprs_llc_prim_upper_down(llc_prim);
OSMO_ASSERT(rc == 0);
llc_prim = osmo_gprs_llc_prim_alloc_llgmm_reset_req(tlli);
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_upper_down(llc_prim);
OSMO_ASSERT(rc == 0);
char xid_l3_pars[] = "xid-l3-dummy-buffer";
llc_prim = osmo_gprs_llc_prim_alloc_ll_establish_req(tlli, OSMO_GPRS_LLC_SAPI_SNDCP3, (uint8_t *)xid_l3_pars, sizeof(xid_l3_pars));
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_upper_down(llc_prim);
OSMO_ASSERT(rc == -ENOTSUP); /* ABM mode not supported yet. */
llc_prim = osmo_gprs_llc_prim_alloc_ll_xid_req(tlli, OSMO_GPRS_LLC_SAPI_SNDCP3, (uint8_t *)xid_l3_pars, sizeof(xid_l3_pars));
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_upper_down(llc_prim);
OSMO_ASSERT(rc == 0);
char sndcp_data[] = "some-sndcp-data";
llc_prim = osmo_gprs_llc_prim_alloc_ll_unitdata_req(tlli, OSMO_GPRS_LLC_SAPI_SNDCP3, (uint8_t *)sndcp_data, sizeof(sndcp_data));
OSMO_ASSERT(llc_prim);
rc = osmo_gprs_llc_prim_upper_down(llc_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_llc_prim_ms();
test_llc_prim_sgsn();
talloc_free(tall_ctx);
}