blob: de63b7aac06f8fcd0ae67d78008460502bf93b0f [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
Harald Welte5a5bf722021-01-30 21:49:28 +0100172static int ns_vc_tx(struct gprs_ns2_vc *nsvc, struct msgb *msg)
173{
Pau Espin Pedrol8f026bf2023-04-27 16:00:01 +0200174 return nsvc->bind->send_vc(nsvc, msg);
Harald Welte5a5bf722021-01-30 21:49:28 +0100175}
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;
Alexander Couzens6a161492020-07-12 13:45:50 +0200191 nsh->pdu_type = pdu_type;
192
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100193 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
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
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200200 * \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 +0200201 * \returns 0 in case of success */
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200202int ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause, uint16_t *nsvci)
Alexander Couzens6a161492020-07-12 13:45:50 +0200203{
204 struct msgb *msg;
205 struct gprs_ns_hdr *nsh;
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200206 uint16_t encoded_nsvci;
207
208 if (nsvci)
209 encoded_nsvci = osmo_htons(*nsvci);
210 else
211 encoded_nsvci = osmo_htons(nsvc->nsvci);
Alexander Couzens6a161492020-07-12 13:45:50 +0200212
Daniel Willmann751977b2020-12-02 18:59:44 +0100213 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200214 log_set_context(LOG_CTX_GB_NSVC, nsvc);
215
216 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK");
217
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100218 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200219 if (!msg)
220 return -ENOMEM;
221
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200222 rate_ctr_inc(rate_ctr_group_get_ctr(nsvc->ctrg, NS_CTR_BLOCKED));
Alexander Couzens6a161492020-07-12 13:45:50 +0200223
224 msg->l2h = msgb_put(msg, sizeof(*nsh));
225 nsh = (struct gprs_ns_hdr *) msg->l2h;
226 nsh->pdu_type = NS_PDUT_BLOCK;
227
228 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200229 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &encoded_nsvci);
Alexander Couzens6a161492020-07-12 13:45:50 +0200230
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100231 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 +0100232 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200233}
234
Harald Welte5bef2cc2020-09-18 22:33:24 +0200235/*! Transmit a NS-BLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200236 * \param[in] nsvc NS-VC on which the NS-BLOCK is to be transmitted
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200237 * \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 +0200238 * \returns 0 in case of success */
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200239int ns2_tx_block_ack(struct gprs_ns2_vc *nsvc, uint16_t *nsvci)
Alexander Couzens6a161492020-07-12 13:45:50 +0200240{
241 struct msgb *msg;
242 struct gprs_ns_hdr *nsh;
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200243 uint16_t encoded_nsvci;
244
245 if (nsvci)
246 encoded_nsvci = osmo_htons(*nsvci);
247 else
248 encoded_nsvci = osmo_htons(nsvc->nsvci);
Alexander Couzens6a161492020-07-12 13:45:50 +0200249
Daniel Willmann751977b2020-12-02 18:59:44 +0100250 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200251 log_set_context(LOG_CTX_GB_NSVC, nsvc);
252
253 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK ACK");
254
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100255 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200256 if (!msg)
257 return -ENOMEM;
258
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
Alexander Couzens67cfc5d2021-09-07 01:10:38 +0200263 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &encoded_nsvci);
Alexander Couzens6a161492020-07-12 13:45:50 +0200264
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100265 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100266 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200267}
268
Harald Welte5bef2cc2020-09-18 22:33:24 +0200269/*! Transmit a NS-RESET on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200270 * \param[in] nsvc NS-VC used for transmission
Vadim Yanitskiy64277a02023-02-28 03:30:27 +0700271 * \param[in] cause Numeric NS cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200272 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200273int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause)
274{
275 struct msgb *msg;
276 struct gprs_ns_hdr *nsh;
277 uint16_t nsvci = osmo_htons(nsvc->nsvci);
278 uint16_t nsei = osmo_htons(nsvc->nse->nsei);
279
Daniel Willmann751977b2020-12-02 18:59:44 +0100280 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200281 log_set_context(LOG_CTX_GB_NSVC, nsvc);
282
283 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET");
284
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100285 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200286 if (!msg)
287 return -ENOMEM;
288
Alexander Couzens6a161492020-07-12 13:45:50 +0200289 msg->l2h = msgb_put(msg, sizeof(*nsh));
290 nsh = (struct gprs_ns_hdr *) msg->l2h;
291 nsh->pdu_type = NS_PDUT_RESET;
292
293 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
294 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
295 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei);
296
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100297 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 +0100298 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200299}
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
Alexander Couzens6a161492020-07-12 13:45:50 +0200328 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
329 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
330
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100331 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100332 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200333}
334
Harald Welte5bef2cc2020-09-18 22:33:24 +0200335/*! Transmit a NS-UNBLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200336 * \param[in] nsvc NS-VC on which the NS-UNBLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200337 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200338int ns2_tx_unblock(struct gprs_ns2_vc *nsvc)
339{
Daniel Willmann751977b2020-12-02 18:59:44 +0100340 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200341 log_set_context(LOG_CTX_GB_NSVC, nsvc);
342
343 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK");
344
Alexander Couzens6a161492020-07-12 13:45:50 +0200345 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK);
346}
347
348
Harald Welte5bef2cc2020-09-18 22:33:24 +0200349/*! Transmit a NS-UNBLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200350 * \param[in] nsvc NS-VC on which the NS-UNBLOCK-ACK 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_ack(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 ACK");
358
Alexander Couzens6a161492020-07-12 13:45:50 +0200359 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
360}
361
Harald Welte5bef2cc2020-09-18 22:33:24 +0200362/*! Transmit a NS-ALIVE on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200363 * \param[in] nsvc NS-VC on which the NS-ALIVE is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200364 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200365int ns2_tx_alive(struct gprs_ns2_vc *nsvc)
366{
Daniel Willmann751977b2020-12-02 18:59:44 +0100367 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200368 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200369
370 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE);
371}
372
Harald Welte5bef2cc2020-09-18 22:33:24 +0200373/*! Transmit a NS-ALIVE-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200374 * \param[in] nsvc NS-VC on which the NS-ALIVE-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200375 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200376int ns2_tx_alive_ack(struct gprs_ns2_vc *nsvc)
377{
Daniel Willmann751977b2020-12-02 18:59:44 +0100378 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200379 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200380
381 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE_ACK);
382}
383
Harald Welte5bef2cc2020-09-18 22:33:24 +0200384/*! Transmit NS-UNITDATA on a given NS-VC.
385 * \param[in] nsvc NS-VC on which the NS-UNITDATA is to be transmitted
386 * \param[in] bvci BVCI to encode in NS-UNITDATA header
387 * \param[in] sducontrol SDU control octet of NS header
388 * \param[in] msg message buffer containing payload
389 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200390int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
391 uint16_t bvci, uint8_t sducontrol,
392 struct msgb *msg)
393{
394 struct gprs_ns_hdr *nsh;
395
Daniel Willmann751977b2020-12-02 18:59:44 +0100396 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200397 log_set_context(LOG_CTX_GB_NSVC, nsvc);
398
399 msg->l2h = msgb_push(msg, sizeof(*nsh) + 3);
400 nsh = (struct gprs_ns_hdr *) msg->l2h;
401 if (!nsh) {
Harald Weltef2949742021-01-20 14:54:14 +0100402 LOGNSVC(nsvc, LOGL_ERROR, "Not enough headroom for NS header\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200403 msgb_free(msg);
404 return -EIO;
405 }
406
407 nsh->pdu_type = NS_PDUT_UNITDATA;
408 nsh->data[0] = sducontrol;
409 nsh->data[1] = bvci >> 8;
410 nsh->data[2] = bvci & 0xff;
411
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100412 LOG_NS_DATA(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, "\n");
Harald Welte5a5bf722021-01-30 21:49:28 +0100413 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200414}
415
Harald Welte5bef2cc2020-09-18 22:33:24 +0200416/*! Transmit a NS-STATUS on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200417 * \param[in] nsvc NS-VC to be used for transmission
418 * \param[in] cause Numeric NS cause value
419 * \param[in] bvci BVCI to be reset within NSVC
Harald Welte5bef2cc2020-09-18 22:33:24 +0200420 * \param[in] orig_msg message causing the STATUS
Alexander Couzensd802f9a2021-09-23 16:19:32 +0200421 * \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 +0200422 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200423int ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,
Alexander Couzensd802f9a2021-09-23 16:19:32 +0200424 uint16_t bvci, struct msgb *orig_msg, uint16_t *nsvci)
Alexander Couzens6a161492020-07-12 13:45:50 +0200425{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100426 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200427 struct gprs_ns_hdr *nsh;
Alexander Couzensd802f9a2021-09-23 16:19:32 +0200428 uint16_t encoded_nsvci;
Alexander Couzenscf1fa632021-02-15 04:51:14 +0100429 unsigned int orig_len, max_orig_len;
Alexander Couzens6a161492020-07-12 13:45:50 +0200430
Daniel Willmann751977b2020-12-02 18:59:44 +0100431 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200432 log_set_context(LOG_CTX_GB_NSVC, nsvc);
433
434 bvci = osmo_htons(bvci);
435
436 if (!msg)
437 return -ENOMEM;
438
Alexander Couzens6a161492020-07-12 13:45:50 +0200439 msg->l2h = msgb_put(msg, sizeof(*nsh));
440 nsh = (struct gprs_ns_hdr *) msg->l2h;
441 nsh->pdu_type = NS_PDUT_STATUS;
442
443 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
444
Alexander Couzens6a161492020-07-12 13:45:50 +0200445 switch (cause) {
Alexander Couzensce646c22021-02-15 04:55:08 +0100446 case NS_CAUSE_NSVC_BLOCKED:
447 case NS_CAUSE_NSVC_UNKNOWN:
448 /* Section 9.2.7.1: Static conditions for NS-VCI */
Alexander Couzensd802f9a2021-09-23 16:19:32 +0200449 if (nsvci)
450 encoded_nsvci = osmo_htons(*nsvci);
451 else
452 encoded_nsvci = osmo_htons(nsvc->nsvci);
453 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&encoded_nsvci);
Alexander Couzensce646c22021-02-15 04:55:08 +0100454 break;
Alexander Couzens6a161492020-07-12 13:45:50 +0200455 case NS_CAUSE_SEM_INCORR_PDU:
456 case NS_CAUSE_PDU_INCOMP_PSTATE:
457 case NS_CAUSE_PROTO_ERR_UNSPEC:
458 case NS_CAUSE_INVAL_ESSENT_IE:
459 case NS_CAUSE_MISSING_ESSENT_IE:
Alexander Couzensce646c22021-02-15 04:55:08 +0100460 /* Section 9.2.7.2: Static conditions for NS PDU */
Alexander Couzenscf1fa632021-02-15 04:51:14 +0100461 /* ensure the PDU doesn't exceed the MTU */
462 orig_len = msgb_l2len(orig_msg);
463 max_orig_len = msgb_length(msg) + TVLV_GROSS_LEN(orig_len);
464 if (max_orig_len > nsvc->bind->mtu)
465 orig_len -= max_orig_len - nsvc->bind->mtu;
466 msgb_tvlv_put(msg, NS_IE_PDU, orig_len, orig_msg->l2h);
Alexander Couzens6a161492020-07-12 13:45:50 +0200467 break;
Alexander Couzensce646c22021-02-15 04:55:08 +0100468 case NS_CAUSE_BVCI_UNKNOWN:
469 /* Section 9.2.7.3: Static conditions for BVCI */
470 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci);
471 break;
472
Alexander Couzens6a161492020-07-12 13:45:50 +0200473 default:
474 break;
475 }
476
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100477 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 +0100478 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200479}
480
Alexander Couzens27a55922021-02-27 01:08:35 +0100481/*! Encode + Transmit a SNS-ADD/SNS-CHANGE-WEIGHT as per Section 9.3.2/9.3.3.
482 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
483 * \param[in] pdu The PDU type to send out
484 * \param[in] trans_id The transaction id
485 * \param[in] ip4_elems Array of IPv4 Elements
486 * \param[in] num_ip4_elems number of ip4_elems
487 * \param[in] ip6_elems Array of IPv6 Elements
488 * \param[in] num_ip6_elems number of ip6_elems
489 * \returns 0 on success; negative in case of error */
490static int ns2_tx_sns_procedure(struct gprs_ns2_vc *nsvc,
491 enum ns_pdu_type pdu,
492 uint8_t trans_id,
493 const struct gprs_ns_ie_ip4_elem *ip4_elems,
494 unsigned int num_ip4_elems,
495 const struct gprs_ns_ie_ip6_elem *ip6_elems,
496 unsigned int num_ip6_elems)
497{
498 struct msgb *msg;
499 struct gprs_ns_hdr *nsh;
500 uint16_t nsei;
501
502 if (!nsvc)
503 return -EINVAL;
504
505 if (!ip4_elems && !ip6_elems)
506 return -EINVAL;
507
508 msg = ns2_msgb_alloc();
509
510 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
511 log_set_context(LOG_CTX_GB_NSVC, nsvc);
512 if (!msg)
513 return -ENOMEM;
514
515 if (!nsvc->nse->bss_sns_fi) {
516 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
517 msgb_free(msg);
518 return -EIO;
519 }
520
521 nsei = osmo_htons(nsvc->nse->nsei);
522
523 msg->l2h = msgb_put(msg, sizeof(*nsh));
524 nsh = (struct gprs_ns_hdr *) msg->l2h;
525 nsh->pdu_type = pdu;
526 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
527 msgb_v_put(msg, trans_id);
528
529 /* List of IP4 Elements 10.3.2c */
530 if (ip4_elems) {
531 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
532 (const uint8_t *)ip4_elems);
533 } else if (ip6_elems) {
534 /* List of IP6 elements 10.3.2d */
535 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
536 (const uint8_t *)ip6_elems);
537 }
538
539 return ns_vc_tx(nsvc, msg);
540}
541
542/*! Encode + Transmit a SNS-ADD as per Section 9.3.2.
543 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
544 * \param[in] trans_id The transaction id
545 * \param[in] ip4_elems Array of IPv4 Elements
546 * \param[in] num_ip4_elems number of ip4_elems
547 * \param[in] ip6_elems Array of IPv6 Elements
548 * \param[in] num_ip6_elems number of ip6_elems
549 * \returns 0 on success; negative in case of error */
550int ns2_tx_sns_add(struct gprs_ns2_vc *nsvc,
551 uint8_t trans_id,
552 const struct gprs_ns_ie_ip4_elem *ip4_elems,
553 unsigned int num_ip4_elems,
554 const struct gprs_ns_ie_ip6_elem *ip6_elems,
555 unsigned int num_ip6_elems)
556{
557 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_ADD, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
558}
559
560/*! Encode + Transmit a SNS-CHANGE-WEIGHT as per Section 9.3.3.
561 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
562 * \param[in] trans_id The transaction id
563 * \param[in] ip4_elems Array of IPv4 Elements
564 * \param[in] num_ip4_elems number of ip4_elems
565 * \param[in] ip6_elems Array of IPv6 Elements
566 * \param[in] num_ip6_elems number of ip6_elems
567 * \returns 0 on success; negative in case of error */
568int ns2_tx_sns_change_weight(struct gprs_ns2_vc *nsvc,
569 uint8_t trans_id,
570 const struct gprs_ns_ie_ip4_elem *ip4_elems,
571 unsigned int num_ip4_elems,
572 const struct gprs_ns_ie_ip6_elem *ip6_elems,
573 unsigned int num_ip6_elems)
574{
575 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_CHANGE_WEIGHT, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
576}
577
578/*! Encode + Transmit a SNS-DEL as per Section 9.3.6.
579 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
580 * \param[in] trans_id The transaction id
581 * \param[in] ip4_elems Array of IPv4 Elements
582 * \param[in] num_ip4_elems number of ip4_elems
583 * \param[in] ip6_elems Array of IPv6 Elements
584 * \param[in] num_ip6_elems number of ip6_elems
585 * \returns 0 on success; negative in case of error */
586int ns2_tx_sns_del(struct gprs_ns2_vc *nsvc,
587 uint8_t trans_id,
588 const struct gprs_ns_ie_ip4_elem *ip4_elems,
589 unsigned int num_ip4_elems,
590 const struct gprs_ns_ie_ip6_elem *ip6_elems,
591 unsigned int num_ip6_elems)
592{
593 /* TODO: IP Address field */
594 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_DELETE, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
595}
596
Alexander Couzens6a161492020-07-12 13:45:50 +0200597
598/*! Encode + Transmit a SNS-ACK as per Section 9.3.1.
599 * \param[in] nsvc NS-VC through which to transmit the ACK
600 * \param[in] trans_id Transaction ID which to acknowledge
601 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
602 * \param[in] ip4_elems Array of IPv4 Elements
603 * \param[in] num_ip4_elems number of ip4_elems
604 * \returns 0 on success; negative in case of error */
605int ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,
606 const struct gprs_ns_ie_ip4_elem *ip4_elems,
607 unsigned int num_ip4_elems,
608 const struct gprs_ns_ie_ip6_elem *ip6_elems,
609 unsigned int num_ip6_elems)
610{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100611 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200612 struct gprs_ns_hdr *nsh;
613 uint16_t nsei;
614
615 if (!nsvc)
616 return -1;
617
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100618 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200619
Daniel Willmann751977b2020-12-02 18:59:44 +0100620 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200621 log_set_context(LOG_CTX_GB_NSVC, nsvc);
622 if (!msg)
623 return -ENOMEM;
624
625 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100626 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200627 msgb_free(msg);
628 return -EIO;
629 }
630
Harald Welte22274df2021-03-04 07:59:16 +0100631
Alexander Couzens6a161492020-07-12 13:45:50 +0200632 nsei = osmo_htons(nsvc->nse->nsei);
633
634 msg->l2h = msgb_put(msg, sizeof(*nsh));
635 nsh = (struct gprs_ns_hdr *) msg->l2h;
636
637 nsh->pdu_type = SNS_PDUT_ACK;
638 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
639 msgb_v_put(msg, trans_id);
640 if (cause)
641 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
642 if (ip4_elems) {
643 /* List of IP4 Elements 10.3.2c */
644 msgb_tvlv_put(msg, NS_IE_IPv4_LIST,
645 num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
646 (const uint8_t *)ip4_elems);
647 }
648 if (ip6_elems) {
649 /* List of IP6 elements 10.3.2d */
650 msgb_tvlv_put(msg, NS_IE_IPv6_LIST,
651 num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
652 (const uint8_t *)ip6_elems);
653 }
654
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100655 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
656 " (trans_id=%u, cause=%s, num_ip4=%u, num_ip6=%u)\n",
657 trans_id, cause ? gprs_ns2_cause_str(*cause) : "NULL", num_ip4_elems, num_ip6_elems);
Harald Welte5a5bf722021-01-30 21:49:28 +0100658 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200659}
660
661/*! Encode + Transmit a SNS-CONFIG as per Section 9.3.4.
662 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
663 * \param[in] end_flag Whether or not this is the last SNS-CONFIG
664 * \param[in] ip4_elems Array of IPv4 Elements
665 * \param[in] num_ip4_elems number of ip4_elems
666 * \returns 0 on success; negative in case of error */
667int ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,
668 const struct gprs_ns_ie_ip4_elem *ip4_elems,
669 unsigned int num_ip4_elems,
670 const struct gprs_ns_ie_ip6_elem *ip6_elems,
671 unsigned int num_ip6_elems)
672{
673 struct msgb *msg;
674 struct gprs_ns_hdr *nsh;
675 uint16_t nsei;
676
677 if (!nsvc)
678 return -1;
679
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100680 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200681
Daniel Willmann751977b2020-12-02 18:59:44 +0100682 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200683 log_set_context(LOG_CTX_GB_NSVC, nsvc);
684 if (!msg)
685 return -ENOMEM;
686
687 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100688 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200689 msgb_free(msg);
690 return -EIO;
691 }
692
693 nsei = osmo_htons(nsvc->nse->nsei);
694
695 msg->l2h = msgb_put(msg, sizeof(*nsh));
696 nsh = (struct gprs_ns_hdr *) msg->l2h;
697
698 nsh->pdu_type = SNS_PDUT_CONFIG;
699
700 msgb_v_put(msg, end_flag ? 0x01 : 0x00);
701 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
702
703 /* List of IP4 Elements 10.3.2c */
704 if (ip4_elems) {
705 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
706 (const uint8_t *)ip4_elems);
707 } else if (ip6_elems) {
708 /* List of IP6 elements 10.3.2d */
709 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
710 (const uint8_t *)ip6_elems);
711 }
712
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100713 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
714 " (end_flag=%u, num_ip4=%u, num_ip6=%u)\n",
715 end_flag, num_ip4_elems, num_ip6_elems);
Harald Welte5a5bf722021-01-30 21:49:28 +0100716 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200717}
718
719/*! Encode + Transmit a SNS-CONFIG-ACK as per Section 9.3.5.
720 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG-ACK
721 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
722 * \returns 0 on success; negative in case of error */
723int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
724{
725 struct msgb *msg;
726 struct gprs_ns_hdr *nsh;
727 uint16_t nsei;
728
729 if (!nsvc)
730 return -1;
731
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100732 msg = ns2_msgb_alloc();
Daniel Willmann751977b2020-12-02 18:59:44 +0100733 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200734 log_set_context(LOG_CTX_GB_NSVC, nsvc);
735 if (!msg)
736 return -ENOMEM;
737
738 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100739 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200740 msgb_free(msg);
741 return -EIO;
742 }
743
744 nsei = osmo_htons(nsvc->nse->nsei);
745
746 msg->l2h = msgb_put(msg, sizeof(*nsh));
747 nsh = (struct gprs_ns_hdr *) msg->l2h;
748
749 nsh->pdu_type = SNS_PDUT_CONFIG_ACK;
750
751 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
752 if (cause)
753 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
754
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100755 LOGNSVC(nsvc, LOGL_INFO, "Tx SNS-CONFIG-ACK (cause=%s)\n",
756 cause ? gprs_ns2_cause_str(*cause) : "NULL");
757 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100758 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200759}
760
761
762/*! Encode + transmit a SNS-SIZE as per Section 9.3.7.
763 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE
764 * \param[in] reset_flag Whether or not to add a RESET flag
765 * \param[in] max_nr_nsvc Maximum number of NS-VCs
766 * \param[in] ip4_ep_nr Number of IPv4 endpoints (< 0 will omit the TLV)
767 * \param[in] ip6_ep_nr Number of IPv6 endpoints (< 0 will omit the TLV)
768 * \returns 0 on success; negative in case of error */
769int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_nsvc,
770 int ip4_ep_nr, int ip6_ep_nr)
771{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100772 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200773 struct gprs_ns_hdr *nsh;
774 uint16_t nsei;
775
776 if (!nsvc)
777 return -1;
778
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100779 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200780
Daniel Willmann751977b2020-12-02 18:59:44 +0100781 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200782 log_set_context(LOG_CTX_GB_NSVC, nsvc);
783 if (!msg)
784 return -ENOMEM;
785
786 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100787 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200788 msgb_free(msg);
789 return -EIO;
790 }
791
792 nsei = osmo_htons(nsvc->nse->nsei);
793
794 msg->l2h = msgb_put(msg, sizeof(*nsh));
795 nsh = (struct gprs_ns_hdr *) msg->l2h;
796
797 nsh->pdu_type = SNS_PDUT_SIZE;
798
799 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
800 msgb_tv_put(msg, NS_IE_RESET_FLAG, reset_flag ? 0x01 : 0x00);
801 msgb_tv16_put(msg, NS_IE_MAX_NR_NSVC, max_nr_nsvc);
802 if (ip4_ep_nr >= 0)
803 msgb_tv16_put(msg, NS_IE_IPv4_EP_NR, ip4_ep_nr);
804 if (ip6_ep_nr >= 0)
805 msgb_tv16_put(msg, NS_IE_IPv6_EP_NR, ip6_ep_nr);
806
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100807 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
Alexander Couzens6ba77a32021-07-06 11:34:04 +0200808 " (reset=%u, max_nr_nsvc=%u, num_ip4=%d, num_ip6=%d)\n",
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100809 reset_flag, max_nr_nsvc, ip4_ep_nr, ip6_ep_nr);
Harald Welte5a5bf722021-01-30 21:49:28 +0100810 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200811}
812
813/*! Encode + Transmit a SNS-SIZE-ACK as per Section 9.3.8.
814 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE-ACK
815 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
816 * \returns 0 on success; negative in case of error */
817int ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
818{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100819 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200820 struct gprs_ns_hdr *nsh;
821 uint16_t nsei;
822
Daniel Willmann751977b2020-12-02 18:59:44 +0100823 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200824 log_set_context(LOG_CTX_GB_NSVC, nsvc);
825 if (!msg)
826 return -ENOMEM;
827
828 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100829 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200830 msgb_free(msg);
831 return -EIO;
832 }
833
834 nsei = osmo_htons(nsvc->nse->nsei);
835
836 msg->l2h = msgb_put(msg, sizeof(*nsh));
837 nsh = (struct gprs_ns_hdr *) msg->l2h;
838
839 nsh->pdu_type = SNS_PDUT_SIZE_ACK;
840
841 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
842 if (cause)
843 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
844
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100845 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n",
846 cause ? gprs_ns2_cause_str(*cause) : "NULL");
Harald Welte5a5bf722021-01-30 21:49:28 +0100847 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200848}