blob: f41c4a4f80ef18664b54d63c3ef5088fbd7a1301 [file] [log] [blame]
Harald Welte85fc3142011-11-25 08:58:40 +01001/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */
2
Harald Weltebfe62e52017-05-15 12:48:30 +02003/* (C) 2009-2017 by Harald Welte <laforge@gnumonks.org>
Harald Welte85fc3142011-11-25 08:58:40 +01004 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
Harald Welte7fa89c22014-10-26 20:33:09 +01008 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
Harald Welte85fc3142011-11-25 08:58:40 +010010 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte7fa89c22014-10-26 20:33:09 +010015 * GNU General Public License for more details.
Harald Welte85fc3142011-11-25 08:58:40 +010016 *
Harald Welte7fa89c22014-10-26 20:33:09 +010017 * You should have received a copy of the GNU General Public License
Harald Welte85fc3142011-11-25 08:58:40 +010018 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#include <errno.h>
23#include <stdint.h>
24
Harald Welte85fc3142011-11-25 08:58:40 +010025#include <osmocom/core/msgb.h>
Harald Weltebfe62e52017-05-15 12:48:30 +020026#include <osmocom/core/byteswap.h>
Harald Welte85fc3142011-11-25 08:58:40 +010027#include <osmocom/core/rate_ctr.h>
28#include <osmocom/gsm/tlv.h>
29#include <osmocom/core/talloc.h>
Harald Welte73952e32012-06-16 14:59:56 +080030#include <osmocom/gprs/gprs_bssgp.h>
Harald Welte30fabdf2012-09-10 08:54:35 +020031#include <osmocom/gprs/gprs_bssgp_bss.h>
Harald Welte73952e32012-06-16 14:59:56 +080032#include <osmocom/gprs/gprs_ns.h>
Harald Welte85fc3142011-11-25 08:58:40 +010033
Harald Weltecca49632012-06-16 17:45:59 +080034#include "common_vty.h"
Harald Welte85fc3142011-11-25 08:58:40 +010035
Jacob Erlbeckc1cb75e2015-06-18 13:21:30 +020036#define GSM_IMSI_LENGTH 17
37
Harald Welte85fc3142011-11-25 08:58:40 +010038uint8_t *bssgp_msgb_tlli_put(struct msgb *msg, uint32_t tlli)
39{
Harald Weltebfe62e52017-05-15 12:48:30 +020040 uint32_t _tlli = osmo_htonl(tlli);
Harald Welte85fc3142011-11-25 08:58:40 +010041 return msgb_tvlv_put(msg, BSSGP_IE_TLLI, 4, (uint8_t *) &_tlli);
42}
43
Neels Hofmeyr87e45502017-06-20 00:17:59 +020044/*! GMM-SUSPEND.req (Chapter 10.3.6) */
Harald Welte85fc3142011-11-25 08:58:40 +010045int bssgp_tx_suspend(uint16_t nsei, uint32_t tlli,
46 const struct gprs_ra_id *ra_id)
47{
48 struct msgb *msg = bssgp_msgb_alloc();
49 struct bssgp_normal_hdr *bgph =
50 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
51 uint8_t ra[6];
52
53 LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=0) Tx SUSPEND (TLLI=0x%04x)\n",
54 tlli);
55 msgb_nsei(msg) = nsei;
56 msgb_bvci(msg) = 0; /* Signalling */
57 bgph->pdu_type = BSSGP_PDUT_SUSPEND;
58
59 bssgp_msgb_tlli_put(msg, tlli);
60
61 gsm48_construct_ra(ra, ra_id);
62 msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra);
63
64 return gprs_ns_sendmsg(bssgp_nsi, msg);
65}
66
Neels Hofmeyr87e45502017-06-20 00:17:59 +020067/*! GMM-RESUME.req (Chapter 10.3.9) */
Harald Welte85fc3142011-11-25 08:58:40 +010068int bssgp_tx_resume(uint16_t nsei, uint32_t tlli,
69 const struct gprs_ra_id *ra_id, uint8_t suspend_ref)
70{
71 struct msgb *msg = bssgp_msgb_alloc();
72 struct bssgp_normal_hdr *bgph =
73 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
74 uint8_t ra[6];
75
76 LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=0) Tx RESUME (TLLI=0x%04x)\n",
77 tlli);
78 msgb_nsei(msg) = nsei;
79 msgb_bvci(msg) = 0; /* Signalling */
80 bgph->pdu_type = BSSGP_PDUT_RESUME;
81
82 bssgp_msgb_tlli_put(msg, tlli);
83
84 gsm48_construct_ra(ra, ra_id);
85 msgb_tvlv_put(msg, BSSGP_IE_ROUTEING_AREA, 6, ra);
86
87 msgb_tvlv_put(msg, BSSGP_IE_SUSPEND_REF_NR, 1, &suspend_ref);
88
89 return gprs_ns_sendmsg(bssgp_nsi, msg);
90}
91
Neels Hofmeyr87e45502017-06-20 00:17:59 +020092/*! Transmit RA-CAPABILITY-UPDATE (10.3.3) */
Harald Welte85fc3142011-11-25 08:58:40 +010093int bssgp_tx_ra_capa_upd(struct bssgp_bvc_ctx *bctx, uint32_t tlli, uint8_t tag)
94{
95 struct msgb *msg = bssgp_msgb_alloc();
96 struct bssgp_normal_hdr *bgph =
97 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
98
99 LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx RA-CAPA-UPD (TLLI=0x%04x)\n",
100 bctx->bvci, tlli);
101
102 /* set NSEI and BVCI in msgb cb */
103 msgb_nsei(msg) = bctx->nsei;
104 msgb_bvci(msg) = bctx->bvci;
105
106 bgph->pdu_type = BSSGP_PDUT_RA_CAPA_UDPATE;
107 bssgp_msgb_tlli_put(msg, tlli);
108
109 msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag);
110
111 return gprs_ns_sendmsg(bssgp_nsi, msg);
112}
113
114/* first common part of RADIO-STATUS */
115static struct msgb *common_tx_radio_status(struct bssgp_bvc_ctx *bctx)
116{
117 struct msgb *msg = bssgp_msgb_alloc();
118 struct bssgp_normal_hdr *bgph =
119 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
120
121 LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx RADIO-STATUS ",
122 bctx->bvci);
123
124 /* set NSEI and BVCI in msgb cb */
125 msgb_nsei(msg) = bctx->nsei;
126 msgb_bvci(msg) = bctx->bvci;
127
128 bgph->pdu_type = BSSGP_PDUT_RADIO_STATUS;
129
130 return msg;
131}
132
133/* second common part of RADIO-STATUS */
134static int common_tx_radio_status2(struct msgb *msg, uint8_t cause)
135{
136 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause);
Max2c34ab42016-03-17 15:42:26 +0100137 LOGPC(DBSSGP, LOGL_NOTICE, "CAUSE=%s\n", bssgp_cause_str(cause));
Harald Welte85fc3142011-11-25 08:58:40 +0100138
139 return gprs_ns_sendmsg(bssgp_nsi, msg);
140}
141
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200142/*! Transmit RADIO-STATUS for TLLI (10.3.5) */
Harald Welte85fc3142011-11-25 08:58:40 +0100143int bssgp_tx_radio_status_tlli(struct bssgp_bvc_ctx *bctx, uint8_t cause,
144 uint32_t tlli)
145{
146 struct msgb *msg = common_tx_radio_status(bctx);
147
148 if (!msg)
149 return -ENOMEM;
150 bssgp_msgb_tlli_put(msg, tlli);
151 LOGPC(DBSSGP, LOGL_NOTICE, "TLLI=0x%08x ", tlli);
152
153 return common_tx_radio_status2(msg, cause);
154}
155
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200156/*! Transmit RADIO-STATUS for TMSI (10.3.5) */
Harald Welte85fc3142011-11-25 08:58:40 +0100157int bssgp_tx_radio_status_tmsi(struct bssgp_bvc_ctx *bctx, uint8_t cause,
158 uint32_t tmsi)
159{
160 struct msgb *msg = common_tx_radio_status(bctx);
Harald Weltebfe62e52017-05-15 12:48:30 +0200161 uint32_t _tmsi = osmo_htonl(tmsi);
Harald Welte85fc3142011-11-25 08:58:40 +0100162
163 if (!msg)
164 return -ENOMEM;
165 msgb_tvlv_put(msg, BSSGP_IE_TMSI, 4, (uint8_t *)&_tmsi);
166 LOGPC(DBSSGP, LOGL_NOTICE, "TMSI=0x%08x ", tmsi);
167
168 return common_tx_radio_status2(msg, cause);
169}
170
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200171/*! Transmit RADIO-STATUS for IMSI (10.3.5) */
Harald Welte85fc3142011-11-25 08:58:40 +0100172int bssgp_tx_radio_status_imsi(struct bssgp_bvc_ctx *bctx, uint8_t cause,
173 const char *imsi)
174{
175 struct msgb *msg = common_tx_radio_status(bctx);
176 uint8_t mi[10];
177 int imsi_len = gsm48_generate_mid_from_imsi(mi, imsi);
178
179 if (!msg)
180 return -ENOMEM;
181
182 /* strip the MI type and length values (2 bytes) */
183 if (imsi_len > 2)
184 msgb_tvlv_put(msg, BSSGP_IE_IMSI, imsi_len-2, mi+2);
185 LOGPC(DBSSGP, LOGL_NOTICE, "IMSI=%s ", imsi);
186
187 return common_tx_radio_status2(msg, cause);
188}
189
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200190/*! Transmit FLUSH-LL-ACK (Chapter 10.4.2) */
Harald Welte85fc3142011-11-25 08:58:40 +0100191int bssgp_tx_flush_ll_ack(struct bssgp_bvc_ctx *bctx, uint32_t tlli,
192 uint8_t action, uint16_t bvci_new,
193 uint32_t num_octets)
194{
195 struct msgb *msg = bssgp_msgb_alloc();
196 struct bssgp_normal_hdr *bgph =
197 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
Harald Weltebfe62e52017-05-15 12:48:30 +0200198 uint16_t _bvci_new = osmo_htons(bvci_new);
199 uint32_t _oct_aff = osmo_htonl(num_octets & 0xFFFFFF);
Harald Welte85fc3142011-11-25 08:58:40 +0100200
201 msgb_nsei(msg) = bctx->nsei;
202 msgb_bvci(msg) = 0; /* Signalling */
203 bgph->pdu_type = BSSGP_PDUT_FLUSH_LL_ACK;
204
205 bssgp_msgb_tlli_put(msg, tlli);
206 msgb_tvlv_put(msg, BSSGP_IE_FLUSH_ACTION, 1, &action);
207 if (action == 1) /* transferred */
208 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci_new);
209 msgb_tvlv_put(msg, BSSGP_IE_NUM_OCT_AFF, 3, (uint8_t *) &_oct_aff);
210
211 return gprs_ns_sendmsg(bssgp_nsi, msg);
212}
213
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200214/*! Transmit LLC-DISCARDED (Chapter 10.4.3) */
Harald Welte85fc3142011-11-25 08:58:40 +0100215int bssgp_tx_llc_discarded(struct bssgp_bvc_ctx *bctx, uint32_t tlli,
216 uint8_t num_frames, uint32_t num_octets)
217{
218 struct msgb *msg = bssgp_msgb_alloc();
219 struct bssgp_normal_hdr *bgph =
220 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
Harald Weltebfe62e52017-05-15 12:48:30 +0200221 uint16_t _bvci = osmo_htons(bctx->bvci);
222 uint32_t _oct_aff = osmo_htonl(num_octets & 0xFFFFFF);
Harald Welte85fc3142011-11-25 08:58:40 +0100223
224 LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx LLC-DISCARDED "
225 "TLLI=0x%04x, FRAMES=%u, OCTETS=%u\n", bctx->bvci, tlli,
226 num_frames, num_octets);
227 msgb_nsei(msg) = bctx->nsei;
228 msgb_bvci(msg) = 0; /* Signalling */
229 bgph->pdu_type = BSSGP_PDUT_LLC_DISCARD;
230
231 bssgp_msgb_tlli_put(msg, tlli);
232
233 msgb_tvlv_put(msg, BSSGP_IE_LLC_FRAMES_DISCARDED, 1, &num_frames);
234 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
Andreas Eversbergaa5d0e82012-07-21 13:33:39 +0200235 msgb_tvlv_put(msg, BSSGP_IE_NUM_OCT_AFF, 3, ((uint8_t *) &_oct_aff) + 1);
Harald Welte85fc3142011-11-25 08:58:40 +0100236
237 return gprs_ns_sendmsg(bssgp_nsi, msg);
238}
239
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200240/*! Transmit a BVC-BLOCK message (Chapter 10.4.8) */
Harald Welte85fc3142011-11-25 08:58:40 +0100241int bssgp_tx_bvc_block(struct bssgp_bvc_ctx *bctx, uint8_t cause)
242{
243 struct msgb *msg = bssgp_msgb_alloc();
244 struct bssgp_normal_hdr *bgph =
245 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
Harald Weltebfe62e52017-05-15 12:48:30 +0200246 uint16_t _bvci = osmo_htons(bctx->bvci);
Harald Welte85fc3142011-11-25 08:58:40 +0100247
248 LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx BVC-BLOCK "
Max2c34ab42016-03-17 15:42:26 +0100249 "CAUSE=%s\n", bctx->bvci, bssgp_cause_str(cause));
Harald Welte85fc3142011-11-25 08:58:40 +0100250
251 msgb_nsei(msg) = bctx->nsei;
252 msgb_bvci(msg) = 0; /* Signalling */
253 bgph->pdu_type = BSSGP_PDUT_BVC_BLOCK;
254
255 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
256 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause);
257
258 return gprs_ns_sendmsg(bssgp_nsi, msg);
259}
260
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200261/*! Transmit a BVC-UNBLOCK message (Chapter 10.4.10) */
Harald Welte85fc3142011-11-25 08:58:40 +0100262int bssgp_tx_bvc_unblock(struct bssgp_bvc_ctx *bctx)
263{
264 struct msgb *msg = bssgp_msgb_alloc();
265 struct bssgp_normal_hdr *bgph =
266 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
Harald Weltebfe62e52017-05-15 12:48:30 +0200267 uint16_t _bvci = osmo_htons(bctx->bvci);
Harald Welte85fc3142011-11-25 08:58:40 +0100268
269 LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx BVC-BLOCK\n", bctx->bvci);
270
271 msgb_nsei(msg) = bctx->nsei;
272 msgb_bvci(msg) = 0; /* Signalling */
273 bgph->pdu_type = BSSGP_PDUT_BVC_UNBLOCK;
274
275 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
276
277 return gprs_ns_sendmsg(bssgp_nsi, msg);
278}
279
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200280/*! Transmit a BVC-RESET message (Chapter 10.4.12) */
Harald Welte85fc3142011-11-25 08:58:40 +0100281int bssgp_tx_bvc_reset(struct bssgp_bvc_ctx *bctx, uint16_t bvci, uint8_t cause)
282{
283 struct msgb *msg = bssgp_msgb_alloc();
284 struct bssgp_normal_hdr *bgph =
285 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
Harald Weltebfe62e52017-05-15 12:48:30 +0200286 uint16_t _bvci = osmo_htons(bvci);
Harald Welte85fc3142011-11-25 08:58:40 +0100287
288 LOGP(DBSSGP, LOGL_NOTICE, "BSSGP (BVCI=%u) Tx BVC-RESET "
Max2c34ab42016-03-17 15:42:26 +0100289 "CAUSE=%s\n", bvci, bssgp_cause_str(cause));
Harald Welte85fc3142011-11-25 08:58:40 +0100290
291 msgb_nsei(msg) = bctx->nsei;
292 msgb_bvci(msg) = 0; /* Signalling */
293 bgph->pdu_type = BSSGP_PDUT_BVC_RESET;
294
295 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (uint8_t *) &_bvci);
296 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause);
297 if (bvci != BVCI_PTM) {
298 uint8_t bssgp_cid[8];
299 bssgp_create_cell_id(bssgp_cid, &bctx->ra_id, bctx->cell_id);
300 msgb_tvlv_put(msg, BSSGP_IE_CELL_ID, sizeof(bssgp_cid), bssgp_cid);
301 }
302 /* Optional: Feature Bitmap */
303
304 return gprs_ns_sendmsg(bssgp_nsi, msg);
305}
306
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200307/*! Transmit a FLOW_CONTROL-BVC (Chapter 10.4.4)
Harald Weltee92866b2012-09-10 08:56:04 +0200308 * \param[in] bctx BVC Context
Andreas Eversbergb8d18f32012-09-30 16:59:33 +0200309 * \param[in] tag Additional tag to identify acknowledge
Harald Weltee92866b2012-09-10 08:56:04 +0200310 * \param[in] bucket_size Maximum bucket size in octets
311 * \param[in] bucket_leak_rate Bucket leak rate in octets/sec
312 * \param[in] bmax_default_ms Maximum bucket size default for MS
313 * \param[in] r_default_ms Bucket leak rate default for MS in octets/sec
314 * \param[in] bucket_full_ratio Ratio (in percent) of queue filling
315 * \param[in] queue_delay_ms Average queuing delay in milliseconds
316 */
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200317int bssgp_tx_fc_bvc(struct bssgp_bvc_ctx *bctx, uint8_t tag,
Harald Weltee92866b2012-09-10 08:56:04 +0200318 uint32_t bucket_size, uint32_t bucket_leak_rate,
Jacob Erlbeck9385d1e2015-05-06 09:29:32 +0200319 uint32_t bmax_default_ms, uint32_t r_default_ms,
Harald Weltee92866b2012-09-10 08:56:04 +0200320 uint8_t *bucket_full_ratio, uint32_t *queue_delay_ms)
321{
322 struct msgb *msg;
323 struct bssgp_normal_hdr *bgph;
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200324 uint16_t e_bucket_size, e_leak_rate, e_bmax_default_ms, e_r_default_ms;
Harald Weltee92866b2012-09-10 08:56:04 +0200325 uint16_t e_queue_delay = 0; /* to make gcc happy */
326
327 if ((bucket_size / 100) > 0xffff)
328 return -EINVAL;
Harald Weltebfe62e52017-05-15 12:48:30 +0200329 e_bucket_size = osmo_htons(bucket_size / 100);
Harald Weltee92866b2012-09-10 08:56:04 +0200330
331 if ((bucket_leak_rate * 8 / 100) > 0xffff)
332 return -EINVAL;
Harald Weltebfe62e52017-05-15 12:48:30 +0200333 e_leak_rate = osmo_htons((bucket_leak_rate * 8) / 100);
Harald Weltee92866b2012-09-10 08:56:04 +0200334
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200335 if ((bmax_default_ms / 100) > 0xffff)
336 return -EINVAL;
Harald Weltebfe62e52017-05-15 12:48:30 +0200337 e_bmax_default_ms = osmo_htons(bmax_default_ms / 100);
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200338
Harald Weltee92866b2012-09-10 08:56:04 +0200339 if ((r_default_ms * 8 / 100) > 0xffff)
340 return -EINVAL;
Harald Weltebfe62e52017-05-15 12:48:30 +0200341 e_r_default_ms = osmo_htons((r_default_ms * 8) / 100);
Harald Weltee92866b2012-09-10 08:56:04 +0200342
343 if (queue_delay_ms) {
344 if ((*queue_delay_ms / 10) > 60000)
345 return -EINVAL;
346 else if (*queue_delay_ms == 0xFFFFFFFF)
347 e_queue_delay = 0xFFFF;
348 else
Harald Weltebfe62e52017-05-15 12:48:30 +0200349 e_queue_delay = osmo_htons(*queue_delay_ms / 10);
Harald Weltee92866b2012-09-10 08:56:04 +0200350 }
351
352 msg = bssgp_msgb_alloc();
353 bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
354 msgb_nsei(msg) = bctx->nsei;
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200355 msgb_bvci(msg) = bctx->bvci;
Harald Weltee92866b2012-09-10 08:56:04 +0200356 bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC;
357
358 msgb_tvlv_put(msg, BSSGP_IE_TAG, sizeof(tag), (uint8_t *)&tag);
359 msgb_tvlv_put(msg, BSSGP_IE_BVC_BUCKET_SIZE,
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200360 sizeof(e_bucket_size), (uint8_t *) &e_bucket_size);
Harald Weltee92866b2012-09-10 08:56:04 +0200361 msgb_tvlv_put(msg, BSSGP_IE_BUCKET_LEAK_RATE,
362 sizeof(e_leak_rate), (uint8_t *) &e_leak_rate);
363 msgb_tvlv_put(msg, BSSGP_IE_BMAX_DEFAULT_MS,
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200364 sizeof(e_bmax_default_ms),
365 (uint8_t *) &e_bmax_default_ms);
Harald Weltee92866b2012-09-10 08:56:04 +0200366 msgb_tvlv_put(msg, BSSGP_IE_R_DEFAULT_MS,
367 sizeof(e_r_default_ms), (uint8_t *) &e_r_default_ms);
368 if (bucket_full_ratio)
369 msgb_tvlv_put(msg, BSSGP_IE_BUCKET_FULL_RATIO,
370 1, bucket_full_ratio);
371 if (queue_delay_ms)
372 msgb_tvlv_put(msg, BSSGP_IE_BVC_MEASUREMENT,
373 sizeof(e_queue_delay),
374 (uint8_t *) &e_queue_delay);
375
376 return gprs_ns_sendmsg(bssgp_nsi, msg);
377}
378
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200379/*! Transmit a FLOW_CONTROL-MS (Chapter 10.4.6)
Harald Weltee92866b2012-09-10 08:56:04 +0200380 * \param[in] bctx BVC Context
Andreas Eversbergb8d18f32012-09-30 16:59:33 +0200381 * \param[in] tlli TLLI to identify MS
382 * \param[in] tag Additional tag to identify acknowledge
Harald Weltee92866b2012-09-10 08:56:04 +0200383 * \param[in] ms_bucket_size Maximum bucket size in octets
384 * \param[in] bucket_leak_rate Bucket leak rate in octets/sec
385 * \param[in] bucket_full_ratio Ratio (in percent) of queue filling
386 */
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200387int bssgp_tx_fc_ms(struct bssgp_bvc_ctx *bctx, uint32_t tlli, uint8_t tag,
Harald Weltee92866b2012-09-10 08:56:04 +0200388 uint32_t ms_bucket_size, uint32_t bucket_leak_rate,
389 uint8_t *bucket_full_ratio)
390{
391 struct msgb *msg;
392 struct bssgp_normal_hdr *bgph;
393 uint16_t e_bucket_size, e_leak_rate;
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200394 uint32_t e_tlli;
Harald Weltee92866b2012-09-10 08:56:04 +0200395
396 if ((ms_bucket_size / 100) > 0xffff)
397 return -EINVAL;
398 e_bucket_size = ms_bucket_size / 100;
399
400 if ((bucket_leak_rate * 8 / 100) > 0xffff)
401 return -EINVAL;
402 e_leak_rate = (bucket_leak_rate * 8) / 100;
403
404 msg = bssgp_msgb_alloc();
405 bgph = (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
406 msgb_nsei(msg) = bctx->nsei;
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200407 msgb_bvci(msg) = bctx->bvci;
Harald Weltee92866b2012-09-10 08:56:04 +0200408 bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_MS;
409
Harald Weltebfe62e52017-05-15 12:48:30 +0200410 e_tlli = osmo_htonl(tlli);
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200411 msgb_tvlv_put(msg, BSSGP_IE_TLLI, sizeof(e_tlli), (uint8_t *)&e_tlli);
Harald Weltee92866b2012-09-10 08:56:04 +0200412 msgb_tvlv_put(msg, BSSGP_IE_TAG, sizeof(tag), (uint8_t *)&tag);
413 msgb_tvlv_put(msg, BSSGP_IE_MS_BUCKET_SIZE,
414 sizeof(e_bucket_size), (uint8_t *) &e_bucket_size);
415 msgb_tvlv_put(msg, BSSGP_IE_BUCKET_LEAK_RATE,
416 sizeof(e_leak_rate), (uint8_t *) &e_leak_rate);
417 if (bucket_full_ratio)
418 msgb_tvlv_put(msg, BSSGP_IE_BUCKET_FULL_RATIO,
419 1, bucket_full_ratio);
420
421 return gprs_ns_sendmsg(bssgp_nsi, msg);
422}
Harald Welte85fc3142011-11-25 08:58:40 +0100423
Neels Hofmeyr87e45502017-06-20 00:17:59 +0200424/*! RL-UL-UNITDATA.req (Chapter 10.2.2)
Andreas Eversbergb8d18f32012-09-30 16:59:33 +0200425 * \param[in] bctx BVC Context
426 * \param[in] tlli TLLI to identify MS
427 * \param[in] qos_profile Pointer to three octests of QoS profile
428 * \param[in] llc_pdu msgb pointer containing UL Unitdata IE payload
429 */
Harald Welte85fc3142011-11-25 08:58:40 +0100430int bssgp_tx_ul_ud(struct bssgp_bvc_ctx *bctx, uint32_t tlli,
431 const uint8_t *qos_profile, struct msgb *llc_pdu)
432{
433 struct msgb *msg = llc_pdu;
434 uint8_t bssgp_cid[8];
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200435 uint8_t bssgp_align[3] = {0, 0, 0};
Harald Welte85fc3142011-11-25 08:58:40 +0100436 struct bssgp_ud_hdr *budh;
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200437 int align = sizeof(*budh);
Harald Welte85fc3142011-11-25 08:58:40 +0100438
439 /* FIXME: Optional LSA Identifier List, PFI */
440
441 /* Cell Identifier */
442 bssgp_create_cell_id(bssgp_cid, &bctx->ra_id, bctx->cell_id);
Andreas Eversbergf44ed8c2012-09-23 06:05:20 +0200443 align += 2; /* add T+L */
444 align += sizeof(bssgp_cid);
445
446 /* First push alignment IE */
447 align += 2; /* add T+L */
448 align = (4 - align) & 3; /* how many octest are required to align? */
449 msgb_tvlv_push(msg, BSSGP_IE_ALIGNMENT, align, bssgp_align);
450
451 /* Push other IEs */
Harald Welte85fc3142011-11-25 08:58:40 +0100452 msgb_tvlv_push(msg, BSSGP_IE_CELL_ID, sizeof(bssgp_cid), bssgp_cid);
453
454 /* User Data Header */
455 budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh));
Harald Weltebfe62e52017-05-15 12:48:30 +0200456 budh->tlli = osmo_htonl(tlli);
Harald Welte85fc3142011-11-25 08:58:40 +0100457 memcpy(budh->qos_profile, qos_profile, 3);
458 budh->pdu_type = BSSGP_PDUT_UL_UNITDATA;
459
460 /* set NSEI and BVCI in msgb cb */
461 msgb_nsei(msg) = bctx->nsei;
462 msgb_bvci(msg) = bctx->bvci;
463
464 rate_ctr_inc(&bctx->ctrg->ctr[BSSGP_CTR_PKTS_OUT]);
465 rate_ctr_add(&bctx->ctrg->ctr[BSSGP_CTR_BYTES_OUT], msg->len);
466
467 return gprs_ns_sendmsg(bssgp_nsi, msg);
468}
469
470/* Parse a single GMM-PAGING.req to a given NSEI/NS-BVCI */
Harald Weltede4599c2012-06-17 13:04:02 +0800471int bssgp_rx_paging(struct bssgp_paging_info *pinfo,
472 struct msgb *msg)
Harald Welte85fc3142011-11-25 08:58:40 +0100473{
474 struct bssgp_normal_hdr *bgph =
475 (struct bssgp_normal_hdr *) msgb_bssgph(msg);
476 struct tlv_parsed tp;
477 uint8_t ra[6];
478 int rc, data_len;
479
480 memset(ra, 0, sizeof(ra));
481
482 data_len = msgb_bssgp_len(msg) - sizeof(*bgph);
483 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
484 if (rc < 0)
485 goto err_mand_ie;
486
487 switch (bgph->pdu_type) {
488 case BSSGP_PDUT_PAGING_PS:
489 pinfo->mode = BSSGP_PAGING_PS;
490 break;
491 case BSSGP_PDUT_PAGING_CS:
492 pinfo->mode = BSSGP_PAGING_CS;
493 break;
494 default:
495 return -EINVAL;
496 }
497
498 /* IMSI */
499 if (!TLVP_PRESENT(&tp, BSSGP_IE_IMSI))
500 goto err_mand_ie;
501 if (!pinfo->imsi)
Jacob Erlbeckc1cb75e2015-06-18 13:21:30 +0200502 pinfo->imsi = talloc_zero_size(pinfo, GSM_IMSI_LENGTH);
503 gsm48_mi_to_string(pinfo->imsi, GSM_IMSI_LENGTH,
Harald Welte85fc3142011-11-25 08:58:40 +0100504 TLVP_VAL(&tp, BSSGP_IE_IMSI),
505 TLVP_LEN(&tp, BSSGP_IE_IMSI));
506
507 /* DRX Parameters */
508 if (!TLVP_PRESENT(&tp, BSSGP_IE_DRX_PARAMS))
509 goto err_mand_ie;
Harald Weltebfe62e52017-05-15 12:48:30 +0200510 pinfo->drx_params = tlvp_val16be(&tp, BSSGP_IE_DRX_PARAMS);
Harald Welte85fc3142011-11-25 08:58:40 +0100511
512 /* Scope */
513 if (TLVP_PRESENT(&tp, BSSGP_IE_BSS_AREA_ID)) {
514 pinfo->scope = BSSGP_PAGING_BSS_AREA;
515 } else if (TLVP_PRESENT(&tp, BSSGP_IE_LOCATION_AREA)) {
516 pinfo->scope = BSSGP_PAGING_LOCATION_AREA;
517 memcpy(ra, TLVP_VAL(&tp, BSSGP_IE_LOCATION_AREA),
518 TLVP_LEN(&tp, BSSGP_IE_LOCATION_AREA));
519 gsm48_parse_ra(&pinfo->raid, ra);
520 } else if (TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA)) {
521 pinfo->scope = BSSGP_PAGING_ROUTEING_AREA;
522 memcpy(ra, TLVP_VAL(&tp, BSSGP_IE_ROUTEING_AREA),
523 TLVP_LEN(&tp, BSSGP_IE_ROUTEING_AREA));
524 gsm48_parse_ra(&pinfo->raid, ra);
525 } else if (TLVP_PRESENT(&tp, BSSGP_IE_BVCI)) {
526 pinfo->scope = BSSGP_PAGING_BVCI;
Harald Weltebfe62e52017-05-15 12:48:30 +0200527 pinfo->bvci = tlvp_val16be(&tp, BSSGP_IE_BVCI);
Harald Welte85fc3142011-11-25 08:58:40 +0100528 } else
529 return -EINVAL;
530
531 /* QoS profile mandatory for PS */
532 if (pinfo->mode == BSSGP_PAGING_PS) {
533 if (!TLVP_PRESENT(&tp, BSSGP_IE_QOS_PROFILE))
534 goto err_cond_ie;
535 if (TLVP_LEN(&tp, BSSGP_IE_QOS_PROFILE) < 3)
536 goto err;
537
538 memcpy(&pinfo->qos, TLVP_VAL(&tp, BSSGP_IE_QOS_PROFILE),
539 3);
540 }
541
542 /* Optional (P-)TMSI */
543 if (TLVP_PRESENT(&tp, BSSGP_IE_TMSI) &&
Harald Welte6176b6e2016-11-11 15:10:33 +0100544 TLVP_LEN(&tp, BSSGP_IE_TMSI) >= 4) {
Harald Welte85fc3142011-11-25 08:58:40 +0100545 if (!pinfo->ptmsi)
546 pinfo->ptmsi = talloc_zero_size(pinfo, sizeof(uint32_t));
Harald Weltebfe62e52017-05-15 12:48:30 +0200547 *(pinfo->ptmsi) = osmo_load32be(TLVP_VAL(&tp, BSSGP_IE_TMSI));
Harald Welte6176b6e2016-11-11 15:10:33 +0100548 }
Harald Welte85fc3142011-11-25 08:58:40 +0100549
550 return 0;
551
552err_mand_ie:
553err_cond_ie:
554err:
555 /* FIXME */
556 return 0;
557}