blob: e741fb460ed43c7b3f825e2f61fce9468452c8ac [file] [log] [blame]
Harald Welte17a892f2020-12-07 21:39:03 +01001/* BSSGP2 - second generation of BSSGP library */
2
3/* (C) 2020 Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * SPDX-License-Identifier: GPL-2.0+
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include <osmocom/core/utils.h>
25#include <osmocom/core/byteswap.h>
26#include <osmocom/core/msgb.h>
27
28#include <osmocom/gsm/gsm48.h>
29#include <osmocom/gsm/tlv.h>
30
31#include <osmocom/gprs/gprs_ns2.h>
32#include <osmocom/gprs/gprs_bssgp.h>
33#include <osmocom/gprs/gprs_bssgp2.h>
34
35
36/*! transmit BSSGP PDU over NS (PTP BVC)
37 * \param[in] nsi NS Instance through which to transmit
38 * \param[in] nsei NSEI of NSE through which to transmit
39 * \param[in] bvci BVCI through which to transmit
40 * \param[in] msg BSSGP PDU to transmit
41 * \returns 0 on success; negative on error */
42int bssgp2_nsi_tx_ptp(struct gprs_ns2_inst *nsi, uint16_t nsei, uint16_t bvci,
43 struct msgb *msg, uint32_t lsp)
44{
45 struct osmo_gprs_ns2_prim nsp = {};
46 int rc;
47
48 if (!msg)
49 return 0;
50
51 nsp.bvci = bvci;
52 nsp.nsei = nsei;
53 nsp.u.unitdata.link_selector = lsp;
54
55 osmo_prim_init(&nsp.oph, SAP_NS, PRIM_NS_UNIT_DATA, PRIM_OP_REQUEST, msg);
56 rc = gprs_ns2_recv_prim(nsi, &nsp.oph);
57
58 return rc;
59}
60
61/*! transmit BSSGP PDU over NS (SIGNALING BVC)
62 * \param[in] nsi NS Instance through which to transmit
63 * \param[in] nsei NSEI of NSE through which to transmit
64 * \param[in] msg BSSGP PDU to transmit
65 * \returns 0 on success; negative on error */
66int bssgp2_nsi_tx_sig(struct gprs_ns2_inst *nsi, uint16_t nsei, struct msgb *msg, uint32_t lsp)
67{
68 return bssgp2_nsi_tx_ptp(nsi, nsei, 0, msg, lsp);
69}
70
71/*! Encode BSSGP BVC-BLOCK PDU as per TS 48.018 Section 10.4.8. */
72struct msgb *bssgp2_enc_bvc_block(uint16_t bvci, enum gprs_bssgp_cause cause)
73{
74 struct msgb *msg = bssgp_msgb_alloc();
75 struct bssgp_normal_hdr *bgph;
76 uint16_t _bvci = osmo_htons(bvci);
77
78 if (!msg)
79 return NULL;
80
81 bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
82 bgph->pdu_type = BSSGP_PDUT_BVC_BLOCK;
83
84 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
85 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, (uint8_t *) &cause);
86
87 return msg;
88}
89
90/*! Encode BSSGP BVC-BLOCK-ACK PDU as per TS 48.018 Section 10.4.9. */
91struct msgb *bssgp2_enc_bvc_block_ack(uint16_t bvci)
92{
93 struct msgb *msg = bssgp_msgb_alloc();
94 struct bssgp_normal_hdr *bgph;
95 uint16_t _bvci = osmo_htons(bvci);
96
97 if (!msg)
98 return NULL;
99
100 bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
101 bgph->pdu_type = BSSGP_PDUT_BVC_BLOCK_ACK;
102
103 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
104
105 return msg;
106}
107
108/*! Encode BSSGP BVC-UNBLOCK PDU as per TS 48.018 Section 10.4.10. */
109struct msgb *bssgp2_enc_bvc_unblock(uint16_t bvci)
110{
111 struct msgb *msg = bssgp_msgb_alloc();
112 struct bssgp_normal_hdr *bgph;
113 uint16_t _bvci = osmo_htons(bvci);
114
115 if (!msg)
116 return NULL;
117
118 bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
119 bgph->pdu_type = BSSGP_PDUT_BVC_UNBLOCK;
120
121 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
122
123 return msg;
124}
125
126/*! Encode BSSGP BVC-UNBLOCK-ACK PDU as per TS 48.018 Section 10.4.11. */
127struct msgb *bssgp2_enc_bvc_unblock_ack(uint16_t bvci)
128{
129 struct msgb *msg = bssgp_msgb_alloc();
130 struct bssgp_normal_hdr *bgph;
131 uint16_t _bvci = osmo_htons(bvci);
132
133 if (!msg)
134 return NULL;
135
136 bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
137 bgph->pdu_type = BSSGP_PDUT_BVC_UNBLOCK_ACK;
138
139 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
140
141 return msg;
142}
143
144/*! Encode BSSGP BVC-RESET PDU as per TS 48.018 Section 10.4.12.
145 * \param[in] bvci PTP BVCI to encode into the BVCI IE
146 * \param[in] cause BSSGP Cause value (reason for reset)
147 * \param[in] ra_id Routing Area ID to be encoded to CELL_ID IE (optional)
148 * \param[in] cell_id Cell ID to be encoded to CELL_ID IE (only if ra_id is non-NULL)
149 * \param[in] feat_bm Feature Bitmap (optional)
150 * \param[in] ext_feat_bm Extended Feature Bitmap (optional) */
151struct msgb *bssgp2_enc_bvc_reset(uint16_t bvci, enum gprs_bssgp_cause cause,
152 const struct gprs_ra_id *ra_id, uint16_t cell_id,
153 const uint8_t *feat_bm, const uint8_t *ext_feat_bm)
154{
155 struct msgb *msg = bssgp_msgb_alloc();
156 struct bssgp_normal_hdr *bgph;
157 uint16_t _bvci = osmo_htons(bvci);
158
159 if (!msg)
160 return NULL;
161
162 bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
163 bgph->pdu_type = BSSGP_PDUT_BVC_RESET;
164
165 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
166 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, (uint8_t *) &cause);
167 if (ra_id) {
168 uint8_t bssgp_cid[8];
169 bssgp_create_cell_id(bssgp_cid, ra_id, cell_id);
170 msgb_tvlv_put(msg, BSSGP_IE_CELL_ID, sizeof(bssgp_cid), bssgp_cid);
171 }
172
173 if (feat_bm)
174 msgb_tvlv_put(msg, BSSGP_IE_FEATURE_BITMAP, 1, feat_bm);
175
176 if (ext_feat_bm)
177 msgb_tvlv_put(msg, BSSGP_IE_EXT_FEATURE_BITMAP, 1, feat_bm);
178
179 return msg;
180}
181
182/*! Encode BSSGP BVC-RESET-ACK PDU as per TS 48.018 Section 10.4.13.
183 * \param[in] bvci PTP BVCI to encode into the BVCI IE
184 * \param[in] ra_id Routing Area ID to be encoded to CELL_ID IE (optional)
185 * \param[in] cell_id Cell ID to be encoded to CELL_ID IE (only if ra_id is non-NULL)
186 * \param[in] feat_bm Feature Bitmap (optional)
187 * \param[in] ext_feat_bm Extended Feature Bitmap (optional) */
188struct msgb *bssgp2_enc_bvc_reset_ack(uint16_t bvci, const struct gprs_ra_id *ra_id, uint16_t cell_id,
189 const uint8_t *feat_bm, const uint8_t *ext_feat_bm)
190{
191 struct msgb *msg = bssgp_msgb_alloc();
192 struct bssgp_normal_hdr *bgph;
193 uint16_t _bvci = osmo_htons(bvci);
194
195 if (!msg)
196 return NULL;
197
198 bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
199 bgph->pdu_type = BSSGP_PDUT_BVC_RESET_ACK;
200
201 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
202 if (ra_id) {
203 uint8_t bssgp_cid[8];
204 bssgp_create_cell_id(bssgp_cid, ra_id, cell_id);
205 msgb_tvlv_put(msg, BSSGP_IE_CELL_ID, sizeof(bssgp_cid), bssgp_cid);
206 }
207
208 if (feat_bm)
209 msgb_tvlv_put(msg, BSSGP_IE_FEATURE_BITMAP, 1, feat_bm);
210
211 if (ext_feat_bm)
212 msgb_tvlv_put(msg, BSSGP_IE_EXT_FEATURE_BITMAP, 1, feat_bm);
213
214 return msg;
215}
216
217/*! Encode BSSGP STATUS PDU as per TS 48.018 Section 10.4.14.
218 * \param[in] cause BSSGP Cause value
219 * \param[in] bvci optional BVCI - only encoded if non-NULL
220 * \param[in] msg optional message buffer containing PDU in error - only encoded if non-NULL */
221struct msgb *bssgp2_enc_status(uint8_t cause, const uint16_t *bvci, const struct msgb *orig_msg)
222{
223 struct msgb *msg = bssgp_msgb_alloc();
224 struct bssgp_normal_hdr *bgph;
225
226 if (!msg)
227 return NULL;
228
229 bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
230 bgph->pdu_type = BSSGP_PDUT_STATUS;
231 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause);
232 if (bvci) {
233 uint16_t _bvci = osmo_htons(*bvci);
234 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
235 }
236 if (orig_msg)
237 msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR, msgb_bssgp_len(orig_msg), msgb_bssgph(orig_msg));
238
239 return msg;
240}