/* llc_prim tests * * (C) 2022 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 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); }