blob: cd498969bf630140e82503bf43de7fe0b990b35a [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 Weltee5f55f72021-01-30 21:51:15 +0100171 rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]);
172 rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT], msgb_length(msg));
173
Harald Welte5a5bf722021-01-30 21:49:28 +0100174 return nsvc->bind->send_vc(nsvc, msg);
175}
176
Alexander Couzens6a161492020-07-12 13:45:50 +0200177/* transmit functions */
178static int ns2_tx_simple(struct gprs_ns2_vc *nsvc, uint8_t pdu_type)
179{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100180 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200181 struct gprs_ns_hdr *nsh;
182
Daniel Willmann751977b2020-12-02 18:59:44 +0100183 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200184 log_set_context(LOG_CTX_GB_NSVC, nsvc);
185
186 if (!msg)
187 return -ENOMEM;
188
189 msg->l2h = msgb_put(msg, sizeof(*nsh));
190 nsh = (struct gprs_ns_hdr *) msg->l2h;
191
192 nsh->pdu_type = pdu_type;
193
Harald Welte5a5bf722021-01-30 21:49:28 +0100194 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200195}
196
Harald Welte5bef2cc2020-09-18 22:33:24 +0200197/*! Transmit a NS-BLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200198 * \param[in] vc NS-VC on which the NS-BLOCK is to be transmitted
199 * \param[in] cause Numeric NS Cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200200 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200201int ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause)
202{
203 struct msgb *msg;
204 struct gprs_ns_hdr *nsh;
205 uint16_t nsvci = osmo_htons(nsvc->nsvci);
206
Daniel Willmann751977b2020-12-02 18:59:44 +0100207 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200208 log_set_context(LOG_CTX_GB_NSVC, nsvc);
209
210 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK");
211
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100212 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200213 if (!msg)
214 return -ENOMEM;
215
Harald Weltef2949742021-01-20 14:54:14 +0100216 LOGNSVC(nsvc, LOGL_INFO, "Tx NS BLOCK (cause=%s)\n", gprs_ns2_cause_str(cause));
Alexander Couzens6a161492020-07-12 13:45:50 +0200217
218 rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
219
220 msg->l2h = msgb_put(msg, sizeof(*nsh));
221 nsh = (struct gprs_ns_hdr *) msg->l2h;
222 nsh->pdu_type = NS_PDUT_BLOCK;
223
224 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
225 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
226
Harald Welte5a5bf722021-01-30 21:49:28 +0100227 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200228}
229
Harald Welte5bef2cc2020-09-18 22:33:24 +0200230/*! Transmit a NS-BLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200231 * \param[in] nsvc NS-VC on which the NS-BLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200232 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200233int ns2_tx_block_ack(struct gprs_ns2_vc *nsvc)
234{
235 struct msgb *msg;
236 struct gprs_ns_hdr *nsh;
237 uint16_t nsvci = osmo_htons(nsvc->nsvci);
238
Daniel Willmann751977b2020-12-02 18:59:44 +0100239 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200240 log_set_context(LOG_CTX_GB_NSVC, nsvc);
241
242 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK ACK");
243
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100244 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200245 if (!msg)
246 return -ENOMEM;
247
Harald Weltef2949742021-01-20 14:54:14 +0100248 LOGNSVC(nsvc, LOGL_INFO, "Tx NS BLOCK ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200249
Alexander Couzens6a161492020-07-12 13:45:50 +0200250 msg->l2h = msgb_put(msg, sizeof(*nsh));
251 nsh = (struct gprs_ns_hdr *) msg->l2h;
252 nsh->pdu_type = NS_PDUT_BLOCK_ACK;
253
254 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
255
Harald Welte5a5bf722021-01-30 21:49:28 +0100256 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200257}
258
Harald Welte5bef2cc2020-09-18 22:33:24 +0200259/*! Transmit a NS-RESET on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200260 * \param[in] nsvc NS-VC used for transmission
261 * \paam[in] cause Numeric NS cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200262 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200263int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause)
264{
265 struct msgb *msg;
266 struct gprs_ns_hdr *nsh;
267 uint16_t nsvci = osmo_htons(nsvc->nsvci);
268 uint16_t nsei = osmo_htons(nsvc->nse->nsei);
269
Daniel Willmann751977b2020-12-02 18:59:44 +0100270 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200271 log_set_context(LOG_CTX_GB_NSVC, nsvc);
272
273 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET");
274
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100275 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200276 if (!msg)
277 return -ENOMEM;
278
Harald Weltef2949742021-01-20 14:54:14 +0100279 LOGNSVC(nsvc, LOGL_INFO, "Tx NS RESET (cause=%s)\n", gprs_ns2_cause_str(cause));
Alexander Couzens6a161492020-07-12 13:45:50 +0200280
281 msg->l2h = msgb_put(msg, sizeof(*nsh));
282 nsh = (struct gprs_ns_hdr *) msg->l2h;
283 nsh->pdu_type = NS_PDUT_RESET;
284
285 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
286 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
287 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei);
288
Harald Welte5a5bf722021-01-30 21:49:28 +0100289 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200290}
291
Harald Welte5bef2cc2020-09-18 22:33:24 +0200292/*! Transmit a NS-RESET-ACK on a given NS-VC.
293 * \param[in] nsvc NS-VC used for transmission
294 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200295int ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc)
296{
297 struct msgb *msg;
298 struct gprs_ns_hdr *nsh;
299 uint16_t nsvci, nsei;
300
Harald Welte5bef2cc2020-09-18 22:33:24 +0200301 /* Section 9.2.6 */
Daniel Willmann751977b2020-12-02 18:59:44 +0100302 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200303 log_set_context(LOG_CTX_GB_NSVC, nsvc);
304
305 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET ACK");
306
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100307 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200308 if (!msg)
309 return -ENOMEM;
310
311 nsvci = osmo_htons(nsvc->nsvci);
312 nsei = osmo_htons(nsvc->nse->nsei);
313
314 msg->l2h = msgb_put(msg, sizeof(*nsh));
315 nsh = (struct gprs_ns_hdr *) msg->l2h;
316
317 nsh->pdu_type = NS_PDUT_RESET_ACK;
318
Harald Weltef2949742021-01-20 14:54:14 +0100319 LOGNSVC(nsvc, LOGL_INFO, "Tx NS RESET ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200320
321 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
322 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
323
Harald Welte5a5bf722021-01-30 21:49:28 +0100324 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200325}
326
Harald Welte5bef2cc2020-09-18 22:33:24 +0200327/*! Transmit a NS-UNBLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200328 * \param[in] nsvc NS-VC on which the NS-UNBLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200329 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200330int ns2_tx_unblock(struct gprs_ns2_vc *nsvc)
331{
Daniel Willmann751977b2020-12-02 18:59:44 +0100332 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200333 log_set_context(LOG_CTX_GB_NSVC, nsvc);
334
335 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK");
336
Harald Weltef2949742021-01-20 14:54:14 +0100337 LOGNSVC(nsvc, LOGL_INFO, "Tx NS UNBLOCK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200338
339 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK);
340}
341
342
Harald Welte5bef2cc2020-09-18 22:33:24 +0200343/*! Transmit a NS-UNBLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200344 * \param[in] nsvc NS-VC on which the NS-UNBLOCK-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200345 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200346int ns2_tx_unblock_ack(struct gprs_ns2_vc *nsvc)
347{
Daniel Willmann751977b2020-12-02 18:59:44 +0100348 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200349 log_set_context(LOG_CTX_GB_NSVC, nsvc);
350
351 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK ACK");
352
Harald Weltef2949742021-01-20 14:54:14 +0100353 LOGNSVC(nsvc, LOGL_INFO, "Tx NS UNBLOCK_ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200354
355 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
356}
357
Harald Welte5bef2cc2020-09-18 22:33:24 +0200358/*! Transmit a NS-ALIVE on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200359 * \param[in] nsvc NS-VC on which the NS-ALIVE is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200360 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200361int ns2_tx_alive(struct gprs_ns2_vc *nsvc)
362{
Daniel Willmann751977b2020-12-02 18:59:44 +0100363 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200364 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Harald Weltef2949742021-01-20 14:54:14 +0100365 LOGNSVC(nsvc, LOGL_DEBUG, "Tx NS ALIVE\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200366
367 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE);
368}
369
Harald Welte5bef2cc2020-09-18 22:33:24 +0200370/*! Transmit a NS-ALIVE-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200371 * \param[in] nsvc NS-VC on which the NS-ALIVE-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200372 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200373int ns2_tx_alive_ack(struct gprs_ns2_vc *nsvc)
374{
Daniel Willmann751977b2020-12-02 18:59:44 +0100375 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200376 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Harald Weltef2949742021-01-20 14:54:14 +0100377 LOGNSVC(nsvc, LOGL_DEBUG, "Tx NS ALIVE_ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200378
379 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE_ACK);
380}
381
Harald Welte5bef2cc2020-09-18 22:33:24 +0200382/*! Transmit NS-UNITDATA on a given NS-VC.
383 * \param[in] nsvc NS-VC on which the NS-UNITDATA is to be transmitted
384 * \param[in] bvci BVCI to encode in NS-UNITDATA header
385 * \param[in] sducontrol SDU control octet of NS header
386 * \param[in] msg message buffer containing payload
387 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200388int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
389 uint16_t bvci, uint8_t sducontrol,
390 struct msgb *msg)
391{
392 struct gprs_ns_hdr *nsh;
393
Daniel Willmann751977b2020-12-02 18:59:44 +0100394 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200395 log_set_context(LOG_CTX_GB_NSVC, nsvc);
396
397 msg->l2h = msgb_push(msg, sizeof(*nsh) + 3);
398 nsh = (struct gprs_ns_hdr *) msg->l2h;
399 if (!nsh) {
Harald Weltef2949742021-01-20 14:54:14 +0100400 LOGNSVC(nsvc, LOGL_ERROR, "Not enough headroom for NS header\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200401 msgb_free(msg);
402 return -EIO;
403 }
404
405 nsh->pdu_type = NS_PDUT_UNITDATA;
406 nsh->data[0] = sducontrol;
407 nsh->data[1] = bvci >> 8;
408 nsh->data[2] = bvci & 0xff;
409
Harald Welte5a5bf722021-01-30 21:49:28 +0100410 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200411}
412
Harald Welte5bef2cc2020-09-18 22:33:24 +0200413/*! Transmit a NS-STATUS on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200414 * \param[in] nsvc NS-VC to be used for transmission
415 * \param[in] cause Numeric NS cause value
416 * \param[in] bvci BVCI to be reset within NSVC
Harald Welte5bef2cc2020-09-18 22:33:24 +0200417 * \param[in] orig_msg message causing the STATUS
418 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200419int ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,
420 uint16_t bvci, struct msgb *orig_msg)
421{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100422 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200423 struct gprs_ns_hdr *nsh;
424 uint16_t nsvci = osmo_htons(nsvc->nsvci);
425
Daniel Willmann751977b2020-12-02 18:59:44 +0100426 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200427 log_set_context(LOG_CTX_GB_NSVC, nsvc);
428
429 bvci = osmo_htons(bvci);
430
431 if (!msg)
432 return -ENOMEM;
433
Harald Weltef2949742021-01-20 14:54:14 +0100434 LOGNSVC(nsvc, LOGL_NOTICE, "Tx NS STATUS (cause=%s)\n", gprs_ns2_cause_str(cause));
Alexander Couzens6a161492020-07-12 13:45:50 +0200435
436 msg->l2h = msgb_put(msg, sizeof(*nsh));
437 nsh = (struct gprs_ns_hdr *) msg->l2h;
438 nsh->pdu_type = NS_PDUT_STATUS;
439
440 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
441
442 /* Section 9.2.7.1: Static conditions for NS-VCI */
443 if (cause == NS_CAUSE_NSVC_BLOCKED ||
444 cause == NS_CAUSE_NSVC_UNKNOWN)
445 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
446
447 /* Section 9.2.7.2: Static conditions for NS PDU */
448 switch (cause) {
449 case NS_CAUSE_SEM_INCORR_PDU:
450 case NS_CAUSE_PDU_INCOMP_PSTATE:
451 case NS_CAUSE_PROTO_ERR_UNSPEC:
452 case NS_CAUSE_INVAL_ESSENT_IE:
453 case NS_CAUSE_MISSING_ESSENT_IE:
454 msgb_tvlv_put(msg, NS_IE_PDU, msgb_l2len(orig_msg),
455 orig_msg->l2h);
456 break;
457 default:
458 break;
459 }
460
461 /* Section 9.2.7.3: Static conditions for BVCI */
462 if (cause == NS_CAUSE_BVCI_UNKNOWN)
463 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci);
464
Harald Welte5a5bf722021-01-30 21:49:28 +0100465 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200466}
467
468
469/*! Encode + Transmit a SNS-ACK as per Section 9.3.1.
470 * \param[in] nsvc NS-VC through which to transmit the ACK
471 * \param[in] trans_id Transaction ID which to acknowledge
472 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
473 * \param[in] ip4_elems Array of IPv4 Elements
474 * \param[in] num_ip4_elems number of ip4_elems
475 * \returns 0 on success; negative in case of error */
476int ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,
477 const struct gprs_ns_ie_ip4_elem *ip4_elems,
478 unsigned int num_ip4_elems,
479 const struct gprs_ns_ie_ip6_elem *ip6_elems,
480 unsigned int num_ip6_elems)
481{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100482 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200483 struct gprs_ns_hdr *nsh;
484 uint16_t nsei;
485
486 if (!nsvc)
487 return -1;
488
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100489 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200490
Daniel Willmann751977b2020-12-02 18:59:44 +0100491 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200492 log_set_context(LOG_CTX_GB_NSVC, nsvc);
493 if (!msg)
494 return -ENOMEM;
495
496 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100497 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200498 msgb_free(msg);
499 return -EIO;
500 }
501
502 nsei = osmo_htons(nsvc->nse->nsei);
503
504 msg->l2h = msgb_put(msg, sizeof(*nsh));
505 nsh = (struct gprs_ns_hdr *) msg->l2h;
506
507 nsh->pdu_type = SNS_PDUT_ACK;
508 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
509 msgb_v_put(msg, trans_id);
510 if (cause)
511 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
512 if (ip4_elems) {
513 /* List of IP4 Elements 10.3.2c */
514 msgb_tvlv_put(msg, NS_IE_IPv4_LIST,
515 num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
516 (const uint8_t *)ip4_elems);
517 }
518 if (ip6_elems) {
519 /* List of IP6 elements 10.3.2d */
520 msgb_tvlv_put(msg, NS_IE_IPv6_LIST,
521 num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
522 (const uint8_t *)ip6_elems);
523 }
524
Harald Welte5a5bf722021-01-30 21:49:28 +0100525 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200526}
527
528/*! Encode + Transmit a SNS-CONFIG as per Section 9.3.4.
529 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
530 * \param[in] end_flag Whether or not this is the last SNS-CONFIG
531 * \param[in] ip4_elems Array of IPv4 Elements
532 * \param[in] num_ip4_elems number of ip4_elems
533 * \returns 0 on success; negative in case of error */
534int ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,
535 const struct gprs_ns_ie_ip4_elem *ip4_elems,
536 unsigned int num_ip4_elems,
537 const struct gprs_ns_ie_ip6_elem *ip6_elems,
538 unsigned int num_ip6_elems)
539{
540 struct msgb *msg;
541 struct gprs_ns_hdr *nsh;
542 uint16_t nsei;
543
544 if (!nsvc)
545 return -1;
546
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100547 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200548
Daniel Willmann751977b2020-12-02 18:59:44 +0100549 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200550 log_set_context(LOG_CTX_GB_NSVC, nsvc);
551 if (!msg)
552 return -ENOMEM;
553
554 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100555 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200556 msgb_free(msg);
557 return -EIO;
558 }
559
560 nsei = osmo_htons(nsvc->nse->nsei);
561
562 msg->l2h = msgb_put(msg, sizeof(*nsh));
563 nsh = (struct gprs_ns_hdr *) msg->l2h;
564
565 nsh->pdu_type = SNS_PDUT_CONFIG;
566
567 msgb_v_put(msg, end_flag ? 0x01 : 0x00);
568 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
569
570 /* List of IP4 Elements 10.3.2c */
571 if (ip4_elems) {
572 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
573 (const uint8_t *)ip4_elems);
574 } else if (ip6_elems) {
575 /* List of IP6 elements 10.3.2d */
576 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
577 (const uint8_t *)ip6_elems);
578 }
579
Harald Welte5a5bf722021-01-30 21:49:28 +0100580 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200581}
582
583/*! Encode + Transmit a SNS-CONFIG-ACK as per Section 9.3.5.
584 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG-ACK
585 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
586 * \returns 0 on success; negative in case of error */
587int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
588{
589 struct msgb *msg;
590 struct gprs_ns_hdr *nsh;
591 uint16_t nsei;
592
593 if (!nsvc)
594 return -1;
595
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100596 msg = ns2_msgb_alloc();
Daniel Willmann751977b2020-12-02 18:59:44 +0100597 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200598 log_set_context(LOG_CTX_GB_NSVC, nsvc);
599 if (!msg)
600 return -ENOMEM;
601
602 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100603 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200604 msgb_free(msg);
605 return -EIO;
606 }
607
608 nsei = osmo_htons(nsvc->nse->nsei);
609
610 msg->l2h = msgb_put(msg, sizeof(*nsh));
611 nsh = (struct gprs_ns_hdr *) msg->l2h;
612
613 nsh->pdu_type = SNS_PDUT_CONFIG_ACK;
614
615 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
616 if (cause)
617 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
618
Harald Welte5a5bf722021-01-30 21:49:28 +0100619 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200620}
621
622
623/*! Encode + transmit a SNS-SIZE as per Section 9.3.7.
624 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE
625 * \param[in] reset_flag Whether or not to add a RESET flag
626 * \param[in] max_nr_nsvc Maximum number of NS-VCs
627 * \param[in] ip4_ep_nr Number of IPv4 endpoints (< 0 will omit the TLV)
628 * \param[in] ip6_ep_nr Number of IPv6 endpoints (< 0 will omit the TLV)
629 * \returns 0 on success; negative in case of error */
630int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_nsvc,
631 int ip4_ep_nr, int ip6_ep_nr)
632{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100633 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200634 struct gprs_ns_hdr *nsh;
635 uint16_t nsei;
636
637 if (!nsvc)
638 return -1;
639
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100640 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200641
Daniel Willmann751977b2020-12-02 18:59:44 +0100642 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200643 log_set_context(LOG_CTX_GB_NSVC, nsvc);
644 if (!msg)
645 return -ENOMEM;
646
647 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100648 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200649 msgb_free(msg);
650 return -EIO;
651 }
652
653 nsei = osmo_htons(nsvc->nse->nsei);
654
655 msg->l2h = msgb_put(msg, sizeof(*nsh));
656 nsh = (struct gprs_ns_hdr *) msg->l2h;
657
658 nsh->pdu_type = SNS_PDUT_SIZE;
659
660 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
661 msgb_tv_put(msg, NS_IE_RESET_FLAG, reset_flag ? 0x01 : 0x00);
662 msgb_tv16_put(msg, NS_IE_MAX_NR_NSVC, max_nr_nsvc);
663 if (ip4_ep_nr >= 0)
664 msgb_tv16_put(msg, NS_IE_IPv4_EP_NR, ip4_ep_nr);
665 if (ip6_ep_nr >= 0)
666 msgb_tv16_put(msg, NS_IE_IPv6_EP_NR, ip6_ep_nr);
667
Harald Welte5a5bf722021-01-30 21:49:28 +0100668 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200669}
670
671/*! Encode + Transmit a SNS-SIZE-ACK as per Section 9.3.8.
672 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE-ACK
673 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
674 * \returns 0 on success; negative in case of error */
675int ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
676{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100677 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200678 struct gprs_ns_hdr *nsh;
679 uint16_t nsei;
680
Daniel Willmann751977b2020-12-02 18:59:44 +0100681 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200682 log_set_context(LOG_CTX_GB_NSVC, nsvc);
683 if (!msg)
684 return -ENOMEM;
685
686 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100687 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200688 msgb_free(msg);
689 return -EIO;
690 }
691
692 nsei = osmo_htons(nsvc->nse->nsei);
693
694 msg->l2h = msgb_put(msg, sizeof(*nsh));
695 nsh = (struct gprs_ns_hdr *) msg->l2h;
696
697 nsh->pdu_type = SNS_PDUT_SIZE_ACK;
698
699 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
700 if (cause)
701 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
702
Harald Welte5a5bf722021-01-30 21:49:28 +0100703 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200704}
705
706