blob: c525dd7af599b4ec3c76b380adfe4e25d2629a31 [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
49enum ns_ctr {
50 NS_CTR_PKTS_IN,
51 NS_CTR_PKTS_OUT,
52 NS_CTR_BYTES_IN,
53 NS_CTR_BYTES_OUT,
54 NS_CTR_BLOCKED,
55 NS_CTR_DEAD,
56 NS_CTR_REPLACED,
57 NS_CTR_NSEI_CHG,
58 NS_CTR_INV_VCI,
59 NS_CTR_INV_NSEI,
60 NS_CTR_LOST_ALIVE,
61 NS_CTR_LOST_RESET,
62};
63
64
65
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010066static 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 +020067{
Harald Welte798efea2020-12-03 16:01:02 +010068 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1) ||
69 !TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_NSEI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020070 *cause = NS_CAUSE_MISSING_ESSENT_IE;
71 return -1;
72 }
73
74 return 0;
75}
76
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010077static 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 +020078{
Harald Welte798efea2020-12-03 16:01:02 +010079 if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_NSEI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020080 *cause = NS_CAUSE_MISSING_ESSENT_IE;
81 return -1;
82 }
83
84 return 0;
85}
86
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010087static 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 +020088{
Harald Welte798efea2020-12-03 16:01:02 +010089 if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020090 *cause = NS_CAUSE_MISSING_ESSENT_IE;
91 return -1;
92 }
93
94 return 0;
95}
96
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010097static 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 +020098{
Harald Welte798efea2020-12-03 16:01:02 +010099 if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200100 *cause = NS_CAUSE_MISSING_ESSENT_IE;
101 return -1;
102 }
103
104 return 0;
105}
106
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100107static 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 +0200108{
109
Harald Welte798efea2020-12-03 16:01:02 +0100110 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200111 *cause = NS_CAUSE_MISSING_ESSENT_IE;
112 return -1;
113 }
114
115 uint8_t _cause = tlvp_val8(tp, NS_IE_VCI, 0);
116
117 switch (_cause) {
118 case NS_CAUSE_NSVC_BLOCKED:
119 case NS_CAUSE_NSVC_UNKNOWN:
Harald Welte798efea2020-12-03 16:01:02 +0100120 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200121 *cause = NS_CAUSE_MISSING_ESSENT_IE;
122 return -1;
123 }
124 break;
125 case NS_CAUSE_SEM_INCORR_PDU:
126 case NS_CAUSE_PDU_INCOMP_PSTATE:
127 case NS_CAUSE_PROTO_ERR_UNSPEC:
128 case NS_CAUSE_INVAL_ESSENT_IE:
129 case NS_CAUSE_MISSING_ESSENT_IE:
Harald Welte798efea2020-12-03 16:01:02 +0100130 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200131 *cause = NS_CAUSE_MISSING_ESSENT_IE;
132 return -1;
133 }
134 break;
135 case NS_CAUSE_BVCI_UNKNOWN:
Harald Welte798efea2020-12-03 16:01:02 +0100136 if (!TLVP_PRES_LEN(tp, NS_IE_BVCI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200137 *cause = NS_CAUSE_MISSING_ESSENT_IE;
138 return -1;
139 }
140 break;
141 case NS_CAUSE_UNKN_IP_TEST_FAILED:
Harald Welte798efea2020-12-03 16:01:02 +0100142 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST) && !TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200143 *cause = NS_CAUSE_MISSING_ESSENT_IE;
144 return -1;
145 }
146 break;
147 }
148
149 return 0;
150}
151
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100152int ns2_validate(struct gprs_ns2_vc *nsvc,
153 uint8_t pdu_type,
154 struct msgb *msg,
155 struct tlv_parsed *tp,
156 uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +0200157{
158 switch (pdu_type) {
159 case NS_PDUT_RESET:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100160 return ns2_validate_reset(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200161 case NS_PDUT_RESET_ACK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100162 return ns2_validate_reset_ack(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200163 case NS_PDUT_BLOCK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100164 return ns2_validate_block(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200165 case NS_PDUT_BLOCK_ACK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100166 return ns2_validate_block_ack(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200167 case NS_PDUT_STATUS:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100168 return ns2_validate_status(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200169
170 /* following PDUs doesn't have any payloads */
171 case NS_PDUT_ALIVE:
172 case NS_PDUT_ALIVE_ACK:
173 case NS_PDUT_UNBLOCK:
174 case NS_PDUT_UNBLOCK_ACK:
175 if (msgb_l2len(msg) != sizeof(struct gprs_ns_hdr)) {
176 *cause = NS_CAUSE_PROTO_ERR_UNSPEC;
177 return -1;
178 }
179 break;
180 }
181
182 return 0;
183}
184
185
186/* transmit functions */
187static int ns2_tx_simple(struct gprs_ns2_vc *nsvc, uint8_t pdu_type)
188{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100189 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200190 struct gprs_ns_hdr *nsh;
191
Daniel Willmann751977b2020-12-02 18:59:44 +0100192 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200193 log_set_context(LOG_CTX_GB_NSVC, nsvc);
194
195 if (!msg)
196 return -ENOMEM;
197
198 msg->l2h = msgb_put(msg, sizeof(*nsh));
199 nsh = (struct gprs_ns_hdr *) msg->l2h;
200
201 nsh->pdu_type = pdu_type;
202
203 return nsvc->bind->send_vc(nsvc, msg);
204}
205
Harald Welte5bef2cc2020-09-18 22:33:24 +0200206/*! Transmit a NS-BLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200207 * \param[in] vc NS-VC on which the NS-BLOCK is to be transmitted
208 * \param[in] cause Numeric NS Cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200209 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200210int ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause)
211{
212 struct msgb *msg;
213 struct gprs_ns_hdr *nsh;
214 uint16_t nsvci = osmo_htons(nsvc->nsvci);
215
Daniel Willmann751977b2020-12-02 18:59:44 +0100216 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200217 log_set_context(LOG_CTX_GB_NSVC, nsvc);
218
219 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK");
220
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100221 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200222 if (!msg)
223 return -ENOMEM;
224
Harald Weltef2949742021-01-20 14:54:14 +0100225 LOGNSVC(nsvc, LOGL_INFO, "Tx NS BLOCK (cause=%s)\n", gprs_ns2_cause_str(cause));
Alexander Couzens6a161492020-07-12 13:45:50 +0200226
227 rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
228
229 msg->l2h = msgb_put(msg, sizeof(*nsh));
230 nsh = (struct gprs_ns_hdr *) msg->l2h;
231 nsh->pdu_type = NS_PDUT_BLOCK;
232
233 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
234 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
235
236 return nsvc->bind->send_vc(nsvc, msg);
237}
238
Harald Welte5bef2cc2020-09-18 22:33:24 +0200239/*! Transmit a NS-BLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200240 * \param[in] nsvc NS-VC on which the NS-BLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200241 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200242int ns2_tx_block_ack(struct gprs_ns2_vc *nsvc)
243{
244 struct msgb *msg;
245 struct gprs_ns_hdr *nsh;
246 uint16_t nsvci = osmo_htons(nsvc->nsvci);
247
Daniel Willmann751977b2020-12-02 18:59:44 +0100248 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200249 log_set_context(LOG_CTX_GB_NSVC, nsvc);
250
251 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK ACK");
252
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100253 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200254 if (!msg)
255 return -ENOMEM;
256
Harald Weltef2949742021-01-20 14:54:14 +0100257 LOGNSVC(nsvc, LOGL_INFO, "Tx NS BLOCK ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200258
Alexander Couzens6a161492020-07-12 13:45:50 +0200259 msg->l2h = msgb_put(msg, sizeof(*nsh));
260 nsh = (struct gprs_ns_hdr *) msg->l2h;
261 nsh->pdu_type = NS_PDUT_BLOCK_ACK;
262
263 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
264
265 return nsvc->bind->send_vc(nsvc, msg);
266}
267
Harald Welte5bef2cc2020-09-18 22:33:24 +0200268/*! Transmit a NS-RESET on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200269 * \param[in] nsvc NS-VC used for transmission
270 * \paam[in] cause Numeric NS cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200271 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200272int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause)
273{
274 struct msgb *msg;
275 struct gprs_ns_hdr *nsh;
276 uint16_t nsvci = osmo_htons(nsvc->nsvci);
277 uint16_t nsei = osmo_htons(nsvc->nse->nsei);
278
Daniel Willmann751977b2020-12-02 18:59:44 +0100279 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200280 log_set_context(LOG_CTX_GB_NSVC, nsvc);
281
282 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET");
283
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100284 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200285 if (!msg)
286 return -ENOMEM;
287
Harald Weltef2949742021-01-20 14:54:14 +0100288 LOGNSVC(nsvc, LOGL_INFO, "Tx NS RESET (cause=%s)\n", gprs_ns2_cause_str(cause));
Alexander Couzens6a161492020-07-12 13:45:50 +0200289
290 msg->l2h = msgb_put(msg, sizeof(*nsh));
291 nsh = (struct gprs_ns_hdr *) msg->l2h;
292 nsh->pdu_type = NS_PDUT_RESET;
293
294 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
295 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
296 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei);
297
298 return nsvc->bind->send_vc(nsvc, msg);
299}
300
Harald Welte5bef2cc2020-09-18 22:33:24 +0200301/*! Transmit a NS-RESET-ACK on a given NS-VC.
302 * \param[in] nsvc NS-VC used for transmission
303 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200304int ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc)
305{
306 struct msgb *msg;
307 struct gprs_ns_hdr *nsh;
308 uint16_t nsvci, nsei;
309
Harald Welte5bef2cc2020-09-18 22:33:24 +0200310 /* Section 9.2.6 */
Daniel Willmann751977b2020-12-02 18:59:44 +0100311 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200312 log_set_context(LOG_CTX_GB_NSVC, nsvc);
313
314 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET ACK");
315
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100316 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200317 if (!msg)
318 return -ENOMEM;
319
320 nsvci = osmo_htons(nsvc->nsvci);
321 nsei = osmo_htons(nsvc->nse->nsei);
322
323 msg->l2h = msgb_put(msg, sizeof(*nsh));
324 nsh = (struct gprs_ns_hdr *) msg->l2h;
325
326 nsh->pdu_type = NS_PDUT_RESET_ACK;
327
Harald Weltef2949742021-01-20 14:54:14 +0100328 LOGNSVC(nsvc, LOGL_INFO, "Tx NS RESET ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200329
330 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
331 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
332
333 return nsvc->bind->send_vc(nsvc, msg);
334}
335
Harald Welte5bef2cc2020-09-18 22:33:24 +0200336/*! Transmit a NS-UNBLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200337 * \param[in] nsvc NS-VC on which the NS-UNBLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200338 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200339int ns2_tx_unblock(struct gprs_ns2_vc *nsvc)
340{
Daniel Willmann751977b2020-12-02 18:59:44 +0100341 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200342 log_set_context(LOG_CTX_GB_NSVC, nsvc);
343
344 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK");
345
Harald Weltef2949742021-01-20 14:54:14 +0100346 LOGNSVC(nsvc, LOGL_INFO, "Tx NS UNBLOCK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200347
348 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK);
349}
350
351
Harald Welte5bef2cc2020-09-18 22:33:24 +0200352/*! Transmit a NS-UNBLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200353 * \param[in] nsvc NS-VC on which the NS-UNBLOCK-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200354 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200355int ns2_tx_unblock_ack(struct gprs_ns2_vc *nsvc)
356{
Daniel Willmann751977b2020-12-02 18:59:44 +0100357 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200358 log_set_context(LOG_CTX_GB_NSVC, nsvc);
359
360 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK ACK");
361
Harald Weltef2949742021-01-20 14:54:14 +0100362 LOGNSVC(nsvc, LOGL_INFO, "Tx NS UNBLOCK_ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200363
364 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
365}
366
Harald Welte5bef2cc2020-09-18 22:33:24 +0200367/*! Transmit a NS-ALIVE on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200368 * \param[in] nsvc NS-VC on which the NS-ALIVE is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200369 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200370int ns2_tx_alive(struct gprs_ns2_vc *nsvc)
371{
Daniel Willmann751977b2020-12-02 18:59:44 +0100372 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200373 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Harald Weltef2949742021-01-20 14:54:14 +0100374 LOGNSVC(nsvc, LOGL_DEBUG, "Tx NS ALIVE\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200375
376 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE);
377}
378
Harald Welte5bef2cc2020-09-18 22:33:24 +0200379/*! Transmit a NS-ALIVE-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200380 * \param[in] nsvc NS-VC on which the NS-ALIVE-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200381 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200382int ns2_tx_alive_ack(struct gprs_ns2_vc *nsvc)
383{
Daniel Willmann751977b2020-12-02 18:59:44 +0100384 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200385 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Harald Weltef2949742021-01-20 14:54:14 +0100386 LOGNSVC(nsvc, LOGL_DEBUG, "Tx NS ALIVE_ACK\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200387
388 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE_ACK);
389}
390
Harald Welte5bef2cc2020-09-18 22:33:24 +0200391/*! Transmit NS-UNITDATA on a given NS-VC.
392 * \param[in] nsvc NS-VC on which the NS-UNITDATA is to be transmitted
393 * \param[in] bvci BVCI to encode in NS-UNITDATA header
394 * \param[in] sducontrol SDU control octet of NS header
395 * \param[in] msg message buffer containing payload
396 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200397int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
398 uint16_t bvci, uint8_t sducontrol,
399 struct msgb *msg)
400{
401 struct gprs_ns_hdr *nsh;
402
Daniel Willmann751977b2020-12-02 18:59:44 +0100403 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200404 log_set_context(LOG_CTX_GB_NSVC, nsvc);
405
406 msg->l2h = msgb_push(msg, sizeof(*nsh) + 3);
407 nsh = (struct gprs_ns_hdr *) msg->l2h;
408 if (!nsh) {
Harald Weltef2949742021-01-20 14:54:14 +0100409 LOGNSVC(nsvc, LOGL_ERROR, "Not enough headroom for NS header\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200410 msgb_free(msg);
411 return -EIO;
412 }
413
414 nsh->pdu_type = NS_PDUT_UNITDATA;
415 nsh->data[0] = sducontrol;
416 nsh->data[1] = bvci >> 8;
417 nsh->data[2] = bvci & 0xff;
418
419 return nsvc->bind->send_vc(nsvc, msg);
420}
421
Harald Welte5bef2cc2020-09-18 22:33:24 +0200422/*! Transmit a NS-STATUS on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200423 * \param[in] nsvc NS-VC to be used for transmission
424 * \param[in] cause Numeric NS cause value
425 * \param[in] bvci BVCI to be reset within NSVC
Harald Welte5bef2cc2020-09-18 22:33:24 +0200426 * \param[in] orig_msg message causing the STATUS
427 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200428int ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,
429 uint16_t bvci, struct msgb *orig_msg)
430{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100431 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200432 struct gprs_ns_hdr *nsh;
433 uint16_t nsvci = osmo_htons(nsvc->nsvci);
434
Daniel Willmann751977b2020-12-02 18:59:44 +0100435 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200436 log_set_context(LOG_CTX_GB_NSVC, nsvc);
437
438 bvci = osmo_htons(bvci);
439
440 if (!msg)
441 return -ENOMEM;
442
Harald Weltef2949742021-01-20 14:54:14 +0100443 LOGNSVC(nsvc, LOGL_NOTICE, "Tx NS STATUS (cause=%s)\n", gprs_ns2_cause_str(cause));
Alexander Couzens6a161492020-07-12 13:45:50 +0200444
445 msg->l2h = msgb_put(msg, sizeof(*nsh));
446 nsh = (struct gprs_ns_hdr *) msg->l2h;
447 nsh->pdu_type = NS_PDUT_STATUS;
448
449 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
450
451 /* Section 9.2.7.1: Static conditions for NS-VCI */
452 if (cause == NS_CAUSE_NSVC_BLOCKED ||
453 cause == NS_CAUSE_NSVC_UNKNOWN)
454 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
455
456 /* Section 9.2.7.2: Static conditions for NS PDU */
457 switch (cause) {
458 case NS_CAUSE_SEM_INCORR_PDU:
459 case NS_CAUSE_PDU_INCOMP_PSTATE:
460 case NS_CAUSE_PROTO_ERR_UNSPEC:
461 case NS_CAUSE_INVAL_ESSENT_IE:
462 case NS_CAUSE_MISSING_ESSENT_IE:
463 msgb_tvlv_put(msg, NS_IE_PDU, msgb_l2len(orig_msg),
464 orig_msg->l2h);
465 break;
466 default:
467 break;
468 }
469
470 /* Section 9.2.7.3: Static conditions for BVCI */
471 if (cause == NS_CAUSE_BVCI_UNKNOWN)
472 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci);
473
474 return nsvc->bind->send_vc(nsvc, msg);
475}
476
477
478/*! Encode + Transmit a SNS-ACK as per Section 9.3.1.
479 * \param[in] nsvc NS-VC through which to transmit the ACK
480 * \param[in] trans_id Transaction ID which to acknowledge
481 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
482 * \param[in] ip4_elems Array of IPv4 Elements
483 * \param[in] num_ip4_elems number of ip4_elems
484 * \returns 0 on success; negative in case of error */
485int ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,
486 const struct gprs_ns_ie_ip4_elem *ip4_elems,
487 unsigned int num_ip4_elems,
488 const struct gprs_ns_ie_ip6_elem *ip6_elems,
489 unsigned int num_ip6_elems)
490{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100491 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200492 struct gprs_ns_hdr *nsh;
493 uint16_t nsei;
494
495 if (!nsvc)
496 return -1;
497
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100498 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200499
Daniel Willmann751977b2020-12-02 18:59:44 +0100500 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200501 log_set_context(LOG_CTX_GB_NSVC, nsvc);
502 if (!msg)
503 return -ENOMEM;
504
505 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100506 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200507 msgb_free(msg);
508 return -EIO;
509 }
510
511 nsei = osmo_htons(nsvc->nse->nsei);
512
513 msg->l2h = msgb_put(msg, sizeof(*nsh));
514 nsh = (struct gprs_ns_hdr *) msg->l2h;
515
516 nsh->pdu_type = SNS_PDUT_ACK;
517 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
518 msgb_v_put(msg, trans_id);
519 if (cause)
520 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
521 if (ip4_elems) {
522 /* List of IP4 Elements 10.3.2c */
523 msgb_tvlv_put(msg, NS_IE_IPv4_LIST,
524 num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
525 (const uint8_t *)ip4_elems);
526 }
527 if (ip6_elems) {
528 /* List of IP6 elements 10.3.2d */
529 msgb_tvlv_put(msg, NS_IE_IPv6_LIST,
530 num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
531 (const uint8_t *)ip6_elems);
532 }
533
534 return nsvc->bind->send_vc(nsvc, msg);
535}
536
537/*! Encode + Transmit a SNS-CONFIG as per Section 9.3.4.
538 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
539 * \param[in] end_flag Whether or not this is the last SNS-CONFIG
540 * \param[in] ip4_elems Array of IPv4 Elements
541 * \param[in] num_ip4_elems number of ip4_elems
542 * \returns 0 on success; negative in case of error */
543int ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,
544 const struct gprs_ns_ie_ip4_elem *ip4_elems,
545 unsigned int num_ip4_elems,
546 const struct gprs_ns_ie_ip6_elem *ip6_elems,
547 unsigned int num_ip6_elems)
548{
549 struct msgb *msg;
550 struct gprs_ns_hdr *nsh;
551 uint16_t nsei;
552
553 if (!nsvc)
554 return -1;
555
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100556 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200557
Daniel Willmann751977b2020-12-02 18:59:44 +0100558 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200559 log_set_context(LOG_CTX_GB_NSVC, nsvc);
560 if (!msg)
561 return -ENOMEM;
562
563 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100564 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200565 msgb_free(msg);
566 return -EIO;
567 }
568
569 nsei = osmo_htons(nsvc->nse->nsei);
570
571 msg->l2h = msgb_put(msg, sizeof(*nsh));
572 nsh = (struct gprs_ns_hdr *) msg->l2h;
573
574 nsh->pdu_type = SNS_PDUT_CONFIG;
575
576 msgb_v_put(msg, end_flag ? 0x01 : 0x00);
577 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
578
579 /* List of IP4 Elements 10.3.2c */
580 if (ip4_elems) {
581 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
582 (const uint8_t *)ip4_elems);
583 } else if (ip6_elems) {
584 /* List of IP6 elements 10.3.2d */
585 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
586 (const uint8_t *)ip6_elems);
587 }
588
589 return nsvc->bind->send_vc(nsvc, msg);
590}
591
592/*! Encode + Transmit a SNS-CONFIG-ACK as per Section 9.3.5.
593 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG-ACK
594 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
595 * \returns 0 on success; negative in case of error */
596int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
597{
598 struct msgb *msg;
599 struct gprs_ns_hdr *nsh;
600 uint16_t nsei;
601
602 if (!nsvc)
603 return -1;
604
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100605 msg = ns2_msgb_alloc();
Daniel Willmann751977b2020-12-02 18:59:44 +0100606 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200607 log_set_context(LOG_CTX_GB_NSVC, nsvc);
608 if (!msg)
609 return -ENOMEM;
610
611 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100612 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200613 msgb_free(msg);
614 return -EIO;
615 }
616
617 nsei = osmo_htons(nsvc->nse->nsei);
618
619 msg->l2h = msgb_put(msg, sizeof(*nsh));
620 nsh = (struct gprs_ns_hdr *) msg->l2h;
621
622 nsh->pdu_type = SNS_PDUT_CONFIG_ACK;
623
624 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
625 if (cause)
626 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
627
628 return nsvc->bind->send_vc(nsvc, msg);
629}
630
631
632/*! Encode + transmit a SNS-SIZE as per Section 9.3.7.
633 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE
634 * \param[in] reset_flag Whether or not to add a RESET flag
635 * \param[in] max_nr_nsvc Maximum number of NS-VCs
636 * \param[in] ip4_ep_nr Number of IPv4 endpoints (< 0 will omit the TLV)
637 * \param[in] ip6_ep_nr Number of IPv6 endpoints (< 0 will omit the TLV)
638 * \returns 0 on success; negative in case of error */
639int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_nsvc,
640 int ip4_ep_nr, int ip6_ep_nr)
641{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100642 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200643 struct gprs_ns_hdr *nsh;
644 uint16_t nsei;
645
646 if (!nsvc)
647 return -1;
648
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100649 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200650
Daniel Willmann751977b2020-12-02 18:59:44 +0100651 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200652 log_set_context(LOG_CTX_GB_NSVC, nsvc);
653 if (!msg)
654 return -ENOMEM;
655
656 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100657 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200658 msgb_free(msg);
659 return -EIO;
660 }
661
662 nsei = osmo_htons(nsvc->nse->nsei);
663
664 msg->l2h = msgb_put(msg, sizeof(*nsh));
665 nsh = (struct gprs_ns_hdr *) msg->l2h;
666
667 nsh->pdu_type = SNS_PDUT_SIZE;
668
669 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
670 msgb_tv_put(msg, NS_IE_RESET_FLAG, reset_flag ? 0x01 : 0x00);
671 msgb_tv16_put(msg, NS_IE_MAX_NR_NSVC, max_nr_nsvc);
672 if (ip4_ep_nr >= 0)
673 msgb_tv16_put(msg, NS_IE_IPv4_EP_NR, ip4_ep_nr);
674 if (ip6_ep_nr >= 0)
675 msgb_tv16_put(msg, NS_IE_IPv6_EP_NR, ip6_ep_nr);
676
677 return nsvc->bind->send_vc(nsvc, msg);
678}
679
680/*! Encode + Transmit a SNS-SIZE-ACK as per Section 9.3.8.
681 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE-ACK
682 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
683 * \returns 0 on success; negative in case of error */
684int ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
685{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100686 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200687 struct gprs_ns_hdr *nsh;
688 uint16_t nsei;
689
Daniel Willmann751977b2020-12-02 18:59:44 +0100690 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200691 log_set_context(LOG_CTX_GB_NSVC, nsvc);
692 if (!msg)
693 return -ENOMEM;
694
695 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100696 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200697 msgb_free(msg);
698 return -EIO;
699 }
700
701 nsei = osmo_htons(nsvc->nse->nsei);
702
703 msg->l2h = msgb_put(msg, sizeof(*nsh));
704 nsh = (struct gprs_ns_hdr *) msg->l2h;
705
706 nsh->pdu_type = SNS_PDUT_SIZE_ACK;
707
708 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
709 if (cause)
710 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
711
712 return nsvc->bind->send_vc(nsvc, msg);
713}
714
715