blob: 93341bbd0d02d6f814f6682db490f72f3313b24b [file] [log] [blame]
Alexander Couzens6a161492020-07-12 13:45:50 +02001/*! \file gprs_ns2_message.c
2 * NS-over-FR-over-GRE implementation.
3 * GPRS Networks Service (NS) messages on the Gb interface.
4 * 3GPP TS 08.16 version 8.0.1 Release 1999 / ETSI TS 101 299 V8.0.1 (2002-05)
5 * as well as its successor 3GPP TS 48.016 */
6
7/* (C) 2020 sysmocom - s.f.m.c. GmbH
8 * Author: Alexander Couzens <lynxis@fe80.eu>
9 *
10 * All Rights Reserved
11 *
12 * SPDX-License-Identifier: GPL-2.0+
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program. If not, see <http://www.gnu.org/licenses/>.
26 *
27 */
28
29#include <errno.h>
30
31#include <osmocom/core/byteswap.h>
32#include <osmocom/core/rate_ctr.h>
33#include <osmocom/core/stat_item.h>
34#include <osmocom/core/stats.h>
35#include <osmocom/gsm/tlv.h>
36#include <osmocom/gprs/gprs_msgb.h>
37#include <osmocom/gprs/gprs_ns2.h>
38#include <osmocom/gprs/protocol/gsm_08_16.h>
39
40#include "gprs_ns2_internal.h"
41
42#define ERR_IF_NSVC_USES_SNS(nsvc, reason) \
43 do { \
44 if (!nsvc->nse->bss_sns_fi) \
45 break; \
Harald Weltef2949742021-01-20 14:54:14 +010046 LOGNSVC(nsvc, LOGL_DEBUG, "invalid packet %s with SNS\n", reason); \
Alexander Couzens6a161492020-07-12 13:45:50 +020047 } while (0)
48
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010049static int ns2_validate_reset(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +020050{
Harald Welte798efea2020-12-03 16:01:02 +010051 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1) ||
52 !TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_NSEI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020053 *cause = NS_CAUSE_MISSING_ESSENT_IE;
54 return -1;
55 }
56
57 return 0;
58}
59
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010060static int ns2_validate_reset_ack(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +020061{
Harald Welte798efea2020-12-03 16:01:02 +010062 if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_NSEI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020063 *cause = NS_CAUSE_MISSING_ESSENT_IE;
64 return -1;
65 }
66
67 return 0;
68}
69
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010070static int ns2_validate_block(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +020071{
Harald Welte798efea2020-12-03 16:01:02 +010072 if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2) || !TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020073 *cause = NS_CAUSE_MISSING_ESSENT_IE;
74 return -1;
75 }
76
77 return 0;
78}
79
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010080static int ns2_validate_block_ack(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +020081{
Harald Welte798efea2020-12-03 16:01:02 +010082 if (!TLVP_PRES_LEN(tp, NS_IE_VCI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020083 *cause = NS_CAUSE_MISSING_ESSENT_IE;
84 return -1;
85 }
86
87 return 0;
88}
89
Alexander Couzensf7e2cac2021-01-25 16:18:21 +010090static int ns2_validate_status(struct gprs_ns2_vc *nsvc, struct msgb *msg, struct tlv_parsed *tp, uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +020091{
92
Harald Welte798efea2020-12-03 16:01:02 +010093 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +020094 *cause = NS_CAUSE_MISSING_ESSENT_IE;
95 return -1;
96 }
97
98 uint8_t _cause = tlvp_val8(tp, NS_IE_VCI, 0);
99
100 switch (_cause) {
101 case NS_CAUSE_NSVC_BLOCKED:
102 case NS_CAUSE_NSVC_UNKNOWN:
Harald Welte798efea2020-12-03 16:01:02 +0100103 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200104 *cause = NS_CAUSE_MISSING_ESSENT_IE;
105 return -1;
106 }
107 break;
108 case NS_CAUSE_SEM_INCORR_PDU:
109 case NS_CAUSE_PDU_INCOMP_PSTATE:
110 case NS_CAUSE_PROTO_ERR_UNSPEC:
111 case NS_CAUSE_INVAL_ESSENT_IE:
112 case NS_CAUSE_MISSING_ESSENT_IE:
Harald Welte798efea2020-12-03 16:01:02 +0100113 if (!TLVP_PRES_LEN(tp, NS_IE_CAUSE, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200114 *cause = NS_CAUSE_MISSING_ESSENT_IE;
115 return -1;
116 }
117 break;
118 case NS_CAUSE_BVCI_UNKNOWN:
Harald Welte798efea2020-12-03 16:01:02 +0100119 if (!TLVP_PRES_LEN(tp, NS_IE_BVCI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200120 *cause = NS_CAUSE_MISSING_ESSENT_IE;
121 return -1;
122 }
123 break;
124 case NS_CAUSE_UNKN_IP_TEST_FAILED:
Harald Welte798efea2020-12-03 16:01:02 +0100125 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST) && !TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200126 *cause = NS_CAUSE_MISSING_ESSENT_IE;
127 return -1;
128 }
129 break;
130 }
131
132 return 0;
133}
134
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100135int ns2_validate(struct gprs_ns2_vc *nsvc,
136 uint8_t pdu_type,
137 struct msgb *msg,
138 struct tlv_parsed *tp,
139 uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +0200140{
141 switch (pdu_type) {
142 case NS_PDUT_RESET:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100143 return ns2_validate_reset(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200144 case NS_PDUT_RESET_ACK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100145 return ns2_validate_reset_ack(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200146 case NS_PDUT_BLOCK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100147 return ns2_validate_block(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200148 case NS_PDUT_BLOCK_ACK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100149 return ns2_validate_block_ack(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200150 case NS_PDUT_STATUS:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100151 return ns2_validate_status(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200152
153 /* following PDUs doesn't have any payloads */
154 case NS_PDUT_ALIVE:
155 case NS_PDUT_ALIVE_ACK:
156 case NS_PDUT_UNBLOCK:
157 case NS_PDUT_UNBLOCK_ACK:
158 if (msgb_l2len(msg) != sizeof(struct gprs_ns_hdr)) {
159 *cause = NS_CAUSE_PROTO_ERR_UNSPEC;
160 return -1;
161 }
162 break;
163 }
164
165 return 0;
166}
167
168
Harald Welte5a5bf722021-01-30 21:49:28 +0100169static int ns_vc_tx(struct gprs_ns2_vc *nsvc, struct msgb *msg)
170{
Harald Weltef22ae5a2021-01-30 22:01:28 +0100171 unsigned int bytes = msgb_length(msg);
172 int rc;
Harald Weltee5f55f72021-01-30 21:51:15 +0100173
Harald Weltef22ae5a2021-01-30 22:01:28 +0100174
175 rc = nsvc->bind->send_vc(nsvc, msg);
176 if (rc < 0) {
177 rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT_DROP]);
178 rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT_DROP], bytes);
179 } else {
180 rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_PKTS_OUT]);
181 rate_ctr_add(&nsvc->ctrg->ctr[NS_CTR_BYTES_OUT], bytes);
182 }
183
184 return rc;
Harald Welte5a5bf722021-01-30 21:49:28 +0100185}
186
Alexander Couzens6a161492020-07-12 13:45:50 +0200187/* transmit functions */
188static int ns2_tx_simple(struct gprs_ns2_vc *nsvc, uint8_t pdu_type)
189{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100190 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200191 struct gprs_ns_hdr *nsh;
192
Daniel Willmann751977b2020-12-02 18:59:44 +0100193 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200194 log_set_context(LOG_CTX_GB_NSVC, nsvc);
195
196 if (!msg)
197 return -ENOMEM;
198
199 msg->l2h = msgb_put(msg, sizeof(*nsh));
200 nsh = (struct gprs_ns_hdr *) msg->l2h;
Alexander Couzens6a161492020-07-12 13:45:50 +0200201 nsh->pdu_type = pdu_type;
202
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100203 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100204 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200205}
206
Harald Welte5bef2cc2020-09-18 22:33:24 +0200207/*! Transmit a NS-BLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200208 * \param[in] vc NS-VC on which the NS-BLOCK is to be transmitted
209 * \param[in] cause Numeric NS Cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200210 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200211int ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause)
212{
213 struct msgb *msg;
214 struct gprs_ns_hdr *nsh;
215 uint16_t nsvci = osmo_htons(nsvc->nsvci);
216
Daniel Willmann751977b2020-12-02 18:59:44 +0100217 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200218 log_set_context(LOG_CTX_GB_NSVC, nsvc);
219
220 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK");
221
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100222 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200223 if (!msg)
224 return -ENOMEM;
225
Alexander Couzens6a161492020-07-12 13:45:50 +0200226 rate_ctr_inc(&nsvc->ctrg->ctr[NS_CTR_BLOCKED]);
227
228 msg->l2h = msgb_put(msg, sizeof(*nsh));
229 nsh = (struct gprs_ns_hdr *) msg->l2h;
230 nsh->pdu_type = NS_PDUT_BLOCK;
231
232 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
233 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
234
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100235 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 +0100236 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200237}
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
Alexander Couzens6a161492020-07-12 13:45:50 +0200257 msg->l2h = msgb_put(msg, sizeof(*nsh));
258 nsh = (struct gprs_ns_hdr *) msg->l2h;
259 nsh->pdu_type = NS_PDUT_BLOCK_ACK;
260
261 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
262
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100263 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100264 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200265}
266
Harald Welte5bef2cc2020-09-18 22:33:24 +0200267/*! Transmit a NS-RESET on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200268 * \param[in] nsvc NS-VC used for transmission
269 * \paam[in] cause Numeric NS cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200270 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200271int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause)
272{
273 struct msgb *msg;
274 struct gprs_ns_hdr *nsh;
275 uint16_t nsvci = osmo_htons(nsvc->nsvci);
276 uint16_t nsei = osmo_htons(nsvc->nse->nsei);
277
Daniel Willmann751977b2020-12-02 18:59:44 +0100278 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200279 log_set_context(LOG_CTX_GB_NSVC, nsvc);
280
281 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET");
282
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100283 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200284 if (!msg)
285 return -ENOMEM;
286
Alexander Couzens6a161492020-07-12 13:45:50 +0200287 msg->l2h = msgb_put(msg, sizeof(*nsh));
288 nsh = (struct gprs_ns_hdr *) msg->l2h;
289 nsh->pdu_type = NS_PDUT_RESET;
290
291 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
292 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
293 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei);
294
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100295 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 +0100296 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200297}
298
Harald Welte5bef2cc2020-09-18 22:33:24 +0200299/*! Transmit a NS-RESET-ACK on a given NS-VC.
300 * \param[in] nsvc NS-VC used for transmission
301 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200302int ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc)
303{
304 struct msgb *msg;
305 struct gprs_ns_hdr *nsh;
306 uint16_t nsvci, nsei;
307
Harald Welte5bef2cc2020-09-18 22:33:24 +0200308 /* Section 9.2.6 */
Daniel Willmann751977b2020-12-02 18:59:44 +0100309 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200310 log_set_context(LOG_CTX_GB_NSVC, nsvc);
311
312 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET ACK");
313
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100314 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200315 if (!msg)
316 return -ENOMEM;
317
318 nsvci = osmo_htons(nsvc->nsvci);
319 nsei = osmo_htons(nsvc->nse->nsei);
320
321 msg->l2h = msgb_put(msg, sizeof(*nsh));
322 nsh = (struct gprs_ns_hdr *) msg->l2h;
323
324 nsh->pdu_type = NS_PDUT_RESET_ACK;
325
Alexander Couzens6a161492020-07-12 13:45:50 +0200326 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
327 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
328
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100329 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100330 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200331}
332
Harald Welte5bef2cc2020-09-18 22:33:24 +0200333/*! Transmit a NS-UNBLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200334 * \param[in] nsvc NS-VC on which the NS-UNBLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200335 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200336int ns2_tx_unblock(struct gprs_ns2_vc *nsvc)
337{
Daniel Willmann751977b2020-12-02 18:59:44 +0100338 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200339 log_set_context(LOG_CTX_GB_NSVC, nsvc);
340
341 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK");
342
Alexander Couzens6a161492020-07-12 13:45:50 +0200343 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK);
344}
345
346
Harald Welte5bef2cc2020-09-18 22:33:24 +0200347/*! Transmit a NS-UNBLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200348 * \param[in] nsvc NS-VC on which the NS-UNBLOCK-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200349 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200350int ns2_tx_unblock_ack(struct gprs_ns2_vc *nsvc)
351{
Daniel Willmann751977b2020-12-02 18:59:44 +0100352 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200353 log_set_context(LOG_CTX_GB_NSVC, nsvc);
354
355 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK ACK");
356
Alexander Couzens6a161492020-07-12 13:45:50 +0200357 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
358}
359
Harald Welte5bef2cc2020-09-18 22:33:24 +0200360/*! Transmit a NS-ALIVE on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200361 * \param[in] nsvc NS-VC on which the NS-ALIVE is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200362 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200363int ns2_tx_alive(struct gprs_ns2_vc *nsvc)
364{
Daniel Willmann751977b2020-12-02 18:59:44 +0100365 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200366 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200367
368 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE);
369}
370
Harald Welte5bef2cc2020-09-18 22:33:24 +0200371/*! Transmit a NS-ALIVE-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200372 * \param[in] nsvc NS-VC on which the NS-ALIVE-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200373 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200374int ns2_tx_alive_ack(struct gprs_ns2_vc *nsvc)
375{
Daniel Willmann751977b2020-12-02 18:59:44 +0100376 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200377 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200378
379 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE_ACK);
380}
381
Harald Welte5bef2cc2020-09-18 22:33:24 +0200382/*! Transmit NS-UNITDATA on a given NS-VC.
383 * \param[in] nsvc NS-VC on which the NS-UNITDATA is to be transmitted
384 * \param[in] bvci BVCI to encode in NS-UNITDATA header
385 * \param[in] sducontrol SDU control octet of NS header
386 * \param[in] msg message buffer containing payload
387 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200388int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
389 uint16_t bvci, uint8_t sducontrol,
390 struct msgb *msg)
391{
392 struct gprs_ns_hdr *nsh;
393
Daniel Willmann751977b2020-12-02 18:59:44 +0100394 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200395 log_set_context(LOG_CTX_GB_NSVC, nsvc);
396
397 msg->l2h = msgb_push(msg, sizeof(*nsh) + 3);
398 nsh = (struct gprs_ns_hdr *) msg->l2h;
399 if (!nsh) {
Harald Weltef2949742021-01-20 14:54:14 +0100400 LOGNSVC(nsvc, LOGL_ERROR, "Not enough headroom for NS header\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200401 msgb_free(msg);
402 return -EIO;
403 }
404
405 nsh->pdu_type = NS_PDUT_UNITDATA;
406 nsh->data[0] = sducontrol;
407 nsh->data[1] = bvci >> 8;
408 nsh->data[2] = bvci & 0xff;
409
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100410 LOG_NS_DATA(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, "\n");
Harald Welte5a5bf722021-01-30 21:49:28 +0100411 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200412}
413
Harald Welte5bef2cc2020-09-18 22:33:24 +0200414/*! Transmit a NS-STATUS on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200415 * \param[in] nsvc NS-VC to be used for transmission
416 * \param[in] cause Numeric NS cause value
417 * \param[in] bvci BVCI to be reset within NSVC
Harald Welte5bef2cc2020-09-18 22:33:24 +0200418 * \param[in] orig_msg message causing the STATUS
419 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200420int ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,
421 uint16_t bvci, struct msgb *orig_msg)
422{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100423 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200424 struct gprs_ns_hdr *nsh;
425 uint16_t nsvci = osmo_htons(nsvc->nsvci);
Alexander Couzenscf1fa632021-02-15 04:51:14 +0100426 unsigned int orig_len, max_orig_len;
Alexander Couzens6a161492020-07-12 13:45:50 +0200427
Daniel Willmann751977b2020-12-02 18:59:44 +0100428 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200429 log_set_context(LOG_CTX_GB_NSVC, nsvc);
430
431 bvci = osmo_htons(bvci);
432
433 if (!msg)
434 return -ENOMEM;
435
Alexander Couzens6a161492020-07-12 13:45:50 +0200436 msg->l2h = msgb_put(msg, sizeof(*nsh));
437 nsh = (struct gprs_ns_hdr *) msg->l2h;
438 nsh->pdu_type = NS_PDUT_STATUS;
439
440 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
441
Alexander Couzens6a161492020-07-12 13:45:50 +0200442 switch (cause) {
Alexander Couzensce646c22021-02-15 04:55:08 +0100443 case NS_CAUSE_NSVC_BLOCKED:
444 case NS_CAUSE_NSVC_UNKNOWN:
445 /* Section 9.2.7.1: Static conditions for NS-VCI */
446 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
447 break;
Alexander Couzens6a161492020-07-12 13:45:50 +0200448 case NS_CAUSE_SEM_INCORR_PDU:
449 case NS_CAUSE_PDU_INCOMP_PSTATE:
450 case NS_CAUSE_PROTO_ERR_UNSPEC:
451 case NS_CAUSE_INVAL_ESSENT_IE:
452 case NS_CAUSE_MISSING_ESSENT_IE:
Alexander Couzensce646c22021-02-15 04:55:08 +0100453 /* Section 9.2.7.2: Static conditions for NS PDU */
Alexander Couzenscf1fa632021-02-15 04:51:14 +0100454 /* ensure the PDU doesn't exceed the MTU */
455 orig_len = msgb_l2len(orig_msg);
456 max_orig_len = msgb_length(msg) + TVLV_GROSS_LEN(orig_len);
457 if (max_orig_len > nsvc->bind->mtu)
458 orig_len -= max_orig_len - nsvc->bind->mtu;
459 msgb_tvlv_put(msg, NS_IE_PDU, orig_len, orig_msg->l2h);
Alexander Couzens6a161492020-07-12 13:45:50 +0200460 break;
Alexander Couzensce646c22021-02-15 04:55:08 +0100461 case NS_CAUSE_BVCI_UNKNOWN:
462 /* Section 9.2.7.3: Static conditions for BVCI */
463 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci);
464 break;
465
Alexander Couzens6a161492020-07-12 13:45:50 +0200466 default:
467 break;
468 }
469
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100470 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 +0100471 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200472}
473
Alexander Couzens27a55922021-02-27 01:08:35 +0100474/*! Encode + Transmit a SNS-ADD/SNS-CHANGE-WEIGHT as per Section 9.3.2/9.3.3.
475 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
476 * \param[in] pdu The PDU type to send out
477 * \param[in] trans_id The transaction id
478 * \param[in] ip4_elems Array of IPv4 Elements
479 * \param[in] num_ip4_elems number of ip4_elems
480 * \param[in] ip6_elems Array of IPv6 Elements
481 * \param[in] num_ip6_elems number of ip6_elems
482 * \returns 0 on success; negative in case of error */
483static int ns2_tx_sns_procedure(struct gprs_ns2_vc *nsvc,
484 enum ns_pdu_type pdu,
485 uint8_t trans_id,
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{
491 struct msgb *msg;
492 struct gprs_ns_hdr *nsh;
493 uint16_t nsei;
494
495 if (!nsvc)
496 return -EINVAL;
497
498 if (!ip4_elems && !ip6_elems)
499 return -EINVAL;
500
501 msg = ns2_msgb_alloc();
502
503 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
504 log_set_context(LOG_CTX_GB_NSVC, nsvc);
505 if (!msg)
506 return -ENOMEM;
507
508 if (!nsvc->nse->bss_sns_fi) {
509 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
510 msgb_free(msg);
511 return -EIO;
512 }
513
514 nsei = osmo_htons(nsvc->nse->nsei);
515
516 msg->l2h = msgb_put(msg, sizeof(*nsh));
517 nsh = (struct gprs_ns_hdr *) msg->l2h;
518 nsh->pdu_type = pdu;
519 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
520 msgb_v_put(msg, trans_id);
521
522 /* List of IP4 Elements 10.3.2c */
523 if (ip4_elems) {
524 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
525 (const uint8_t *)ip4_elems);
526 } else if (ip6_elems) {
527 /* List of IP6 elements 10.3.2d */
528 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
529 (const uint8_t *)ip6_elems);
530 }
531
532 return ns_vc_tx(nsvc, msg);
533}
534
535/*! Encode + Transmit a SNS-ADD as per Section 9.3.2.
536 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
537 * \param[in] trans_id The transaction id
538 * \param[in] ip4_elems Array of IPv4 Elements
539 * \param[in] num_ip4_elems number of ip4_elems
540 * \param[in] ip6_elems Array of IPv6 Elements
541 * \param[in] num_ip6_elems number of ip6_elems
542 * \returns 0 on success; negative in case of error */
543int ns2_tx_sns_add(struct gprs_ns2_vc *nsvc,
544 uint8_t trans_id,
545 const struct gprs_ns_ie_ip4_elem *ip4_elems,
546 unsigned int num_ip4_elems,
547 const struct gprs_ns_ie_ip6_elem *ip6_elems,
548 unsigned int num_ip6_elems)
549{
550 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_ADD, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
551}
552
553/*! Encode + Transmit a SNS-CHANGE-WEIGHT as per Section 9.3.3.
554 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
555 * \param[in] trans_id The transaction id
556 * \param[in] ip4_elems Array of IPv4 Elements
557 * \param[in] num_ip4_elems number of ip4_elems
558 * \param[in] ip6_elems Array of IPv6 Elements
559 * \param[in] num_ip6_elems number of ip6_elems
560 * \returns 0 on success; negative in case of error */
561int ns2_tx_sns_change_weight(struct gprs_ns2_vc *nsvc,
562 uint8_t trans_id,
563 const struct gprs_ns_ie_ip4_elem *ip4_elems,
564 unsigned int num_ip4_elems,
565 const struct gprs_ns_ie_ip6_elem *ip6_elems,
566 unsigned int num_ip6_elems)
567{
568 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_CHANGE_WEIGHT, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
569}
570
571/*! Encode + Transmit a SNS-DEL as per Section 9.3.6.
572 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
573 * \param[in] trans_id The transaction id
574 * \param[in] ip4_elems Array of IPv4 Elements
575 * \param[in] num_ip4_elems number of ip4_elems
576 * \param[in] ip6_elems Array of IPv6 Elements
577 * \param[in] num_ip6_elems number of ip6_elems
578 * \returns 0 on success; negative in case of error */
579int ns2_tx_sns_del(struct gprs_ns2_vc *nsvc,
580 uint8_t trans_id,
581 const struct gprs_ns_ie_ip4_elem *ip4_elems,
582 unsigned int num_ip4_elems,
583 const struct gprs_ns_ie_ip6_elem *ip6_elems,
584 unsigned int num_ip6_elems)
585{
586 /* TODO: IP Address field */
587 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_DELETE, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
588}
589
Alexander Couzens6a161492020-07-12 13:45:50 +0200590
591/*! Encode + Transmit a SNS-ACK as per Section 9.3.1.
592 * \param[in] nsvc NS-VC through which to transmit the ACK
593 * \param[in] trans_id Transaction ID which to acknowledge
594 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
595 * \param[in] ip4_elems Array of IPv4 Elements
596 * \param[in] num_ip4_elems number of ip4_elems
597 * \returns 0 on success; negative in case of error */
598int ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,
599 const struct gprs_ns_ie_ip4_elem *ip4_elems,
600 unsigned int num_ip4_elems,
601 const struct gprs_ns_ie_ip6_elem *ip6_elems,
602 unsigned int num_ip6_elems)
603{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100604 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200605 struct gprs_ns_hdr *nsh;
606 uint16_t nsei;
607
608 if (!nsvc)
609 return -1;
610
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100611 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200612
Daniel Willmann751977b2020-12-02 18:59:44 +0100613 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200614 log_set_context(LOG_CTX_GB_NSVC, nsvc);
615 if (!msg)
616 return -ENOMEM;
617
618 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100619 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200620 msgb_free(msg);
621 return -EIO;
622 }
623
Harald Welte22274df2021-03-04 07:59:16 +0100624
Alexander Couzens6a161492020-07-12 13:45:50 +0200625 nsei = osmo_htons(nsvc->nse->nsei);
626
627 msg->l2h = msgb_put(msg, sizeof(*nsh));
628 nsh = (struct gprs_ns_hdr *) msg->l2h;
629
630 nsh->pdu_type = SNS_PDUT_ACK;
631 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
632 msgb_v_put(msg, trans_id);
633 if (cause)
634 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
635 if (ip4_elems) {
636 /* List of IP4 Elements 10.3.2c */
637 msgb_tvlv_put(msg, NS_IE_IPv4_LIST,
638 num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
639 (const uint8_t *)ip4_elems);
640 }
641 if (ip6_elems) {
642 /* List of IP6 elements 10.3.2d */
643 msgb_tvlv_put(msg, NS_IE_IPv6_LIST,
644 num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
645 (const uint8_t *)ip6_elems);
646 }
647
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100648 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
649 " (trans_id=%u, cause=%s, num_ip4=%u, num_ip6=%u)\n",
650 trans_id, cause ? gprs_ns2_cause_str(*cause) : "NULL", num_ip4_elems, num_ip6_elems);
Harald Welte5a5bf722021-01-30 21:49:28 +0100651 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200652}
653
654/*! Encode + Transmit a SNS-CONFIG as per Section 9.3.4.
655 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
656 * \param[in] end_flag Whether or not this is the last SNS-CONFIG
657 * \param[in] ip4_elems Array of IPv4 Elements
658 * \param[in] num_ip4_elems number of ip4_elems
659 * \returns 0 on success; negative in case of error */
660int ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,
661 const struct gprs_ns_ie_ip4_elem *ip4_elems,
662 unsigned int num_ip4_elems,
663 const struct gprs_ns_ie_ip6_elem *ip6_elems,
664 unsigned int num_ip6_elems)
665{
666 struct msgb *msg;
667 struct gprs_ns_hdr *nsh;
668 uint16_t nsei;
669
670 if (!nsvc)
671 return -1;
672
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100673 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200674
Daniel Willmann751977b2020-12-02 18:59:44 +0100675 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200676 log_set_context(LOG_CTX_GB_NSVC, nsvc);
677 if (!msg)
678 return -ENOMEM;
679
680 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100681 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200682 msgb_free(msg);
683 return -EIO;
684 }
685
686 nsei = osmo_htons(nsvc->nse->nsei);
687
688 msg->l2h = msgb_put(msg, sizeof(*nsh));
689 nsh = (struct gprs_ns_hdr *) msg->l2h;
690
691 nsh->pdu_type = SNS_PDUT_CONFIG;
692
693 msgb_v_put(msg, end_flag ? 0x01 : 0x00);
694 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
695
696 /* List of IP4 Elements 10.3.2c */
697 if (ip4_elems) {
698 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
699 (const uint8_t *)ip4_elems);
700 } else if (ip6_elems) {
701 /* List of IP6 elements 10.3.2d */
702 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
703 (const uint8_t *)ip6_elems);
704 }
705
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100706 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
707 " (end_flag=%u, num_ip4=%u, num_ip6=%u)\n",
708 end_flag, num_ip4_elems, num_ip6_elems);
Harald Welte5a5bf722021-01-30 21:49:28 +0100709 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200710}
711
712/*! Encode + Transmit a SNS-CONFIG-ACK as per Section 9.3.5.
713 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG-ACK
714 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
715 * \returns 0 on success; negative in case of error */
716int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
717{
718 struct msgb *msg;
719 struct gprs_ns_hdr *nsh;
720 uint16_t nsei;
721
722 if (!nsvc)
723 return -1;
724
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100725 msg = ns2_msgb_alloc();
Daniel Willmann751977b2020-12-02 18:59:44 +0100726 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200727 log_set_context(LOG_CTX_GB_NSVC, nsvc);
728 if (!msg)
729 return -ENOMEM;
730
731 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100732 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200733 msgb_free(msg);
734 return -EIO;
735 }
736
737 nsei = osmo_htons(nsvc->nse->nsei);
738
739 msg->l2h = msgb_put(msg, sizeof(*nsh));
740 nsh = (struct gprs_ns_hdr *) msg->l2h;
741
742 nsh->pdu_type = SNS_PDUT_CONFIG_ACK;
743
744 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
745 if (cause)
746 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
747
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100748 LOGNSVC(nsvc, LOGL_INFO, "Tx SNS-CONFIG-ACK (cause=%s)\n",
749 cause ? gprs_ns2_cause_str(*cause) : "NULL");
750 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100751 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200752}
753
754
755/*! Encode + transmit a SNS-SIZE as per Section 9.3.7.
756 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE
757 * \param[in] reset_flag Whether or not to add a RESET flag
758 * \param[in] max_nr_nsvc Maximum number of NS-VCs
759 * \param[in] ip4_ep_nr Number of IPv4 endpoints (< 0 will omit the TLV)
760 * \param[in] ip6_ep_nr Number of IPv6 endpoints (< 0 will omit the TLV)
761 * \returns 0 on success; negative in case of error */
762int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_nsvc,
763 int ip4_ep_nr, int ip6_ep_nr)
764{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100765 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200766 struct gprs_ns_hdr *nsh;
767 uint16_t nsei;
768
769 if (!nsvc)
770 return -1;
771
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100772 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200773
Daniel Willmann751977b2020-12-02 18:59:44 +0100774 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200775 log_set_context(LOG_CTX_GB_NSVC, nsvc);
776 if (!msg)
777 return -ENOMEM;
778
779 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100780 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200781 msgb_free(msg);
782 return -EIO;
783 }
784
785 nsei = osmo_htons(nsvc->nse->nsei);
786
787 msg->l2h = msgb_put(msg, sizeof(*nsh));
788 nsh = (struct gprs_ns_hdr *) msg->l2h;
789
790 nsh->pdu_type = SNS_PDUT_SIZE;
791
792 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
793 msgb_tv_put(msg, NS_IE_RESET_FLAG, reset_flag ? 0x01 : 0x00);
794 msgb_tv16_put(msg, NS_IE_MAX_NR_NSVC, max_nr_nsvc);
795 if (ip4_ep_nr >= 0)
796 msgb_tv16_put(msg, NS_IE_IPv4_EP_NR, ip4_ep_nr);
797 if (ip6_ep_nr >= 0)
798 msgb_tv16_put(msg, NS_IE_IPv6_EP_NR, ip6_ep_nr);
799
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100800 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
801 " (reset=%u, max_nr_nsvc=%u, num_ip4=%u, num_ip6=%u)\n",
802 reset_flag, max_nr_nsvc, ip4_ep_nr, ip6_ep_nr);
Harald Welte5a5bf722021-01-30 21:49:28 +0100803 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200804}
805
806/*! Encode + Transmit a SNS-SIZE-ACK as per Section 9.3.8.
807 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE-ACK
808 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
809 * \returns 0 on success; negative in case of error */
810int ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
811{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100812 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200813 struct gprs_ns_hdr *nsh;
814 uint16_t nsei;
815
Daniel Willmann751977b2020-12-02 18:59:44 +0100816 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200817 log_set_context(LOG_CTX_GB_NSVC, nsvc);
818 if (!msg)
819 return -ENOMEM;
820
821 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100822 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200823 msgb_free(msg);
824 return -EIO;
825 }
826
827 nsei = osmo_htons(nsvc->nse->nsei);
828
829 msg->l2h = msgb_put(msg, sizeof(*nsh));
830 nsh = (struct gprs_ns_hdr *) msg->l2h;
831
832 nsh->pdu_type = SNS_PDUT_SIZE_ACK;
833
834 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
835 if (cause)
836 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
837
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100838 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n",
839 cause ? gprs_ns2_cause_str(*cause) : "NULL");
Harald Welte5a5bf722021-01-30 21:49:28 +0100840 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200841}