blob: 1b986feb9c9f749ff2dcd9b86475f1d69354adff [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
Alexander Couzenseec4f602021-09-06 18:17:15 +020098 uint8_t _cause = tlvp_val8(tp, NS_IE_CAUSE, 0);
Alexander Couzens6a161492020-07-12 13:45:50 +020099 switch (_cause) {
100 case NS_CAUSE_NSVC_BLOCKED:
101 case NS_CAUSE_NSVC_UNKNOWN:
Alexander Couzenseec4f602021-09-06 18:17:15 +0200102 if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200103 *cause = NS_CAUSE_MISSING_ESSENT_IE;
104 return -1;
105 }
Alexander Couzensa2b846b2021-09-07 15:30:02 +0200106
107 if (nsvc->mode != GPRS_NS2_VC_MODE_BLOCKRESET) {
108 *cause = NS_CAUSE_PDU_INCOMP_PSTATE;
109 return -1;
110 }
Alexander Couzens6a161492020-07-12 13:45:50 +0200111 break;
112 case NS_CAUSE_SEM_INCORR_PDU:
113 case NS_CAUSE_PDU_INCOMP_PSTATE:
114 case NS_CAUSE_PROTO_ERR_UNSPEC:
115 case NS_CAUSE_INVAL_ESSENT_IE:
116 case NS_CAUSE_MISSING_ESSENT_IE:
Alexander Couzenseec4f602021-09-06 18:17:15 +0200117 if (!TLVP_PRES_LEN(tp, NS_IE_PDU, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200118 *cause = NS_CAUSE_MISSING_ESSENT_IE;
119 return -1;
120 }
121 break;
122 case NS_CAUSE_BVCI_UNKNOWN:
Harald Welte798efea2020-12-03 16:01:02 +0100123 if (!TLVP_PRES_LEN(tp, NS_IE_BVCI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200124 *cause = NS_CAUSE_MISSING_ESSENT_IE;
125 return -1;
126 }
127 break;
128 case NS_CAUSE_UNKN_IP_TEST_FAILED:
Harald Welte798efea2020-12-03 16:01:02 +0100129 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST) && !TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200130 *cause = NS_CAUSE_MISSING_ESSENT_IE;
131 return -1;
132 }
133 break;
134 }
135
136 return 0;
137}
138
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100139int ns2_validate(struct gprs_ns2_vc *nsvc,
140 uint8_t pdu_type,
141 struct msgb *msg,
142 struct tlv_parsed *tp,
143 uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +0200144{
145 switch (pdu_type) {
146 case NS_PDUT_RESET:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100147 return ns2_validate_reset(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200148 case NS_PDUT_RESET_ACK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100149 return ns2_validate_reset_ack(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200150 case NS_PDUT_BLOCK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100151 return ns2_validate_block(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200152 case NS_PDUT_BLOCK_ACK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100153 return ns2_validate_block_ack(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200154 case NS_PDUT_STATUS:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100155 return ns2_validate_status(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200156
157 /* following PDUs doesn't have any payloads */
158 case NS_PDUT_ALIVE:
159 case NS_PDUT_ALIVE_ACK:
160 case NS_PDUT_UNBLOCK:
161 case NS_PDUT_UNBLOCK_ACK:
162 if (msgb_l2len(msg) != sizeof(struct gprs_ns_hdr)) {
163 *cause = NS_CAUSE_PROTO_ERR_UNSPEC;
164 return -1;
165 }
166 break;
167 }
168
169 return 0;
170}
171
172
Harald Welte5a5bf722021-01-30 21:49:28 +0100173static int ns_vc_tx(struct gprs_ns2_vc *nsvc, struct msgb *msg)
174{
Harald Weltef22ae5a2021-01-30 22:01:28 +0100175 unsigned int bytes = msgb_length(msg);
176 int rc;
Harald Weltee5f55f72021-01-30 21:51:15 +0100177
Harald Weltef22ae5a2021-01-30 22:01:28 +0100178
179 rc = nsvc->bind->send_vc(nsvc, msg);
180 if (rc < 0) {
Daniel Willmannefa64f92021-07-09 20:35:00 +0200181 RATE_CTR_INC_NS(nsvc, NS_CTR_PKTS_OUT_DROP);
182 RATE_CTR_ADD_NS(nsvc, NS_CTR_BYTES_OUT_DROP, bytes);
Harald Weltef22ae5a2021-01-30 22:01:28 +0100183 } else {
Daniel Willmannefa64f92021-07-09 20:35:00 +0200184 RATE_CTR_INC_NS(nsvc, NS_CTR_PKTS_OUT);
185 RATE_CTR_ADD_NS(nsvc, NS_CTR_BYTES_OUT, bytes);
Harald Weltef22ae5a2021-01-30 22:01:28 +0100186 }
187
188 return rc;
Harald Welte5a5bf722021-01-30 21:49:28 +0100189}
190
Alexander Couzens6a161492020-07-12 13:45:50 +0200191/* transmit functions */
192static int ns2_tx_simple(struct gprs_ns2_vc *nsvc, uint8_t pdu_type)
193{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100194 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200195 struct gprs_ns_hdr *nsh;
196
Daniel Willmann751977b2020-12-02 18:59:44 +0100197 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200198 log_set_context(LOG_CTX_GB_NSVC, nsvc);
199
200 if (!msg)
201 return -ENOMEM;
202
203 msg->l2h = msgb_put(msg, sizeof(*nsh));
204 nsh = (struct gprs_ns_hdr *) msg->l2h;
Alexander Couzens6a161492020-07-12 13:45:50 +0200205 nsh->pdu_type = pdu_type;
206
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100207 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100208 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200209}
210
Harald Welte5bef2cc2020-09-18 22:33:24 +0200211/*! Transmit a NS-BLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200212 * \param[in] vc NS-VC on which the NS-BLOCK is to be transmitted
213 * \param[in] cause Numeric NS Cause value
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200214 * \param[in] nsvci if given this NSVCI will be encoded. If NULL the nsvc->nsvci will be used.
Harald Welte5bef2cc2020-09-18 22:33:24 +0200215 * \returns 0 in case of success */
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200216int ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause, uint16_t *nsvci)
Alexander Couzens6a161492020-07-12 13:45:50 +0200217{
218 struct msgb *msg;
219 struct gprs_ns_hdr *nsh;
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200220 uint16_t encoded_nsvci;
221
222 if (nsvci)
223 encoded_nsvci = osmo_htons(*nsvci);
224 else
225 encoded_nsvci = osmo_htons(nsvc->nsvci);
Alexander Couzens6a161492020-07-12 13:45:50 +0200226
Daniel Willmann751977b2020-12-02 18:59:44 +0100227 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200228 log_set_context(LOG_CTX_GB_NSVC, nsvc);
229
230 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK");
231
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100232 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200233 if (!msg)
234 return -ENOMEM;
235
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200236 rate_ctr_inc(rate_ctr_group_get_ctr(nsvc->ctrg, NS_CTR_BLOCKED));
Alexander Couzens6a161492020-07-12 13:45:50 +0200237
238 msg->l2h = msgb_put(msg, sizeof(*nsh));
239 nsh = (struct gprs_ns_hdr *) msg->l2h;
240 nsh->pdu_type = NS_PDUT_BLOCK;
241
242 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200243 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &encoded_nsvci);
Alexander Couzens6a161492020-07-12 13:45:50 +0200244
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100245 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n", gprs_ns2_cause_str(cause));
Harald Welte5a5bf722021-01-30 21:49:28 +0100246 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200247}
248
Harald Welte5bef2cc2020-09-18 22:33:24 +0200249/*! Transmit a NS-BLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200250 * \param[in] nsvc NS-VC on which the NS-BLOCK is to be transmitted
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200251 * \param[in] nsvci if given this NSVCI will be encoded. If NULL the nsvc->nsvci will be used.
Harald Welte5bef2cc2020-09-18 22:33:24 +0200252 * \returns 0 in case of success */
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200253int ns2_tx_block_ack(struct gprs_ns2_vc *nsvc, uint16_t *nsvci)
Alexander Couzens6a161492020-07-12 13:45:50 +0200254{
255 struct msgb *msg;
256 struct gprs_ns_hdr *nsh;
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200257 uint16_t encoded_nsvci;
258
259 if (nsvci)
260 encoded_nsvci = osmo_htons(*nsvci);
261 else
262 encoded_nsvci = osmo_htons(nsvc->nsvci);
Alexander Couzens6a161492020-07-12 13:45:50 +0200263
Daniel Willmann751977b2020-12-02 18:59:44 +0100264 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200265 log_set_context(LOG_CTX_GB_NSVC, nsvc);
266
267 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK ACK");
268
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100269 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200270 if (!msg)
271 return -ENOMEM;
272
Alexander Couzens6a161492020-07-12 13:45:50 +0200273 msg->l2h = msgb_put(msg, sizeof(*nsh));
274 nsh = (struct gprs_ns_hdr *) msg->l2h;
275 nsh->pdu_type = NS_PDUT_BLOCK_ACK;
276
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200277 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &encoded_nsvci);
Alexander Couzens6a161492020-07-12 13:45:50 +0200278
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100279 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100280 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200281}
282
Harald Welte5bef2cc2020-09-18 22:33:24 +0200283/*! Transmit a NS-RESET on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200284 * \param[in] nsvc NS-VC used for transmission
Vadim Yanitskiy64277a02023-02-28 03:30:27 +0700285 * \param[in] cause Numeric NS cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200286 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200287int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause)
288{
289 struct msgb *msg;
290 struct gprs_ns_hdr *nsh;
291 uint16_t nsvci = osmo_htons(nsvc->nsvci);
292 uint16_t nsei = osmo_htons(nsvc->nse->nsei);
293
Daniel Willmann751977b2020-12-02 18:59:44 +0100294 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200295 log_set_context(LOG_CTX_GB_NSVC, nsvc);
296
297 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET");
298
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100299 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200300 if (!msg)
301 return -ENOMEM;
302
Alexander Couzens6a161492020-07-12 13:45:50 +0200303 msg->l2h = msgb_put(msg, sizeof(*nsh));
304 nsh = (struct gprs_ns_hdr *) msg->l2h;
305 nsh->pdu_type = NS_PDUT_RESET;
306
307 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
308 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
309 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei);
310
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100311 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n", gprs_ns2_cause_str(cause));
Harald Welte5a5bf722021-01-30 21:49:28 +0100312 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200313}
314
Harald Welte5bef2cc2020-09-18 22:33:24 +0200315/*! Transmit a NS-RESET-ACK on a given NS-VC.
316 * \param[in] nsvc NS-VC used for transmission
317 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200318int ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc)
319{
320 struct msgb *msg;
321 struct gprs_ns_hdr *nsh;
322 uint16_t nsvci, nsei;
323
Harald Welte5bef2cc2020-09-18 22:33:24 +0200324 /* Section 9.2.6 */
Daniel Willmann751977b2020-12-02 18:59:44 +0100325 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200326 log_set_context(LOG_CTX_GB_NSVC, nsvc);
327
328 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET ACK");
329
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100330 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200331 if (!msg)
332 return -ENOMEM;
333
334 nsvci = osmo_htons(nsvc->nsvci);
335 nsei = osmo_htons(nsvc->nse->nsei);
336
337 msg->l2h = msgb_put(msg, sizeof(*nsh));
338 nsh = (struct gprs_ns_hdr *) msg->l2h;
339
340 nsh->pdu_type = NS_PDUT_RESET_ACK;
341
Alexander Couzens6a161492020-07-12 13:45:50 +0200342 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
343 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
344
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100345 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100346 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200347}
348
Harald Welte5bef2cc2020-09-18 22:33:24 +0200349/*! Transmit a NS-UNBLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200350 * \param[in] nsvc NS-VC on which the NS-UNBLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200351 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200352int ns2_tx_unblock(struct gprs_ns2_vc *nsvc)
353{
Daniel Willmann751977b2020-12-02 18:59:44 +0100354 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200355 log_set_context(LOG_CTX_GB_NSVC, nsvc);
356
357 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK");
358
Alexander Couzens6a161492020-07-12 13:45:50 +0200359 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK);
360}
361
362
Harald Welte5bef2cc2020-09-18 22:33:24 +0200363/*! Transmit a NS-UNBLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200364 * \param[in] nsvc NS-VC on which the NS-UNBLOCK-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200365 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200366int ns2_tx_unblock_ack(struct gprs_ns2_vc *nsvc)
367{
Daniel Willmann751977b2020-12-02 18:59:44 +0100368 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200369 log_set_context(LOG_CTX_GB_NSVC, nsvc);
370
371 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK ACK");
372
Alexander Couzens6a161492020-07-12 13:45:50 +0200373 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
374}
375
Harald Welte5bef2cc2020-09-18 22:33:24 +0200376/*! Transmit a NS-ALIVE on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200377 * \param[in] nsvc NS-VC on which the NS-ALIVE is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200378 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200379int ns2_tx_alive(struct gprs_ns2_vc *nsvc)
380{
Daniel Willmann751977b2020-12-02 18:59:44 +0100381 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200382 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200383
384 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE);
385}
386
Harald Welte5bef2cc2020-09-18 22:33:24 +0200387/*! Transmit a NS-ALIVE-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200388 * \param[in] nsvc NS-VC on which the NS-ALIVE-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200389 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200390int ns2_tx_alive_ack(struct gprs_ns2_vc *nsvc)
391{
Daniel Willmann751977b2020-12-02 18:59:44 +0100392 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200393 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200394
395 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE_ACK);
396}
397
Harald Welte5bef2cc2020-09-18 22:33:24 +0200398/*! Transmit NS-UNITDATA on a given NS-VC.
399 * \param[in] nsvc NS-VC on which the NS-UNITDATA is to be transmitted
400 * \param[in] bvci BVCI to encode in NS-UNITDATA header
401 * \param[in] sducontrol SDU control octet of NS header
402 * \param[in] msg message buffer containing payload
403 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200404int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
405 uint16_t bvci, uint8_t sducontrol,
406 struct msgb *msg)
407{
408 struct gprs_ns_hdr *nsh;
409
Daniel Willmann751977b2020-12-02 18:59:44 +0100410 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200411 log_set_context(LOG_CTX_GB_NSVC, nsvc);
412
413 msg->l2h = msgb_push(msg, sizeof(*nsh) + 3);
414 nsh = (struct gprs_ns_hdr *) msg->l2h;
415 if (!nsh) {
Harald Weltef2949742021-01-20 14:54:14 +0100416 LOGNSVC(nsvc, LOGL_ERROR, "Not enough headroom for NS header\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200417 msgb_free(msg);
418 return -EIO;
419 }
420
421 nsh->pdu_type = NS_PDUT_UNITDATA;
422 nsh->data[0] = sducontrol;
423 nsh->data[1] = bvci >> 8;
424 nsh->data[2] = bvci & 0xff;
425
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100426 LOG_NS_DATA(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, "\n");
Harald Welte5a5bf722021-01-30 21:49:28 +0100427 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200428}
429
Harald Welte5bef2cc2020-09-18 22:33:24 +0200430/*! Transmit a NS-STATUS on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200431 * \param[in] nsvc NS-VC to be used for transmission
432 * \param[in] cause Numeric NS cause value
433 * \param[in] bvci BVCI to be reset within NSVC
Harald Welte5bef2cc2020-09-18 22:33:24 +0200434 * \param[in] orig_msg message causing the STATUS
Alexander Couzensd802f9a2021-09-23 16:19:32 +0200435 * \param[in] nsvci if given this NSVCI will be encoded. If NULL the nsvc->nsvci will be used.
Harald Welte5bef2cc2020-09-18 22:33:24 +0200436 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200437int ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,
Alexander Couzensd802f9a2021-09-23 16:19:32 +0200438 uint16_t bvci, struct msgb *orig_msg, uint16_t *nsvci)
Alexander Couzens6a161492020-07-12 13:45:50 +0200439{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100440 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200441 struct gprs_ns_hdr *nsh;
Alexander Couzensd802f9a2021-09-23 16:19:32 +0200442 uint16_t encoded_nsvci;
Alexander Couzenscf1fa632021-02-15 04:51:14 +0100443 unsigned int orig_len, max_orig_len;
Alexander Couzens6a161492020-07-12 13:45:50 +0200444
Daniel Willmann751977b2020-12-02 18:59:44 +0100445 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200446 log_set_context(LOG_CTX_GB_NSVC, nsvc);
447
448 bvci = osmo_htons(bvci);
449
450 if (!msg)
451 return -ENOMEM;
452
Alexander Couzens6a161492020-07-12 13:45:50 +0200453 msg->l2h = msgb_put(msg, sizeof(*nsh));
454 nsh = (struct gprs_ns_hdr *) msg->l2h;
455 nsh->pdu_type = NS_PDUT_STATUS;
456
457 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
458
Alexander Couzens6a161492020-07-12 13:45:50 +0200459 switch (cause) {
Alexander Couzensce646c22021-02-15 04:55:08 +0100460 case NS_CAUSE_NSVC_BLOCKED:
461 case NS_CAUSE_NSVC_UNKNOWN:
462 /* Section 9.2.7.1: Static conditions for NS-VCI */
Alexander Couzensd802f9a2021-09-23 16:19:32 +0200463 if (nsvci)
464 encoded_nsvci = osmo_htons(*nsvci);
465 else
466 encoded_nsvci = osmo_htons(nsvc->nsvci);
467 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&encoded_nsvci);
Alexander Couzensce646c22021-02-15 04:55:08 +0100468 break;
Alexander Couzens6a161492020-07-12 13:45:50 +0200469 case NS_CAUSE_SEM_INCORR_PDU:
470 case NS_CAUSE_PDU_INCOMP_PSTATE:
471 case NS_CAUSE_PROTO_ERR_UNSPEC:
472 case NS_CAUSE_INVAL_ESSENT_IE:
473 case NS_CAUSE_MISSING_ESSENT_IE:
Alexander Couzensce646c22021-02-15 04:55:08 +0100474 /* Section 9.2.7.2: Static conditions for NS PDU */
Alexander Couzenscf1fa632021-02-15 04:51:14 +0100475 /* ensure the PDU doesn't exceed the MTU */
476 orig_len = msgb_l2len(orig_msg);
477 max_orig_len = msgb_length(msg) + TVLV_GROSS_LEN(orig_len);
478 if (max_orig_len > nsvc->bind->mtu)
479 orig_len -= max_orig_len - nsvc->bind->mtu;
480 msgb_tvlv_put(msg, NS_IE_PDU, orig_len, orig_msg->l2h);
Alexander Couzens6a161492020-07-12 13:45:50 +0200481 break;
Alexander Couzensce646c22021-02-15 04:55:08 +0100482 case NS_CAUSE_BVCI_UNKNOWN:
483 /* Section 9.2.7.3: Static conditions for BVCI */
484 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci);
485 break;
486
Alexander Couzens6a161492020-07-12 13:45:50 +0200487 default:
488 break;
489 }
490
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100491 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n", gprs_ns2_cause_str(cause));
Harald Welte5a5bf722021-01-30 21:49:28 +0100492 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200493}
494
Alexander Couzens27a55922021-02-27 01:08:35 +0100495/*! Encode + Transmit a SNS-ADD/SNS-CHANGE-WEIGHT as per Section 9.3.2/9.3.3.
496 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
497 * \param[in] pdu The PDU type to send out
498 * \param[in] trans_id The transaction id
499 * \param[in] ip4_elems Array of IPv4 Elements
500 * \param[in] num_ip4_elems number of ip4_elems
501 * \param[in] ip6_elems Array of IPv6 Elements
502 * \param[in] num_ip6_elems number of ip6_elems
503 * \returns 0 on success; negative in case of error */
504static int ns2_tx_sns_procedure(struct gprs_ns2_vc *nsvc,
505 enum ns_pdu_type pdu,
506 uint8_t trans_id,
507 const struct gprs_ns_ie_ip4_elem *ip4_elems,
508 unsigned int num_ip4_elems,
509 const struct gprs_ns_ie_ip6_elem *ip6_elems,
510 unsigned int num_ip6_elems)
511{
512 struct msgb *msg;
513 struct gprs_ns_hdr *nsh;
514 uint16_t nsei;
515
516 if (!nsvc)
517 return -EINVAL;
518
519 if (!ip4_elems && !ip6_elems)
520 return -EINVAL;
521
522 msg = ns2_msgb_alloc();
523
524 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
525 log_set_context(LOG_CTX_GB_NSVC, nsvc);
526 if (!msg)
527 return -ENOMEM;
528
529 if (!nsvc->nse->bss_sns_fi) {
530 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
531 msgb_free(msg);
532 return -EIO;
533 }
534
535 nsei = osmo_htons(nsvc->nse->nsei);
536
537 msg->l2h = msgb_put(msg, sizeof(*nsh));
538 nsh = (struct gprs_ns_hdr *) msg->l2h;
539 nsh->pdu_type = pdu;
540 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
541 msgb_v_put(msg, trans_id);
542
543 /* List of IP4 Elements 10.3.2c */
544 if (ip4_elems) {
545 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
546 (const uint8_t *)ip4_elems);
547 } else if (ip6_elems) {
548 /* List of IP6 elements 10.3.2d */
549 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
550 (const uint8_t *)ip6_elems);
551 }
552
553 return ns_vc_tx(nsvc, msg);
554}
555
556/*! Encode + Transmit a SNS-ADD as per Section 9.3.2.
557 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
558 * \param[in] trans_id The transaction id
559 * \param[in] ip4_elems Array of IPv4 Elements
560 * \param[in] num_ip4_elems number of ip4_elems
561 * \param[in] ip6_elems Array of IPv6 Elements
562 * \param[in] num_ip6_elems number of ip6_elems
563 * \returns 0 on success; negative in case of error */
564int ns2_tx_sns_add(struct gprs_ns2_vc *nsvc,
565 uint8_t trans_id,
566 const struct gprs_ns_ie_ip4_elem *ip4_elems,
567 unsigned int num_ip4_elems,
568 const struct gprs_ns_ie_ip6_elem *ip6_elems,
569 unsigned int num_ip6_elems)
570{
571 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_ADD, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
572}
573
574/*! Encode + Transmit a SNS-CHANGE-WEIGHT as per Section 9.3.3.
575 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
576 * \param[in] trans_id The transaction id
577 * \param[in] ip4_elems Array of IPv4 Elements
578 * \param[in] num_ip4_elems number of ip4_elems
579 * \param[in] ip6_elems Array of IPv6 Elements
580 * \param[in] num_ip6_elems number of ip6_elems
581 * \returns 0 on success; negative in case of error */
582int ns2_tx_sns_change_weight(struct gprs_ns2_vc *nsvc,
583 uint8_t trans_id,
584 const struct gprs_ns_ie_ip4_elem *ip4_elems,
585 unsigned int num_ip4_elems,
586 const struct gprs_ns_ie_ip6_elem *ip6_elems,
587 unsigned int num_ip6_elems)
588{
589 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_CHANGE_WEIGHT, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
590}
591
592/*! Encode + Transmit a SNS-DEL as per Section 9.3.6.
593 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
594 * \param[in] trans_id The transaction id
595 * \param[in] ip4_elems Array of IPv4 Elements
596 * \param[in] num_ip4_elems number of ip4_elems
597 * \param[in] ip6_elems Array of IPv6 Elements
598 * \param[in] num_ip6_elems number of ip6_elems
599 * \returns 0 on success; negative in case of error */
600int ns2_tx_sns_del(struct gprs_ns2_vc *nsvc,
601 uint8_t trans_id,
602 const struct gprs_ns_ie_ip4_elem *ip4_elems,
603 unsigned int num_ip4_elems,
604 const struct gprs_ns_ie_ip6_elem *ip6_elems,
605 unsigned int num_ip6_elems)
606{
607 /* TODO: IP Address field */
608 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_DELETE, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
609}
610
Alexander Couzens6a161492020-07-12 13:45:50 +0200611
612/*! Encode + Transmit a SNS-ACK as per Section 9.3.1.
613 * \param[in] nsvc NS-VC through which to transmit the ACK
614 * \param[in] trans_id Transaction ID which to acknowledge
615 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
616 * \param[in] ip4_elems Array of IPv4 Elements
617 * \param[in] num_ip4_elems number of ip4_elems
618 * \returns 0 on success; negative in case of error */
619int ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,
620 const struct gprs_ns_ie_ip4_elem *ip4_elems,
621 unsigned int num_ip4_elems,
622 const struct gprs_ns_ie_ip6_elem *ip6_elems,
623 unsigned int num_ip6_elems)
624{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100625 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200626 struct gprs_ns_hdr *nsh;
627 uint16_t nsei;
628
629 if (!nsvc)
630 return -1;
631
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100632 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200633
Daniel Willmann751977b2020-12-02 18:59:44 +0100634 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200635 log_set_context(LOG_CTX_GB_NSVC, nsvc);
636 if (!msg)
637 return -ENOMEM;
638
639 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100640 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200641 msgb_free(msg);
642 return -EIO;
643 }
644
Harald Welte22274df2021-03-04 07:59:16 +0100645
Alexander Couzens6a161492020-07-12 13:45:50 +0200646 nsei = osmo_htons(nsvc->nse->nsei);
647
648 msg->l2h = msgb_put(msg, sizeof(*nsh));
649 nsh = (struct gprs_ns_hdr *) msg->l2h;
650
651 nsh->pdu_type = SNS_PDUT_ACK;
652 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
653 msgb_v_put(msg, trans_id);
654 if (cause)
655 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
656 if (ip4_elems) {
657 /* List of IP4 Elements 10.3.2c */
658 msgb_tvlv_put(msg, NS_IE_IPv4_LIST,
659 num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
660 (const uint8_t *)ip4_elems);
661 }
662 if (ip6_elems) {
663 /* List of IP6 elements 10.3.2d */
664 msgb_tvlv_put(msg, NS_IE_IPv6_LIST,
665 num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
666 (const uint8_t *)ip6_elems);
667 }
668
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100669 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
670 " (trans_id=%u, cause=%s, num_ip4=%u, num_ip6=%u)\n",
671 trans_id, cause ? gprs_ns2_cause_str(*cause) : "NULL", num_ip4_elems, num_ip6_elems);
Harald Welte5a5bf722021-01-30 21:49:28 +0100672 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200673}
674
675/*! Encode + Transmit a SNS-CONFIG as per Section 9.3.4.
676 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
677 * \param[in] end_flag Whether or not this is the last SNS-CONFIG
678 * \param[in] ip4_elems Array of IPv4 Elements
679 * \param[in] num_ip4_elems number of ip4_elems
680 * \returns 0 on success; negative in case of error */
681int ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,
682 const struct gprs_ns_ie_ip4_elem *ip4_elems,
683 unsigned int num_ip4_elems,
684 const struct gprs_ns_ie_ip6_elem *ip6_elems,
685 unsigned int num_ip6_elems)
686{
687 struct msgb *msg;
688 struct gprs_ns_hdr *nsh;
689 uint16_t nsei;
690
691 if (!nsvc)
692 return -1;
693
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100694 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200695
Daniel Willmann751977b2020-12-02 18:59:44 +0100696 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200697 log_set_context(LOG_CTX_GB_NSVC, nsvc);
698 if (!msg)
699 return -ENOMEM;
700
701 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100702 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200703 msgb_free(msg);
704 return -EIO;
705 }
706
707 nsei = osmo_htons(nsvc->nse->nsei);
708
709 msg->l2h = msgb_put(msg, sizeof(*nsh));
710 nsh = (struct gprs_ns_hdr *) msg->l2h;
711
712 nsh->pdu_type = SNS_PDUT_CONFIG;
713
714 msgb_v_put(msg, end_flag ? 0x01 : 0x00);
715 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
716
717 /* List of IP4 Elements 10.3.2c */
718 if (ip4_elems) {
719 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
720 (const uint8_t *)ip4_elems);
721 } else if (ip6_elems) {
722 /* List of IP6 elements 10.3.2d */
723 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
724 (const uint8_t *)ip6_elems);
725 }
726
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100727 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
728 " (end_flag=%u, num_ip4=%u, num_ip6=%u)\n",
729 end_flag, num_ip4_elems, num_ip6_elems);
Harald Welte5a5bf722021-01-30 21:49:28 +0100730 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200731}
732
733/*! Encode + Transmit a SNS-CONFIG-ACK as per Section 9.3.5.
734 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG-ACK
735 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
736 * \returns 0 on success; negative in case of error */
737int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
738{
739 struct msgb *msg;
740 struct gprs_ns_hdr *nsh;
741 uint16_t nsei;
742
743 if (!nsvc)
744 return -1;
745
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100746 msg = ns2_msgb_alloc();
Daniel Willmann751977b2020-12-02 18:59:44 +0100747 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200748 log_set_context(LOG_CTX_GB_NSVC, nsvc);
749 if (!msg)
750 return -ENOMEM;
751
752 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100753 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200754 msgb_free(msg);
755 return -EIO;
756 }
757
758 nsei = osmo_htons(nsvc->nse->nsei);
759
760 msg->l2h = msgb_put(msg, sizeof(*nsh));
761 nsh = (struct gprs_ns_hdr *) msg->l2h;
762
763 nsh->pdu_type = SNS_PDUT_CONFIG_ACK;
764
765 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
766 if (cause)
767 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
768
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100769 LOGNSVC(nsvc, LOGL_INFO, "Tx SNS-CONFIG-ACK (cause=%s)\n",
770 cause ? gprs_ns2_cause_str(*cause) : "NULL");
771 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100772 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200773}
774
775
776/*! Encode + transmit a SNS-SIZE as per Section 9.3.7.
777 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE
778 * \param[in] reset_flag Whether or not to add a RESET flag
779 * \param[in] max_nr_nsvc Maximum number of NS-VCs
780 * \param[in] ip4_ep_nr Number of IPv4 endpoints (< 0 will omit the TLV)
781 * \param[in] ip6_ep_nr Number of IPv6 endpoints (< 0 will omit the TLV)
782 * \returns 0 on success; negative in case of error */
783int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_nsvc,
784 int ip4_ep_nr, int ip6_ep_nr)
785{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100786 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200787 struct gprs_ns_hdr *nsh;
788 uint16_t nsei;
789
790 if (!nsvc)
791 return -1;
792
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100793 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200794
Daniel Willmann751977b2020-12-02 18:59:44 +0100795 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200796 log_set_context(LOG_CTX_GB_NSVC, nsvc);
797 if (!msg)
798 return -ENOMEM;
799
800 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100801 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200802 msgb_free(msg);
803 return -EIO;
804 }
805
806 nsei = osmo_htons(nsvc->nse->nsei);
807
808 msg->l2h = msgb_put(msg, sizeof(*nsh));
809 nsh = (struct gprs_ns_hdr *) msg->l2h;
810
811 nsh->pdu_type = SNS_PDUT_SIZE;
812
813 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
814 msgb_tv_put(msg, NS_IE_RESET_FLAG, reset_flag ? 0x01 : 0x00);
815 msgb_tv16_put(msg, NS_IE_MAX_NR_NSVC, max_nr_nsvc);
816 if (ip4_ep_nr >= 0)
817 msgb_tv16_put(msg, NS_IE_IPv4_EP_NR, ip4_ep_nr);
818 if (ip6_ep_nr >= 0)
819 msgb_tv16_put(msg, NS_IE_IPv6_EP_NR, ip6_ep_nr);
820
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100821 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
Alexander Couzens6ba77a32021-07-06 11:34:04 +0200822 " (reset=%u, max_nr_nsvc=%u, num_ip4=%d, num_ip6=%d)\n",
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100823 reset_flag, max_nr_nsvc, ip4_ep_nr, ip6_ep_nr);
Harald Welte5a5bf722021-01-30 21:49:28 +0100824 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200825}
826
827/*! Encode + Transmit a SNS-SIZE-ACK as per Section 9.3.8.
828 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE-ACK
829 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
830 * \returns 0 on success; negative in case of error */
831int ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
832{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100833 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200834 struct gprs_ns_hdr *nsh;
835 uint16_t nsei;
836
Daniel Willmann751977b2020-12-02 18:59:44 +0100837 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200838 log_set_context(LOG_CTX_GB_NSVC, nsvc);
839 if (!msg)
840 return -ENOMEM;
841
842 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100843 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200844 msgb_free(msg);
845 return -EIO;
846 }
847
848 nsei = osmo_htons(nsvc->nse->nsei);
849
850 msg->l2h = msgb_put(msg, sizeof(*nsh));
851 nsh = (struct gprs_ns_hdr *) msg->l2h;
852
853 nsh->pdu_type = SNS_PDUT_SIZE_ACK;
854
855 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
856 if (cause)
857 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
858
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100859 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n",
860 cause ? gprs_ns2_cause_str(*cause) : "NULL");
Harald Welte5a5bf722021-01-30 21:49:28 +0100861 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200862}