blob: ddf7285f30e57d2f87ab599f6efb0092bcd84f3d [file] [log] [blame]
Alexander Couzens6a161492020-07-12 13:45:50 +02001/*! \file gprs_ns2_message.c
2 * NS-over-FR-over-GRE implementation.
3 * GPRS Networks Service (NS) messages on the Gb interface.
4 * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05)
5 * as well as its successor 3GPP TS 48.016 */
6
7/* (C) 2020 sysmocom - s.f.m.c. GmbH
8 * Author: Alexander Couzens <lynxis@fe80.eu>
9 *
10 * All Rights Reserved
11 *
12 * SPDX-License-Identifier: GPL-2.0+
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 *
27 */
28
29#include <errno.h>
30
31#include <osmocom/core/byteswap.h>
32#include <osmocom/core/rate_ctr.h>
33#include <osmocom/core/stat_item.h>
34#include <osmocom/core/stats.h>
35#include <osmocom/gsm/tlv.h>
36#include <osmocom/gprs/gprs_msgb.h>
37#include <osmocom/gprs/gprs_ns2.h>
38#include <osmocom/gprs/protocol/gsm_08_16.h>
39
40#include "gprs_ns2_internal.h"
41
42#define ERR_IF_NSVC_USES_SNS(nsvc, reason) \
43 do { \
44 if (!nsvc->nse->bss_sns_fi) \
45 break; \
Harald Weltef2949742021-01-20 14:54:14 +010046 LOGNSVC(nsvc, LOGL_DEBUG, "invalid packet %s with SNS\n", reason); \
Alexander Couzens6a161492020-07-12 13:45:50 +020047 } while (0)
48
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010049static int ns2_validate_reset(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +020050{
Harald Welte798efea2020-12-03 16:01:02 +010051 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1) ||
52 !TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_NSEI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020053 *cause = NS_CAUSE_MISSING_ESSENT_IE;
54 return -1;
55 }
56
57 return 0;
58}
59
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010060static int ns2_validate_reset_ack(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +020061{
Harald Welte798efea2020-12-03 16:01:02 +010062 if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_NSEI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020063 *cause = NS_CAUSE_MISSING_ESSENT_IE;
64 return -1;
65 }
66
67 return 0;
68}
69
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010070static int ns2_validate_block(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +020071{
Harald Welte798efea2020-12-03 16:01:02 +010072 if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020073 *cause = NS_CAUSE_MISSING_ESSENT_IE;
74 return -1;
75 }
76
77 return 0;
78}
79
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010080static int ns2_validate_block_ack(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +020081{
Harald Welte798efea2020-12-03 16:01:02 +010082 if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020083 *cause = NS_CAUSE_MISSING_ESSENT_IE;
84 return -1;
85 }
86
87 return 0;
88}
89
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010090static int ns2_validate_status(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +020091{
92
Harald Welte798efea2020-12-03 16:01:02 +010093 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020094 *cause = NS_CAUSE_MISSING_ESSENT_IE;
95 return -1;
96 }
97
98 uint8_t _cause = tlvp_val8(tp, NS_IE_VCI, 0);
99
100 switch (_cause) {
101 case NS_CAUSE_NSVC_BLOCKED:
102 case NS_CAUSE_NSVC_UNKNOWN:
Harald Welte798efea2020-12-03 16:01:02 +0100103 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200104 *cause = NS_CAUSE_MISSING_ESSENT_IE;
105 return -1;
106 }
107 break;
108 case NS_CAUSE_SEM_INCORR_PDU:
109 case NS_CAUSE_PDU_INCOMP_PSTATE:
110 case NS_CAUSE_PROTO_ERR_UNSPEC:
111 case NS_CAUSE_INVAL_ESSENT_IE:
112 case NS_CAUSE_MISSING_ESSENT_IE:
Harald Welte798efea2020-12-03 16:01:02 +0100113 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200114 *cause = NS_CAUSE_MISSING_ESSENT_IE;
115 return -1;
116 }
117 break;
118 case NS_CAUSE_BVCI_UNKNOWN:
Harald Welte798efea2020-12-03 16:01:02 +0100119 if (!TLVP_PRES_LEN(tp, NS_IE_BVCI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200120 *cause = NS_CAUSE_MISSING_ESSENT_IE;
121 return -1;
122 }
123 break;
124 case NS_CAUSE_UNKN_IP_TEST_FAILED:
Harald Welte798efea2020-12-03 16:01:02 +0100125 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST) && !TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200126 *cause = NS_CAUSE_MISSING_ESSENT_IE;
127 return -1;
128 }
129 break;
130 }
131
132 return 0;
133}
134
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100135int ns2_validate(struct gprs_ns2_vc *nsvc,
136 uint8_t pdu_type,
137 struct msgb *msg,
138 struct tlv_parsed *tp,
139 uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +0200140{
141 switch (pdu_type) {
142 case NS_PDUT_RESET:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100143 return ns2_validate_reset(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200144 case NS_PDUT_RESET_ACK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100145 return ns2_validate_reset_ack(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200146 case NS_PDUT_BLOCK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100147 return ns2_validate_block(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200148 case NS_PDUT_BLOCK_ACK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100149 return ns2_validate_block_ack(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200150 case NS_PDUT_STATUS:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100151 return ns2_validate_status(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200152
153 /* following PDUs doesn't have any payloads */
154 case NS_PDUT_ALIVE:
155 case NS_PDUT_ALIVE_ACK:
156 case NS_PDUT_UNBLOCK:
157 case NS_PDUT_UNBLOCK_ACK:
158 if (msgb_l2len(msg) != sizeof(struct gprs_ns_hdr)) {
159 *cause = NS_CAUSE_PROTO_ERR_UNSPEC;
160 return -1;
161 }
162 break;
163 }
164
165 return 0;
166}
167
168
Harald Welte5a5bf722021-01-30 21:49:28 +0100169static int ns_vc_tx(struct gprs_ns2_vc *nsvc, struct msgb *msg)
170{
Harald Weltef22ae5a2021-01-30 22:01:28 +0100171 unsigned int bytes = msgb_length(msg);
172 int rc;
Harald Weltee5f55f72021-01-30 21:51:15 +0100173
Harald Weltef22ae5a2021-01-30 22:01:28 +0100174
175 rc = nsvc->bind->send_vc(nsvc, msg);
176 if (rc < 0) {
177 rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT_DROP]);
178 rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT_DROP], bytes);
179 } else {
180 rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]);
181 rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT], bytes);
182 }
183
184 return rc;
Harald Welte5a5bf722021-01-30 21:49:28 +0100185}
186
Alexander Couzens6a161492020-07-12 13:45:50 +0200187/* transmit functions */
188static int ns2_tx_simple(struct gprs_ns2_vc *nsvc, uint8_t pdu_type)
189{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100190 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200191 struct gprs_ns_hdr *nsh;
192
Daniel Willmann751977b2020-12-02 18:59:44 +0100193 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200194 log_set_context(LOG_CTX_GB_NSVC, nsvc);
195
196 if (!msg)
197 return -ENOMEM;
198
199 msg->l2h = msgb_put(msg, sizeof(*nsh));
200 nsh = (struct gprs_ns_hdr *) msg->l2h;
201
202 nsh->pdu_type = pdu_type;
203
Harald Welte5a5bf722021-01-30 21:49:28 +0100204 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200205}
206
Harald Welte5bef2cc2020-09-18 22:33:24 +0200207/*! Transmit a NS-BLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200208 * \param[in] vc NS-VC on which the NS-BLOCK is to be transmitted
209 * \param[in] cause Numeric NS Cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200210 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200211int ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause)
212{
213 struct msgb *msg;
214 struct gprs_ns_hdr *nsh;
215 uint16_t nsvci = osmo_htons(nsvc->nsvci);
216
Daniel Willmann751977b2020-12-02 18:59:44 +0100217 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200218 log_set_context(LOG_CTX_GB_NSVC, nsvc);
219
220 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK");
221
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100222 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200223 if (!msg)
224 return -ENOMEM;
225
Harald Weltef2949742021-01-20 14:54:14 +0100226 LOGNSVC(nsvc, LOGL_INFO, "Tx NS BLOCK (cause=%s)\n", gprs_ns2_cause_str(cause));
Alexander Couzens6a161492020-07-12 13:45:50 +0200227
228 rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
229
230 msg->l2h = msgb_put(msg, sizeof(*nsh));
231 nsh = (struct gprs_ns_hdr *) msg->l2h;
232 nsh->pdu_type = NS_PDUT_BLOCK;
233
234 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
235 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
236
Harald Welte5a5bf722021-01-30 21:49:28 +0100237 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200238}
239
Harald Welte5bef2cc2020-09-18 22:33:24 +0200240/*! Transmit a NS-BLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200241 * \param[in] nsvc NS-VC on which the NS-BLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200242 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200243int ns2_tx_block_ack(struct gprs_ns2_vc *nsvc)
244{
245 struct msgb *msg;
246 struct gprs_ns_hdr *nsh;
247 uint16_t nsvci = osmo_htons(nsvc->nsvci);
248
Daniel Willmann751977b2020-12-02 18:59:44 +0100249 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200250 log_set_context(LOG_CTX_GB_NSVC, nsvc);
251
252 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK ACK");
253
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100254 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200255 if (!msg)
256 return -ENOMEM;
257
Harald Weltef2949742021-01-20 14:54:14 +0100258 LOGNSVC(nsvc, LOGL_INFO, "Tx NS BLOCK ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200259
Alexander Couzens6a161492020-07-12 13:45:50 +0200260 msg->l2h = msgb_put(msg, sizeof(*nsh));
261 nsh = (struct gprs_ns_hdr *) msg->l2h;
262 nsh->pdu_type = NS_PDUT_BLOCK_ACK;
263
264 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
265
Harald Welte5a5bf722021-01-30 21:49:28 +0100266 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200267}
268
Harald Welte5bef2cc2020-09-18 22:33:24 +0200269/*! Transmit a NS-RESET on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200270 * \param[in] nsvc NS-VC used for transmission
271 * \paam[in] cause Numeric NS cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200272 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200273int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause)
274{
275 struct msgb *msg;
276 struct gprs_ns_hdr *nsh;
277 uint16_t nsvci = osmo_htons(nsvc->nsvci);
278 uint16_t nsei = osmo_htons(nsvc->nse->nsei);
279
Daniel Willmann751977b2020-12-02 18:59:44 +0100280 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200281 log_set_context(LOG_CTX_GB_NSVC, nsvc);
282
283 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET");
284
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100285 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200286 if (!msg)
287 return -ENOMEM;
288
Harald Weltef2949742021-01-20 14:54:14 +0100289 LOGNSVC(nsvc, LOGL_INFO, "Tx NS RESET (cause=%s)\n", gprs_ns2_cause_str(cause));
Alexander Couzens6a161492020-07-12 13:45:50 +0200290
291 msg->l2h = msgb_put(msg, sizeof(*nsh));
292 nsh = (struct gprs_ns_hdr *) msg->l2h;
293 nsh->pdu_type = NS_PDUT_RESET;
294
295 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
296 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
297 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei);
298
Harald Welte5a5bf722021-01-30 21:49:28 +0100299 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200300}
301
Harald Welte5bef2cc2020-09-18 22:33:24 +0200302/*! Transmit a NS-RESET-ACK on a given NS-VC.
303 * \param[in] nsvc NS-VC used for transmission
304 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200305int ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc)
306{
307 struct msgb *msg;
308 struct gprs_ns_hdr *nsh;
309 uint16_t nsvci, nsei;
310
Harald Welte5bef2cc2020-09-18 22:33:24 +0200311 /* Section 9.2.6 */
Daniel Willmann751977b2020-12-02 18:59:44 +0100312 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200313 log_set_context(LOG_CTX_GB_NSVC, nsvc);
314
315 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET ACK");
316
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100317 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200318 if (!msg)
319 return -ENOMEM;
320
321 nsvci = osmo_htons(nsvc->nsvci);
322 nsei = osmo_htons(nsvc->nse->nsei);
323
324 msg->l2h = msgb_put(msg, sizeof(*nsh));
325 nsh = (struct gprs_ns_hdr *) msg->l2h;
326
327 nsh->pdu_type = NS_PDUT_RESET_ACK;
328
Harald Weltef2949742021-01-20 14:54:14 +0100329 LOGNSVC(nsvc, LOGL_INFO, "Tx NS RESET ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200330
331 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
332 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
333
Harald Welte5a5bf722021-01-30 21:49:28 +0100334 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200335}
336
Harald Welte5bef2cc2020-09-18 22:33:24 +0200337/*! Transmit a NS-UNBLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200338 * \param[in] nsvc NS-VC on which the NS-UNBLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200339 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200340int ns2_tx_unblock(struct gprs_ns2_vc *nsvc)
341{
Daniel Willmann751977b2020-12-02 18:59:44 +0100342 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200343 log_set_context(LOG_CTX_GB_NSVC, nsvc);
344
345 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK");
346
Harald Weltef2949742021-01-20 14:54:14 +0100347 LOGNSVC(nsvc, LOGL_INFO, "Tx NS UNBLOCK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200348
349 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK);
350}
351
352
Harald Welte5bef2cc2020-09-18 22:33:24 +0200353/*! Transmit a NS-UNBLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200354 * \param[in] nsvc NS-VC on which the NS-UNBLOCK-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200355 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200356int ns2_tx_unblock_ack(struct gprs_ns2_vc *nsvc)
357{
Daniel Willmann751977b2020-12-02 18:59:44 +0100358 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200359 log_set_context(LOG_CTX_GB_NSVC, nsvc);
360
361 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK ACK");
362
Harald Weltef2949742021-01-20 14:54:14 +0100363 LOGNSVC(nsvc, LOGL_INFO, "Tx NS UNBLOCK_ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200364
365 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
366}
367
Harald Welte5bef2cc2020-09-18 22:33:24 +0200368/*! Transmit a NS-ALIVE on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200369 * \param[in] nsvc NS-VC on which the NS-ALIVE is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200370 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200371int ns2_tx_alive(struct gprs_ns2_vc *nsvc)
372{
Daniel Willmann751977b2020-12-02 18:59:44 +0100373 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200374 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Harald Weltef2949742021-01-20 14:54:14 +0100375 LOGNSVC(nsvc, LOGL_DEBUG, "Tx NS ALIVE\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200376
377 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE);
378}
379
Harald Welte5bef2cc2020-09-18 22:33:24 +0200380/*! Transmit a NS-ALIVE-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200381 * \param[in] nsvc NS-VC on which the NS-ALIVE-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200382 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200383int ns2_tx_alive_ack(struct gprs_ns2_vc *nsvc)
384{
Daniel Willmann751977b2020-12-02 18:59:44 +0100385 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200386 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Harald Weltef2949742021-01-20 14:54:14 +0100387 LOGNSVC(nsvc, LOGL_DEBUG, "Tx NS ALIVE_ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200388
389 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE_ACK);
390}
391
Harald Welte5bef2cc2020-09-18 22:33:24 +0200392/*! Transmit NS-UNITDATA on a given NS-VC.
393 * \param[in] nsvc NS-VC on which the NS-UNITDATA is to be transmitted
394 * \param[in] bvci BVCI to encode in NS-UNITDATA header
395 * \param[in] sducontrol SDU control octet of NS header
396 * \param[in] msg message buffer containing payload
397 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200398int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
399 uint16_t bvci, uint8_t sducontrol,
400 struct msgb *msg)
401{
402 struct gprs_ns_hdr *nsh;
403
Daniel Willmann751977b2020-12-02 18:59:44 +0100404 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200405 log_set_context(LOG_CTX_GB_NSVC, nsvc);
406
407 msg->l2h = msgb_push(msg, sizeof(*nsh) + 3);
408 nsh = (struct gprs_ns_hdr *) msg->l2h;
409 if (!nsh) {
Harald Weltef2949742021-01-20 14:54:14 +0100410 LOGNSVC(nsvc, LOGL_ERROR, "Not enough headroom for NS header\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200411 msgb_free(msg);
412 return -EIO;
413 }
414
415 nsh->pdu_type = NS_PDUT_UNITDATA;
416 nsh->data[0] = sducontrol;
417 nsh->data[1] = bvci >> 8;
418 nsh->data[2] = bvci & 0xff;
419
Harald Welte5a5bf722021-01-30 21:49:28 +0100420 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200421}
422
Harald Welte5bef2cc2020-09-18 22:33:24 +0200423/*! Transmit a NS-STATUS on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200424 * \param[in] nsvc NS-VC to be used for transmission
425 * \param[in] cause Numeric NS cause value
426 * \param[in] bvci BVCI to be reset within NSVC
Harald Welte5bef2cc2020-09-18 22:33:24 +0200427 * \param[in] orig_msg message causing the STATUS
428 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200429int ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,
430 uint16_t bvci, struct msgb *orig_msg)
431{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100432 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200433 struct gprs_ns_hdr *nsh;
434 uint16_t nsvci = osmo_htons(nsvc->nsvci);
Alexander Couzenscf1fa632021-02-15 04:51:14 +0100435 unsigned int orig_len, max_orig_len;
Alexander Couzens6a161492020-07-12 13:45:50 +0200436
Daniel Willmann751977b2020-12-02 18:59:44 +0100437 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200438 log_set_context(LOG_CTX_GB_NSVC, nsvc);
439
440 bvci = osmo_htons(bvci);
441
442 if (!msg)
443 return -ENOMEM;
444
Harald Weltef2949742021-01-20 14:54:14 +0100445 LOGNSVC(nsvc, LOGL_NOTICE, "Tx NS STATUS (cause=%s)\n", gprs_ns2_cause_str(cause));
Alexander Couzens6a161492020-07-12 13:45:50 +0200446
447 msg->l2h = msgb_put(msg, sizeof(*nsh));
448 nsh = (struct gprs_ns_hdr *) msg->l2h;
449 nsh->pdu_type = NS_PDUT_STATUS;
450
451 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
452
Alexander Couzens6a161492020-07-12 13:45:50 +0200453 switch (cause) {
Alexander Couzensce646c22021-02-15 04:55:08 +0100454 case NS_CAUSE_NSVC_BLOCKED:
455 case NS_CAUSE_NSVC_UNKNOWN:
456 /* Section 9.2.7.1: Static conditions for NS-VCI */
457 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
458 break;
Alexander Couzens6a161492020-07-12 13:45:50 +0200459 case NS_CAUSE_SEM_INCORR_PDU:
460 case NS_CAUSE_PDU_INCOMP_PSTATE:
461 case NS_CAUSE_PROTO_ERR_UNSPEC:
462 case NS_CAUSE_INVAL_ESSENT_IE:
463 case NS_CAUSE_MISSING_ESSENT_IE:
Alexander Couzensce646c22021-02-15 04:55:08 +0100464 /* Section 9.2.7.2: Static conditions for NS PDU */
Alexander Couzenscf1fa632021-02-15 04:51:14 +0100465 /* ensure the PDU doesn't exceed the MTU */
466 orig_len = msgb_l2len(orig_msg);
467 max_orig_len = msgb_length(msg) + TVLV_GROSS_LEN(orig_len);
468 if (max_orig_len > nsvc->bind->mtu)
469 orig_len -= max_orig_len - nsvc->bind->mtu;
470 msgb_tvlv_put(msg, NS_IE_PDU, orig_len, orig_msg->l2h);
Alexander Couzens6a161492020-07-12 13:45:50 +0200471 break;
Alexander Couzensce646c22021-02-15 04:55:08 +0100472 case NS_CAUSE_BVCI_UNKNOWN:
473 /* Section 9.2.7.3: Static conditions for BVCI */
474 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci);
475 break;
476
Alexander Couzens6a161492020-07-12 13:45:50 +0200477 default:
478 break;
479 }
480
Harald Welte5a5bf722021-01-30 21:49:28 +0100481 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200482}
483
484
485/*! Encode + Transmit a SNS-ACK as per Section 9.3.1.
486 * \param[in] nsvc NS-VC through which to transmit the ACK
487 * \param[in] trans_id Transaction ID which to acknowledge
488 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
489 * \param[in] ip4_elems Array of IPv4 Elements
490 * \param[in] num_ip4_elems number of ip4_elems
491 * \returns 0 on success; negative in case of error */
492int ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,
493 const struct gprs_ns_ie_ip4_elem *ip4_elems,
494 unsigned int num_ip4_elems,
495 const struct gprs_ns_ie_ip6_elem *ip6_elems,
496 unsigned int num_ip6_elems)
497{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100498 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200499 struct gprs_ns_hdr *nsh;
500 uint16_t nsei;
501
502 if (!nsvc)
503 return -1;
504
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100505 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200506
Daniel Willmann751977b2020-12-02 18:59:44 +0100507 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200508 log_set_context(LOG_CTX_GB_NSVC, nsvc);
509 if (!msg)
510 return -ENOMEM;
511
512 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100513 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200514 msgb_free(msg);
515 return -EIO;
516 }
517
518 nsei = osmo_htons(nsvc->nse->nsei);
519
520 msg->l2h = msgb_put(msg, sizeof(*nsh));
521 nsh = (struct gprs_ns_hdr *) msg->l2h;
522
523 nsh->pdu_type = SNS_PDUT_ACK;
524 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
525 msgb_v_put(msg, trans_id);
526 if (cause)
527 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
528 if (ip4_elems) {
529 /* List of IP4 Elements 10.3.2c */
530 msgb_tvlv_put(msg, NS_IE_IPv4_LIST,
531 num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
532 (const uint8_t *)ip4_elems);
533 }
534 if (ip6_elems) {
535 /* List of IP6 elements 10.3.2d */
536 msgb_tvlv_put(msg, NS_IE_IPv6_LIST,
537 num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
538 (const uint8_t *)ip6_elems);
539 }
540
Harald Welte5a5bf722021-01-30 21:49:28 +0100541 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200542}
543
544/*! Encode + Transmit a SNS-CONFIG as per Section 9.3.4.
545 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
546 * \param[in] end_flag Whether or not this is the last SNS-CONFIG
547 * \param[in] ip4_elems Array of IPv4 Elements
548 * \param[in] num_ip4_elems number of ip4_elems
549 * \returns 0 on success; negative in case of error */
550int ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,
551 const struct gprs_ns_ie_ip4_elem *ip4_elems,
552 unsigned int num_ip4_elems,
553 const struct gprs_ns_ie_ip6_elem *ip6_elems,
554 unsigned int num_ip6_elems)
555{
556 struct msgb *msg;
557 struct gprs_ns_hdr *nsh;
558 uint16_t nsei;
559
560 if (!nsvc)
561 return -1;
562
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100563 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200564
Daniel Willmann751977b2020-12-02 18:59:44 +0100565 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200566 log_set_context(LOG_CTX_GB_NSVC, nsvc);
567 if (!msg)
568 return -ENOMEM;
569
570 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100571 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200572 msgb_free(msg);
573 return -EIO;
574 }
575
576 nsei = osmo_htons(nsvc->nse->nsei);
577
578 msg->l2h = msgb_put(msg, sizeof(*nsh));
579 nsh = (struct gprs_ns_hdr *) msg->l2h;
580
581 nsh->pdu_type = SNS_PDUT_CONFIG;
582
583 msgb_v_put(msg, end_flag ? 0x01 : 0x00);
584 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
585
586 /* List of IP4 Elements 10.3.2c */
587 if (ip4_elems) {
588 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
589 (const uint8_t *)ip4_elems);
590 } else if (ip6_elems) {
591 /* List of IP6 elements 10.3.2d */
592 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
593 (const uint8_t *)ip6_elems);
594 }
595
Harald Welte5a5bf722021-01-30 21:49:28 +0100596 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200597}
598
599/*! Encode + Transmit a SNS-CONFIG-ACK as per Section 9.3.5.
600 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG-ACK
601 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
602 * \returns 0 on success; negative in case of error */
603int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
604{
605 struct msgb *msg;
606 struct gprs_ns_hdr *nsh;
607 uint16_t nsei;
608
609 if (!nsvc)
610 return -1;
611
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100612 msg = ns2_msgb_alloc();
Daniel Willmann751977b2020-12-02 18:59:44 +0100613 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200614 log_set_context(LOG_CTX_GB_NSVC, nsvc);
615 if (!msg)
616 return -ENOMEM;
617
618 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100619 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200620 msgb_free(msg);
621 return -EIO;
622 }
623
624 nsei = osmo_htons(nsvc->nse->nsei);
625
626 msg->l2h = msgb_put(msg, sizeof(*nsh));
627 nsh = (struct gprs_ns_hdr *) msg->l2h;
628
629 nsh->pdu_type = SNS_PDUT_CONFIG_ACK;
630
631 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
632 if (cause)
633 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
634
Harald Welte5a5bf722021-01-30 21:49:28 +0100635 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200636}
637
638
639/*! Encode + transmit a SNS-SIZE as per Section 9.3.7.
640 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE
641 * \param[in] reset_flag Whether or not to add a RESET flag
642 * \param[in] max_nr_nsvc Maximum number of NS-VCs
643 * \param[in] ip4_ep_nr Number of IPv4 endpoints (< 0 will omit the TLV)
644 * \param[in] ip6_ep_nr Number of IPv6 endpoints (< 0 will omit the TLV)
645 * \returns 0 on success; negative in case of error */
646int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_nsvc,
647 int ip4_ep_nr, int ip6_ep_nr)
648{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100649 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200650 struct gprs_ns_hdr *nsh;
651 uint16_t nsei;
652
653 if (!nsvc)
654 return -1;
655
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100656 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200657
Daniel Willmann751977b2020-12-02 18:59:44 +0100658 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200659 log_set_context(LOG_CTX_GB_NSVC, nsvc);
660 if (!msg)
661 return -ENOMEM;
662
663 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100664 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200665 msgb_free(msg);
666 return -EIO;
667 }
668
669 nsei = osmo_htons(nsvc->nse->nsei);
670
671 msg->l2h = msgb_put(msg, sizeof(*nsh));
672 nsh = (struct gprs_ns_hdr *) msg->l2h;
673
674 nsh->pdu_type = SNS_PDUT_SIZE;
675
676 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
677 msgb_tv_put(msg, NS_IE_RESET_FLAG, reset_flag ? 0x01 : 0x00);
678 msgb_tv16_put(msg, NS_IE_MAX_NR_NSVC, max_nr_nsvc);
679 if (ip4_ep_nr >= 0)
680 msgb_tv16_put(msg, NS_IE_IPv4_EP_NR, ip4_ep_nr);
681 if (ip6_ep_nr >= 0)
682 msgb_tv16_put(msg, NS_IE_IPv6_EP_NR, ip6_ep_nr);
683
Harald Welte5a5bf722021-01-30 21:49:28 +0100684 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200685}
686
687/*! Encode + Transmit a SNS-SIZE-ACK as per Section 9.3.8.
688 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE-ACK
689 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
690 * \returns 0 on success; negative in case of error */
691int ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
692{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100693 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200694 struct gprs_ns_hdr *nsh;
695 uint16_t nsei;
696
Daniel Willmann751977b2020-12-02 18:59:44 +0100697 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200698 log_set_context(LOG_CTX_GB_NSVC, nsvc);
699 if (!msg)
700 return -ENOMEM;
701
702 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100703 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200704 msgb_free(msg);
705 return -EIO;
706 }
707
708 nsei = osmo_htons(nsvc->nse->nsei);
709
710 msg->l2h = msgb_put(msg, sizeof(*nsh));
711 nsh = (struct gprs_ns_hdr *) msg->l2h;
712
713 nsh->pdu_type = SNS_PDUT_SIZE_ACK;
714
715 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
716 if (cause)
717 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
718
Harald Welte5a5bf722021-01-30 21:49:28 +0100719 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200720}
721
722