blob: 5e3e025d8e0ab10621934463ca754676f3526418 [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 }
106 break;
107 case NS_CAUSE_SEM_INCORR_PDU:
108 case NS_CAUSE_PDU_INCOMP_PSTATE:
109 case NS_CAUSE_PROTO_ERR_UNSPEC:
110 case NS_CAUSE_INVAL_ESSENT_IE:
111 case NS_CAUSE_MISSING_ESSENT_IE:
Alexander Couzenseec4f602021-09-06 18:17:15 +0200112 if (!TLVP_PRES_LEN(tp, NS_IE_PDU, 1)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200113 *cause = NS_CAUSE_MISSING_ESSENT_IE;
114 return -1;
115 }
116 break;
117 case NS_CAUSE_BVCI_UNKNOWN:
Harald Welte798efea2020-12-03 16:01:02 +0100118 if (!TLVP_PRES_LEN(tp, NS_IE_BVCI, 2)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200119 *cause = NS_CAUSE_MISSING_ESSENT_IE;
120 return -1;
121 }
122 break;
123 case NS_CAUSE_UNKN_IP_TEST_FAILED:
Harald Welte798efea2020-12-03 16:01:02 +0100124 if (!TLVP_PRESENT(tp, NS_IE_IPv4_LIST) && !TLVP_PRESENT(tp, NS_IE_IPv6_LIST)) {
Alexander Couzens6a161492020-07-12 13:45:50 +0200125 *cause = NS_CAUSE_MISSING_ESSENT_IE;
126 return -1;
127 }
128 break;
129 }
130
131 return 0;
132}
133
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100134int ns2_validate(struct gprs_ns2_vc *nsvc,
135 uint8_t pdu_type,
136 struct msgb *msg,
137 struct tlv_parsed *tp,
138 uint8_t *cause)
Alexander Couzens6a161492020-07-12 13:45:50 +0200139{
140 switch (pdu_type) {
141 case NS_PDUT_RESET:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100142 return ns2_validate_reset(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200143 case NS_PDUT_RESET_ACK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100144 return ns2_validate_reset_ack(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200145 case NS_PDUT_BLOCK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100146 return ns2_validate_block(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200147 case NS_PDUT_BLOCK_ACK:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100148 return ns2_validate_block_ack(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200149 case NS_PDUT_STATUS:
Alexander Couzensf7e2cac2021-01-25 16:18:21 +0100150 return ns2_validate_status(nsvc, msg, tp, cause);
Alexander Couzens6a161492020-07-12 13:45:50 +0200151
152 /* following PDUs doesn't have any payloads */
153 case NS_PDUT_ALIVE:
154 case NS_PDUT_ALIVE_ACK:
155 case NS_PDUT_UNBLOCK:
156 case NS_PDUT_UNBLOCK_ACK:
157 if (msgb_l2len(msg) != sizeof(struct gprs_ns_hdr)) {
158 *cause = NS_CAUSE_PROTO_ERR_UNSPEC;
159 return -1;
160 }
161 break;
162 }
163
164 return 0;
165}
166
167
Harald Welte5a5bf722021-01-30 21:49:28 +0100168static int ns_vc_tx(struct gprs_ns2_vc *nsvc, struct msgb *msg)
169{
Harald Weltef22ae5a2021-01-30 22:01:28 +0100170 unsigned int bytes = msgb_length(msg);
171 int rc;
Harald Weltee5f55f72021-01-30 21:51:15 +0100172
Harald Weltef22ae5a2021-01-30 22:01:28 +0100173
174 rc = nsvc->bind->send_vc(nsvc, msg);
175 if (rc < 0) {
Daniel Willmannefa64f92021-07-09 20:35:00 +0200176 RATE_CTR_INC_NS(nsvc, NS_CTR_PKTS_OUT_DROP);
177 RATE_CTR_ADD_NS(nsvc, NS_CTR_BYTES_OUT_DROP, bytes);
Harald Weltef22ae5a2021-01-30 22:01:28 +0100178 } else {
Daniel Willmannefa64f92021-07-09 20:35:00 +0200179 RATE_CTR_INC_NS(nsvc, NS_CTR_PKTS_OUT);
180 RATE_CTR_ADD_NS(nsvc, NS_CTR_BYTES_OUT, bytes);
Harald Weltef22ae5a2021-01-30 22:01:28 +0100181 }
182
183 return rc;
Harald Welte5a5bf722021-01-30 21:49:28 +0100184}
185
Alexander Couzens6a161492020-07-12 13:45:50 +0200186/* transmit functions */
187static int ns2_tx_simple(struct gprs_ns2_vc *nsvc, uint8_t pdu_type)
188{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100189 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200190 struct gprs_ns_hdr *nsh;
191
Daniel Willmann751977b2020-12-02 18:59:44 +0100192 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200193 log_set_context(LOG_CTX_GB_NSVC, nsvc);
194
195 if (!msg)
196 return -ENOMEM;
197
198 msg->l2h = msgb_put(msg, sizeof(*nsh));
199 nsh = (struct gprs_ns_hdr *) msg->l2h;
Alexander Couzens6a161492020-07-12 13:45:50 +0200200 nsh->pdu_type = pdu_type;
201
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100202 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100203 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200204}
205
Harald Welte5bef2cc2020-09-18 22:33:24 +0200206/*! Transmit a NS-BLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200207 * \param[in] vc NS-VC on which the NS-BLOCK is to be transmitted
208 * \param[in] cause Numeric NS Cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200209 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200210int ns2_tx_block(struct gprs_ns2_vc *nsvc, uint8_t cause)
211{
212 struct msgb *msg;
213 struct gprs_ns_hdr *nsh;
214 uint16_t nsvci = osmo_htons(nsvc->nsvci);
215
Daniel Willmann751977b2020-12-02 18:59:44 +0100216 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200217 log_set_context(LOG_CTX_GB_NSVC, nsvc);
218
219 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK");
220
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100221 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200222 if (!msg)
223 return -ENOMEM;
224
Pau Espin Pedrol7b894a72021-06-04 18:17:12 +0200225 rate_ctr_inc(rate_ctr_group_get_ctr(nsvc->ctrg, NS_CTR_BLOCKED));
Alexander Couzens6a161492020-07-12 13:45:50 +0200226
227 msg->l2h = msgb_put(msg, sizeof(*nsh));
228 nsh = (struct gprs_ns_hdr *) msg->l2h;
229 nsh->pdu_type = NS_PDUT_BLOCK;
230
231 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
232 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
233
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100234 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 +0100235 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200236}
237
Harald Welte5bef2cc2020-09-18 22:33:24 +0200238/*! Transmit a NS-BLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200239 * \param[in] nsvc NS-VC on which the NS-BLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200240 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200241int ns2_tx_block_ack(struct gprs_ns2_vc *nsvc)
242{
243 struct msgb *msg;
244 struct gprs_ns_hdr *nsh;
245 uint16_t nsvci = osmo_htons(nsvc->nsvci);
246
Daniel Willmann751977b2020-12-02 18:59:44 +0100247 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200248 log_set_context(LOG_CTX_GB_NSVC, nsvc);
249
250 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS BLOCK ACK");
251
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100252 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200253 if (!msg)
254 return -ENOMEM;
255
Alexander Couzens6a161492020-07-12 13:45:50 +0200256 msg->l2h = msgb_put(msg, sizeof(*nsh));
257 nsh = (struct gprs_ns_hdr *) msg->l2h;
258 nsh->pdu_type = NS_PDUT_BLOCK_ACK;
259
260 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
261
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100262 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100263 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200264}
265
Harald Welte5bef2cc2020-09-18 22:33:24 +0200266/*! Transmit a NS-RESET on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200267 * \param[in] nsvc NS-VC used for transmission
268 * \paam[in] cause Numeric NS cause value
Harald Welte5bef2cc2020-09-18 22:33:24 +0200269 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200270int ns2_tx_reset(struct gprs_ns2_vc *nsvc, uint8_t cause)
271{
272 struct msgb *msg;
273 struct gprs_ns_hdr *nsh;
274 uint16_t nsvci = osmo_htons(nsvc->nsvci);
275 uint16_t nsei = osmo_htons(nsvc->nse->nsei);
276
Daniel Willmann751977b2020-12-02 18:59:44 +0100277 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200278 log_set_context(LOG_CTX_GB_NSVC, nsvc);
279
280 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET");
281
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100282 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200283 if (!msg)
284 return -ENOMEM;
285
Alexander Couzens6a161492020-07-12 13:45:50 +0200286 msg->l2h = msgb_put(msg, sizeof(*nsh));
287 nsh = (struct gprs_ns_hdr *) msg->l2h;
288 nsh->pdu_type = NS_PDUT_RESET;
289
290 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
291 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *) &nsvci);
292 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *) &nsei);
293
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100294 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 +0100295 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200296}
297
Harald Welte5bef2cc2020-09-18 22:33:24 +0200298/*! Transmit a NS-RESET-ACK on a given NS-VC.
299 * \param[in] nsvc NS-VC used for transmission
300 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200301int ns2_tx_reset_ack(struct gprs_ns2_vc *nsvc)
302{
303 struct msgb *msg;
304 struct gprs_ns_hdr *nsh;
305 uint16_t nsvci, nsei;
306
Harald Welte5bef2cc2020-09-18 22:33:24 +0200307 /* Section 9.2.6 */
Daniel Willmann751977b2020-12-02 18:59:44 +0100308 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200309 log_set_context(LOG_CTX_GB_NSVC, nsvc);
310
311 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS RESET ACK");
312
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100313 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200314 if (!msg)
315 return -ENOMEM;
316
317 nsvci = osmo_htons(nsvc->nsvci);
318 nsei = osmo_htons(nsvc->nse->nsei);
319
320 msg->l2h = msgb_put(msg, sizeof(*nsh));
321 nsh = (struct gprs_ns_hdr *) msg->l2h;
322
323 nsh->pdu_type = NS_PDUT_RESET_ACK;
324
Alexander Couzens6a161492020-07-12 13:45:50 +0200325 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
326 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
327
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100328 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100329 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200330}
331
Harald Welte5bef2cc2020-09-18 22:33:24 +0200332/*! Transmit a NS-UNBLOCK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200333 * \param[in] nsvc NS-VC on which the NS-UNBLOCK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200334 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200335int ns2_tx_unblock(struct gprs_ns2_vc *nsvc)
336{
Daniel Willmann751977b2020-12-02 18:59:44 +0100337 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200338 log_set_context(LOG_CTX_GB_NSVC, nsvc);
339
340 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK");
341
Alexander Couzens6a161492020-07-12 13:45:50 +0200342 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK);
343}
344
345
Harald Welte5bef2cc2020-09-18 22:33:24 +0200346/*! Transmit a NS-UNBLOCK-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200347 * \param[in] nsvc NS-VC on which the NS-UNBLOCK-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200348 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200349int ns2_tx_unblock_ack(struct gprs_ns2_vc *nsvc)
350{
Daniel Willmann751977b2020-12-02 18:59:44 +0100351 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200352 log_set_context(LOG_CTX_GB_NSVC, nsvc);
353
354 ERR_IF_NSVC_USES_SNS(nsvc, "transmit NS UNBLOCK ACK");
355
Alexander Couzens6a161492020-07-12 13:45:50 +0200356 return ns2_tx_simple(nsvc, NS_PDUT_UNBLOCK_ACK);
357}
358
Harald Welte5bef2cc2020-09-18 22:33:24 +0200359/*! Transmit a NS-ALIVE on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200360 * \param[in] nsvc NS-VC on which the NS-ALIVE is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200361 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200362int ns2_tx_alive(struct gprs_ns2_vc *nsvc)
363{
Daniel Willmann751977b2020-12-02 18:59:44 +0100364 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200365 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200366
367 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE);
368}
369
Harald Welte5bef2cc2020-09-18 22:33:24 +0200370/*! Transmit a NS-ALIVE-ACK on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200371 * \param[in] nsvc NS-VC on which the NS-ALIVE-ACK is to be transmitted
Harald Welte5bef2cc2020-09-18 22:33:24 +0200372 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200373int ns2_tx_alive_ack(struct gprs_ns2_vc *nsvc)
374{
Daniel Willmann751977b2020-12-02 18:59:44 +0100375 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200376 log_set_context(LOG_CTX_GB_NSVC, nsvc);
Alexander Couzens6a161492020-07-12 13:45:50 +0200377
378 return ns2_tx_simple(nsvc, NS_PDUT_ALIVE_ACK);
379}
380
Harald Welte5bef2cc2020-09-18 22:33:24 +0200381/*! Transmit NS-UNITDATA on a given NS-VC.
382 * \param[in] nsvc NS-VC on which the NS-UNITDATA is to be transmitted
383 * \param[in] bvci BVCI to encode in NS-UNITDATA header
384 * \param[in] sducontrol SDU control octet of NS header
385 * \param[in] msg message buffer containing payload
386 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200387int ns2_tx_unit_data(struct gprs_ns2_vc *nsvc,
388 uint16_t bvci, uint8_t sducontrol,
389 struct msgb *msg)
390{
391 struct gprs_ns_hdr *nsh;
392
Daniel Willmann751977b2020-12-02 18:59:44 +0100393 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200394 log_set_context(LOG_CTX_GB_NSVC, nsvc);
395
396 msg->l2h = msgb_push(msg, sizeof(*nsh) + 3);
397 nsh = (struct gprs_ns_hdr *) msg->l2h;
398 if (!nsh) {
Harald Weltef2949742021-01-20 14:54:14 +0100399 LOGNSVC(nsvc, LOGL_ERROR, "Not enough headroom for NS header\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200400 msgb_free(msg);
401 return -EIO;
402 }
403
404 nsh->pdu_type = NS_PDUT_UNITDATA;
405 nsh->data[0] = sducontrol;
406 nsh->data[1] = bvci >> 8;
407 nsh->data[2] = bvci & 0xff;
408
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100409 LOG_NS_DATA(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, "\n");
Harald Welte5a5bf722021-01-30 21:49:28 +0100410 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200411}
412
Harald Welte5bef2cc2020-09-18 22:33:24 +0200413/*! Transmit a NS-STATUS on a given NS-VC.
Alexander Couzens6a161492020-07-12 13:45:50 +0200414 * \param[in] nsvc NS-VC to be used for transmission
415 * \param[in] cause Numeric NS cause value
416 * \param[in] bvci BVCI to be reset within NSVC
Harald Welte5bef2cc2020-09-18 22:33:24 +0200417 * \param[in] orig_msg message causing the STATUS
418 * \returns 0 in case of success */
Alexander Couzens6a161492020-07-12 13:45:50 +0200419int ns2_tx_status(struct gprs_ns2_vc *nsvc, uint8_t cause,
420 uint16_t bvci, struct msgb *orig_msg)
421{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100422 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200423 struct gprs_ns_hdr *nsh;
424 uint16_t nsvci = osmo_htons(nsvc->nsvci);
Alexander Couzenscf1fa632021-02-15 04:51:14 +0100425 unsigned int orig_len, max_orig_len;
Alexander Couzens6a161492020-07-12 13:45:50 +0200426
Daniel Willmann751977b2020-12-02 18:59:44 +0100427 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200428 log_set_context(LOG_CTX_GB_NSVC, nsvc);
429
430 bvci = osmo_htons(bvci);
431
432 if (!msg)
433 return -ENOMEM;
434
Alexander Couzens6a161492020-07-12 13:45:50 +0200435 msg->l2h = msgb_put(msg, sizeof(*nsh));
436 nsh = (struct gprs_ns_hdr *) msg->l2h;
437 nsh->pdu_type = NS_PDUT_STATUS;
438
439 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, &cause);
440
Alexander Couzens6a161492020-07-12 13:45:50 +0200441 switch (cause) {
Alexander Couzensce646c22021-02-15 04:55:08 +0100442 case NS_CAUSE_NSVC_BLOCKED:
443 case NS_CAUSE_NSVC_UNKNOWN:
444 /* Section 9.2.7.1: Static conditions for NS-VCI */
445 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&nsvci);
446 break;
Alexander Couzens6a161492020-07-12 13:45:50 +0200447 case NS_CAUSE_SEM_INCORR_PDU:
448 case NS_CAUSE_PDU_INCOMP_PSTATE:
449 case NS_CAUSE_PROTO_ERR_UNSPEC:
450 case NS_CAUSE_INVAL_ESSENT_IE:
451 case NS_CAUSE_MISSING_ESSENT_IE:
Alexander Couzensce646c22021-02-15 04:55:08 +0100452 /* Section 9.2.7.2: Static conditions for NS PDU */
Alexander Couzenscf1fa632021-02-15 04:51:14 +0100453 /* ensure the PDU doesn't exceed the MTU */
454 orig_len = msgb_l2len(orig_msg);
455 max_orig_len = msgb_length(msg) + TVLV_GROSS_LEN(orig_len);
456 if (max_orig_len > nsvc->bind->mtu)
457 orig_len -= max_orig_len - nsvc->bind->mtu;
458 msgb_tvlv_put(msg, NS_IE_PDU, orig_len, orig_msg->l2h);
Alexander Couzens6a161492020-07-12 13:45:50 +0200459 break;
Alexander Couzensce646c22021-02-15 04:55:08 +0100460 case NS_CAUSE_BVCI_UNKNOWN:
461 /* Section 9.2.7.3: Static conditions for BVCI */
462 msgb_tvlv_put(msg, NS_IE_VCI, 2, (uint8_t *)&bvci);
463 break;
464
Alexander Couzens6a161492020-07-12 13:45:50 +0200465 default:
466 break;
467 }
468
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100469 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 +0100470 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200471}
472
Alexander Couzens27a55922021-02-27 01:08:35 +0100473/*! Encode + Transmit a SNS-ADD/SNS-CHANGE-WEIGHT as per Section 9.3.2/9.3.3.
474 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
475 * \param[in] pdu The PDU type to send out
476 * \param[in] trans_id The transaction id
477 * \param[in] ip4_elems Array of IPv4 Elements
478 * \param[in] num_ip4_elems number of ip4_elems
479 * \param[in] ip6_elems Array of IPv6 Elements
480 * \param[in] num_ip6_elems number of ip6_elems
481 * \returns 0 on success; negative in case of error */
482static int ns2_tx_sns_procedure(struct gprs_ns2_vc *nsvc,
483 enum ns_pdu_type pdu,
484 uint8_t trans_id,
485 const struct gprs_ns_ie_ip4_elem *ip4_elems,
486 unsigned int num_ip4_elems,
487 const struct gprs_ns_ie_ip6_elem *ip6_elems,
488 unsigned int num_ip6_elems)
489{
490 struct msgb *msg;
491 struct gprs_ns_hdr *nsh;
492 uint16_t nsei;
493
494 if (!nsvc)
495 return -EINVAL;
496
497 if (!ip4_elems && !ip6_elems)
498 return -EINVAL;
499
500 msg = ns2_msgb_alloc();
501
502 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
503 log_set_context(LOG_CTX_GB_NSVC, nsvc);
504 if (!msg)
505 return -ENOMEM;
506
507 if (!nsvc->nse->bss_sns_fi) {
508 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
509 msgb_free(msg);
510 return -EIO;
511 }
512
513 nsei = osmo_htons(nsvc->nse->nsei);
514
515 msg->l2h = msgb_put(msg, sizeof(*nsh));
516 nsh = (struct gprs_ns_hdr *) msg->l2h;
517 nsh->pdu_type = pdu;
518 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
519 msgb_v_put(msg, trans_id);
520
521 /* List of IP4 Elements 10.3.2c */
522 if (ip4_elems) {
523 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
524 (const uint8_t *)ip4_elems);
525 } else if (ip6_elems) {
526 /* List of IP6 elements 10.3.2d */
527 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
528 (const uint8_t *)ip6_elems);
529 }
530
531 return ns_vc_tx(nsvc, msg);
532}
533
534/*! Encode + Transmit a SNS-ADD as per Section 9.3.2.
535 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
536 * \param[in] trans_id The transaction id
537 * \param[in] ip4_elems Array of IPv4 Elements
538 * \param[in] num_ip4_elems number of ip4_elems
539 * \param[in] ip6_elems Array of IPv6 Elements
540 * \param[in] num_ip6_elems number of ip6_elems
541 * \returns 0 on success; negative in case of error */
542int ns2_tx_sns_add(struct gprs_ns2_vc *nsvc,
543 uint8_t trans_id,
544 const struct gprs_ns_ie_ip4_elem *ip4_elems,
545 unsigned int num_ip4_elems,
546 const struct gprs_ns_ie_ip6_elem *ip6_elems,
547 unsigned int num_ip6_elems)
548{
549 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_ADD, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
550}
551
552/*! Encode + Transmit a SNS-CHANGE-WEIGHT as per Section 9.3.3.
553 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
554 * \param[in] trans_id The transaction id
555 * \param[in] ip4_elems Array of IPv4 Elements
556 * \param[in] num_ip4_elems number of ip4_elems
557 * \param[in] ip6_elems Array of IPv6 Elements
558 * \param[in] num_ip6_elems number of ip6_elems
559 * \returns 0 on success; negative in case of error */
560int ns2_tx_sns_change_weight(struct gprs_ns2_vc *nsvc,
561 uint8_t trans_id,
562 const struct gprs_ns_ie_ip4_elem *ip4_elems,
563 unsigned int num_ip4_elems,
564 const struct gprs_ns_ie_ip6_elem *ip6_elems,
565 unsigned int num_ip6_elems)
566{
567 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_CHANGE_WEIGHT, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
568}
569
570/*! Encode + Transmit a SNS-DEL as per Section 9.3.6.
571 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
572 * \param[in] trans_id The transaction id
573 * \param[in] ip4_elems Array of IPv4 Elements
574 * \param[in] num_ip4_elems number of ip4_elems
575 * \param[in] ip6_elems Array of IPv6 Elements
576 * \param[in] num_ip6_elems number of ip6_elems
577 * \returns 0 on success; negative in case of error */
578int ns2_tx_sns_del(struct gprs_ns2_vc *nsvc,
579 uint8_t trans_id,
580 const struct gprs_ns_ie_ip4_elem *ip4_elems,
581 unsigned int num_ip4_elems,
582 const struct gprs_ns_ie_ip6_elem *ip6_elems,
583 unsigned int num_ip6_elems)
584{
585 /* TODO: IP Address field */
586 return ns2_tx_sns_procedure(nsvc, SNS_PDUT_DELETE, trans_id, ip4_elems, num_ip4_elems, ip6_elems, num_ip6_elems);
587}
588
Alexander Couzens6a161492020-07-12 13:45:50 +0200589
590/*! Encode + Transmit a SNS-ACK as per Section 9.3.1.
591 * \param[in] nsvc NS-VC through which to transmit the ACK
592 * \param[in] trans_id Transaction ID which to acknowledge
593 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
594 * \param[in] ip4_elems Array of IPv4 Elements
595 * \param[in] num_ip4_elems number of ip4_elems
596 * \returns 0 on success; negative in case of error */
597int ns2_tx_sns_ack(struct gprs_ns2_vc *nsvc, uint8_t trans_id, uint8_t *cause,
598 const struct gprs_ns_ie_ip4_elem *ip4_elems,
599 unsigned int num_ip4_elems,
600 const struct gprs_ns_ie_ip6_elem *ip6_elems,
601 unsigned int num_ip6_elems)
602{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100603 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200604 struct gprs_ns_hdr *nsh;
605 uint16_t nsei;
606
607 if (!nsvc)
608 return -1;
609
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100610 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200611
Daniel Willmann751977b2020-12-02 18:59:44 +0100612 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200613 log_set_context(LOG_CTX_GB_NSVC, nsvc);
614 if (!msg)
615 return -ENOMEM;
616
617 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100618 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200619 msgb_free(msg);
620 return -EIO;
621 }
622
Harald Welte22274df2021-03-04 07:59:16 +0100623
Alexander Couzens6a161492020-07-12 13:45:50 +0200624 nsei = osmo_htons(nsvc->nse->nsei);
625
626 msg->l2h = msgb_put(msg, sizeof(*nsh));
627 nsh = (struct gprs_ns_hdr *) msg->l2h;
628
629 nsh->pdu_type = SNS_PDUT_ACK;
630 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
631 msgb_v_put(msg, trans_id);
632 if (cause)
633 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
634 if (ip4_elems) {
635 /* List of IP4 Elements 10.3.2c */
636 msgb_tvlv_put(msg, NS_IE_IPv4_LIST,
637 num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
638 (const uint8_t *)ip4_elems);
639 }
640 if (ip6_elems) {
641 /* List of IP6 elements 10.3.2d */
642 msgb_tvlv_put(msg, NS_IE_IPv6_LIST,
643 num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
644 (const uint8_t *)ip6_elems);
645 }
646
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100647 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
648 " (trans_id=%u, cause=%s, num_ip4=%u, num_ip6=%u)\n",
649 trans_id, cause ? gprs_ns2_cause_str(*cause) : "NULL", num_ip4_elems, num_ip6_elems);
Harald Welte5a5bf722021-01-30 21:49:28 +0100650 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200651}
652
653/*! Encode + Transmit a SNS-CONFIG as per Section 9.3.4.
654 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG
655 * \param[in] end_flag Whether or not this is the last SNS-CONFIG
656 * \param[in] ip4_elems Array of IPv4 Elements
657 * \param[in] num_ip4_elems number of ip4_elems
658 * \returns 0 on success; negative in case of error */
659int ns2_tx_sns_config(struct gprs_ns2_vc *nsvc, bool end_flag,
660 const struct gprs_ns_ie_ip4_elem *ip4_elems,
661 unsigned int num_ip4_elems,
662 const struct gprs_ns_ie_ip6_elem *ip6_elems,
663 unsigned int num_ip6_elems)
664{
665 struct msgb *msg;
666 struct gprs_ns_hdr *nsh;
667 uint16_t nsei;
668
669 if (!nsvc)
670 return -1;
671
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100672 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200673
Daniel Willmann751977b2020-12-02 18:59:44 +0100674 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200675 log_set_context(LOG_CTX_GB_NSVC, nsvc);
676 if (!msg)
677 return -ENOMEM;
678
679 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100680 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200681 msgb_free(msg);
682 return -EIO;
683 }
684
685 nsei = osmo_htons(nsvc->nse->nsei);
686
687 msg->l2h = msgb_put(msg, sizeof(*nsh));
688 nsh = (struct gprs_ns_hdr *) msg->l2h;
689
690 nsh->pdu_type = SNS_PDUT_CONFIG;
691
692 msgb_v_put(msg, end_flag ? 0x01 : 0x00);
693 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
694
695 /* List of IP4 Elements 10.3.2c */
696 if (ip4_elems) {
697 msgb_tvlv_put(msg, NS_IE_IPv4_LIST, num_ip4_elems*sizeof(struct gprs_ns_ie_ip4_elem),
698 (const uint8_t *)ip4_elems);
699 } else if (ip6_elems) {
700 /* List of IP6 elements 10.3.2d */
701 msgb_tvlv_put(msg, NS_IE_IPv6_LIST, num_ip6_elems*sizeof(struct gprs_ns_ie_ip6_elem),
702 (const uint8_t *)ip6_elems);
703 }
704
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100705 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
706 " (end_flag=%u, num_ip4=%u, num_ip6=%u)\n",
707 end_flag, num_ip4_elems, num_ip6_elems);
Harald Welte5a5bf722021-01-30 21:49:28 +0100708 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200709}
710
711/*! Encode + Transmit a SNS-CONFIG-ACK as per Section 9.3.5.
712 * \param[in] nsvc NS-VC through which to transmit the SNS-CONFIG-ACK
713 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
714 * \returns 0 on success; negative in case of error */
715int ns2_tx_sns_config_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
716{
717 struct msgb *msg;
718 struct gprs_ns_hdr *nsh;
719 uint16_t nsei;
720
721 if (!nsvc)
722 return -1;
723
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100724 msg = ns2_msgb_alloc();
Daniel Willmann751977b2020-12-02 18:59:44 +0100725 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200726 log_set_context(LOG_CTX_GB_NSVC, nsvc);
727 if (!msg)
728 return -ENOMEM;
729
730 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100731 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200732 msgb_free(msg);
733 return -EIO;
734 }
735
736 nsei = osmo_htons(nsvc->nse->nsei);
737
738 msg->l2h = msgb_put(msg, sizeof(*nsh));
739 nsh = (struct gprs_ns_hdr *) msg->l2h;
740
741 nsh->pdu_type = SNS_PDUT_CONFIG_ACK;
742
743 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
744 if (cause)
745 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
746
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100747 LOGNSVC(nsvc, LOGL_INFO, "Tx SNS-CONFIG-ACK (cause=%s)\n",
748 cause ? gprs_ns2_cause_str(*cause) : "NULL");
749 LOG_NS_TX_SIGNAL(nsvc, nsh->pdu_type);
Harald Welte5a5bf722021-01-30 21:49:28 +0100750 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200751}
752
753
754/*! Encode + transmit a SNS-SIZE as per Section 9.3.7.
755 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE
756 * \param[in] reset_flag Whether or not to add a RESET flag
757 * \param[in] max_nr_nsvc Maximum number of NS-VCs
758 * \param[in] ip4_ep_nr Number of IPv4 endpoints (< 0 will omit the TLV)
759 * \param[in] ip6_ep_nr Number of IPv6 endpoints (< 0 will omit the TLV)
760 * \returns 0 on success; negative in case of error */
761int ns2_tx_sns_size(struct gprs_ns2_vc *nsvc, bool reset_flag, uint16_t max_nr_nsvc,
762 int ip4_ep_nr, int ip6_ep_nr)
763{
Daniel Willmann89a00f32021-01-17 14:20:28 +0100764 struct msgb *msg;
Alexander Couzens6a161492020-07-12 13:45:50 +0200765 struct gprs_ns_hdr *nsh;
766 uint16_t nsei;
767
768 if (!nsvc)
769 return -1;
770
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100771 msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200772
Daniel Willmann751977b2020-12-02 18:59:44 +0100773 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200774 log_set_context(LOG_CTX_GB_NSVC, nsvc);
775 if (!msg)
776 return -ENOMEM;
777
778 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100779 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200780 msgb_free(msg);
781 return -EIO;
782 }
783
784 nsei = osmo_htons(nsvc->nse->nsei);
785
786 msg->l2h = msgb_put(msg, sizeof(*nsh));
787 nsh = (struct gprs_ns_hdr *) msg->l2h;
788
789 nsh->pdu_type = SNS_PDUT_SIZE;
790
791 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
792 msgb_tv_put(msg, NS_IE_RESET_FLAG, reset_flag ? 0x01 : 0x00);
793 msgb_tv16_put(msg, NS_IE_MAX_NR_NSVC, max_nr_nsvc);
794 if (ip4_ep_nr >= 0)
795 msgb_tv16_put(msg, NS_IE_IPv4_EP_NR, ip4_ep_nr);
796 if (ip6_ep_nr >= 0)
797 msgb_tv16_put(msg, NS_IE_IPv6_EP_NR, ip6_ep_nr);
798
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100799 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO,
Alexander Couzens6ba77a32021-07-06 11:34:04 +0200800 " (reset=%u, max_nr_nsvc=%u, num_ip4=%d, num_ip6=%d)\n",
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100801 reset_flag, max_nr_nsvc, ip4_ep_nr, ip6_ep_nr);
Harald Welte5a5bf722021-01-30 21:49:28 +0100802 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200803}
804
805/*! Encode + Transmit a SNS-SIZE-ACK as per Section 9.3.8.
806 * \param[in] nsvc NS-VC through which to transmit the SNS-SIZE-ACK
807 * \param[in] cause Pointer to cause value (NULL if no cause to be sent)
808 * \returns 0 on success; negative in case of error */
809int ns2_tx_sns_size_ack(struct gprs_ns2_vc *nsvc, uint8_t *cause)
810{
Alexander Couzens8dfc24c2021-01-25 16:09:23 +0100811 struct msgb *msg = ns2_msgb_alloc();
Alexander Couzens6a161492020-07-12 13:45:50 +0200812 struct gprs_ns_hdr *nsh;
813 uint16_t nsei;
814
Daniel Willmann751977b2020-12-02 18:59:44 +0100815 log_set_context(LOG_CTX_GB_NSE, nsvc->nse);
Alexander Couzens6a161492020-07-12 13:45:50 +0200816 log_set_context(LOG_CTX_GB_NSVC, nsvc);
817 if (!msg)
818 return -ENOMEM;
819
820 if (!nsvc->nse->bss_sns_fi) {
Harald Weltef2949742021-01-20 14:54:14 +0100821 LOGNSVC(nsvc, LOGL_ERROR, "Cannot transmit SNS on NSVC without SNS active\n");
Alexander Couzens6a161492020-07-12 13:45:50 +0200822 msgb_free(msg);
823 return -EIO;
824 }
825
826 nsei = osmo_htons(nsvc->nse->nsei);
827
828 msg->l2h = msgb_put(msg, sizeof(*nsh));
829 nsh = (struct gprs_ns_hdr *) msg->l2h;
830
831 nsh->pdu_type = SNS_PDUT_SIZE_ACK;
832
833 msgb_tvlv_put(msg, NS_IE_NSEI, 2, (uint8_t *)&nsei);
834 if (cause)
835 msgb_tvlv_put(msg, NS_IE_CAUSE, 1, cause);
836
Alexander Couzens6cf65d92021-01-18 17:55:35 +0100837 LOG_NS_SIGNAL(nsvc, "Tx", nsh->pdu_type, LOGL_INFO, " cause=%s\n",
838 cause ? gprs_ns2_cause_str(*cause) : "NULL");
Harald Welte5a5bf722021-01-30 21:49:28 +0100839 return ns_vc_tx(nsvc, msg);
Alexander Couzens6a161492020-07-12 13:45:50 +0200840}