blob: 650d7d45d33d2629abf69f8020ae9e5b0d0e3e43 [file] [log] [blame]
Harald Welte9ba50052010-03-14 15:45:01 +08001/* GPRS BSSGP protocol implementation as per 3GPP TS 08.18 */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 *
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * 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
10 * (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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <errno.h>
24#include <sys/types.h>
25
26#include <netinet/in.h>
27
28#include <osmocore/msgb.h>
29#include <osmocore/tlv.h>
30#include <openbsc/debug.h>
31#include <openbsc/gsm_data.h>
32#include <openbsc/gsm_04_08_gprs.h>
33#include <openbsc/gprs_bssgp.h>
34#include <openbsc/gprs_llc.h>
35#include <openbsc/gprs_ns.h>
36
37/* global pointer to the gsm network data structure */
38/* FIXME: this must go! */
39extern struct gsm_network *bsc_gsmnet;
Harald Welte24a655f2010-04-30 19:54:29 +020040struct gprs_ns_inst *bssgp_nsi;
Harald Welte9ba50052010-03-14 15:45:01 +080041
42/* Chapter 11.3.9 / Table 11.10: Cause coding */
43static const char *bssgp_cause_strings[] = {
44 [BSSGP_CAUSE_PROC_OVERLOAD] = "Processor overload",
45 [BSSGP_CAUSE_EQUIP_FAIL] = "Equipment Failure",
46 [BSSGP_CAUSE_TRASIT_NET_FAIL] = "Transit netowkr service failure",
47 [BSSGP_CAUSE_CAPA_GREATER_0KPBS]= "Transmission capacity modified",
48 [BSSGP_CAUSE_UNKNOWN_MS] = "Unknown MS",
49 [BSSGP_CAUSE_UNKNOWN_BVCI] = "Unknown BVCI",
50 [BSSGP_CAUSE_CELL_TRAF_CONG] = "Cell traffic congestion",
51 [BSSGP_CAUSE_SGSN_CONG] = "SGSN congestion",
52 [BSSGP_CAUSE_OML_INTERV] = "O&M intervention",
53 [BSSGP_CAUSE_BVCI_BLOCKED] = "BVCI blocked",
54 [BSSGP_CAUSE_PFC_CREATE_FAIL] = "PFC create failure",
55 [BSSGP_CAUSE_SEM_INCORR_PDU] = "Semantically incorrect PDU",
56 [BSSGP_CAUSE_INV_MAND_INF] = "Invalid mandatory information",
57 [BSSGP_CAUSE_MISSING_MAND_IE] = "Missing mandatory IE",
58 [BSSGP_CAUSE_MISSING_COND_IE] = "Missing conditional IE",
59 [BSSGP_CAUSE_UNEXP_COND_IE] = "Unexpected conditional IE",
60 [BSSGP_CAUSE_COND_IE_ERR] = "Conditional IE error",
61 [BSSGP_CAUSE_PDU_INCOMP_STATE] = "PDU incompatible with protocol state",
62 [BSSGP_CAUSE_PROTO_ERR_UNSPEC] = "Protocol error - unspecified",
63 [BSSGP_CAUSE_PDU_INCOMP_FEAT] = "PDU not compatible with feature set",
64};
65
66static const char *bssgp_cause_str(enum gprs_bssgp_cause cause)
67{
68 if (cause >= ARRAY_SIZE(bssgp_cause_strings))
69 return "undefined";
70
71 if (bssgp_cause_strings[cause])
72 return bssgp_cause_strings[cause];
73
74 return "undefined";
75}
76
77static inline int bssgp_tlv_parse(struct tlv_parsed *tp, u_int8_t *buf, int len)
78{
79 return tlv_parse(tp, &tvlv_att_def, buf, len, 0, 0);
80}
81
82static inline struct msgb *bssgp_msgb_alloc(void)
83{
84 return msgb_alloc_headroom(4096, 128, "BSSGP");
85}
86
87/* Transmit a simple response such as BLOCK/UNBLOCK/RESET ACK/NACK */
Harald Welte24a655f2010-04-30 19:54:29 +020088static int bssgp_tx_simple_bvci(u_int8_t pdu_type, u_int16_t nsei,
89 u_int16_t bvci, u_int16_t ns_bvci)
Harald Welte9ba50052010-03-14 15:45:01 +080090{
91 struct msgb *msg = bssgp_msgb_alloc();
92 struct bssgp_normal_hdr *bgph =
93 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
94 u_int16_t _bvci;
95
Harald Welte24a655f2010-04-30 19:54:29 +020096 msgb_nsei(msg) = nsei;
97 msgb_bvci(msg) = ns_bvci;
98
Harald Welte9ba50052010-03-14 15:45:01 +080099 bgph->pdu_type = pdu_type;
100 _bvci = htons(bvci);
101 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci);
102
Harald Welte24a655f2010-04-30 19:54:29 +0200103 return gprs_ns_sendmsg(bssgp_nsi, msg);
Harald Welte9ba50052010-03-14 15:45:01 +0800104}
105
106/* Chapter 10.4.5: Flow Control BVC ACK */
Harald Welte24a655f2010-04-30 19:54:29 +0200107static int bssgp_tx_fc_bvc_ack(u_int16_t nsei, u_int8_t tag, u_int16_t ns_bvci)
Harald Welte9ba50052010-03-14 15:45:01 +0800108{
109 struct msgb *msg = bssgp_msgb_alloc();
110 struct bssgp_normal_hdr *bgph =
111 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
112
Harald Welte24a655f2010-04-30 19:54:29 +0200113 msgb_nsei(msg) = nsei;
114 msgb_bvci(msg) = ns_bvci;
115
Harald Welte9ba50052010-03-14 15:45:01 +0800116 bgph->pdu_type = BSSGP_PDUT_FLOW_CONTROL_BVC_ACK;
117 msgb_tvlv_put(msg, BSSGP_IE_TAG, 1, &tag);
118
Harald Welte24a655f2010-04-30 19:54:29 +0200119 return gprs_ns_sendmsg(bssgp_nsi, msg);
Harald Welte9ba50052010-03-14 15:45:01 +0800120}
121
122/* Chapter 10.4.14: Status */
123static int bssgp_tx_status(u_int8_t cause, u_int16_t *bvci, struct msgb *orig_msg)
124{
125 struct msgb *msg = bssgp_msgb_alloc();
126 struct bssgp_normal_hdr *bgph =
127 (struct bssgp_normal_hdr *) msgb_put(msg, sizeof(*bgph));
128
129 DEBUGPC(DGPRS, "BSSGP: TX STATUS, cause=%s\n", bssgp_cause_str(cause));
Harald Welte24a655f2010-04-30 19:54:29 +0200130 msgb_nsei(msg) = msgb_nsei(orig_msg);
131 msgb_bvci(msg) = 0;
Harald Welte9ba50052010-03-14 15:45:01 +0800132
133 bgph->pdu_type = BSSGP_PDUT_STATUS;
134 msgb_tvlv_put(msg, BSSGP_IE_CAUSE, 1, &cause);
135 if (bvci) {
136 u_int16_t _bvci = htons(*bvci);
137 msgb_tvlv_put(msg, BSSGP_IE_BVCI, 2, (u_int8_t *) &_bvci);
138 }
139 if (orig_msg)
140 msgb_tvlv_put(msg, BSSGP_IE_PDU_IN_ERROR,
141 msgb_l3len(orig_msg), orig_msg->l3h);
142
Harald Welte24a655f2010-04-30 19:54:29 +0200143 return gprs_ns_sendmsg(bssgp_nsi, msg);
Harald Welte9ba50052010-03-14 15:45:01 +0800144}
145
146/* Uplink unit-data */
147static int bssgp_rx_ul_ud(struct msgb *msg, u_int16_t bvci)
148{
149 struct bssgp_ud_hdr *budh = (struct bssgp_ud_hdr *) msg->l3h;
150 struct gsm_bts *bts;
151 int data_len = msgb_l3len(msg) - sizeof(*budh);
152 struct tlv_parsed tp;
153 int rc;
154
155 DEBUGP(DGPRS, "BSSGP UL-UD\n");
156
Harald Welte510c3922010-04-30 16:33:12 +0200157 msgb_tlli(msg) = ntohl(budh->tlli);
Harald Welte9ba50052010-03-14 15:45:01 +0800158 rc = bssgp_tlv_parse(&tp, budh->data, data_len);
159
160 /* Cell ID and LLC_PDU are the only mandatory IE */
161 if (!TLVP_PRESENT(&tp, BSSGP_IE_CELL_ID) ||
162 !TLVP_PRESENT(&tp, BSSGP_IE_LLC_PDU))
163 return -EIO;
164
165 /* Determine the BTS based on the Cell ID */
166 bts = gsm48_bts_by_ra_id(bsc_gsmnet,
167 TLVP_VAL(&tp, BSSGP_IE_CELL_ID),
168 TLVP_LEN(&tp, BSSGP_IE_CELL_ID));
169 if (bts)
170 msg->trx = bts->c0;
171
Harald Welte510c3922010-04-30 16:33:12 +0200172 msgb_llch(msg) = TLVP_VAL(&tp, BSSGP_IE_LLC_PDU);
Harald Welte9ba50052010-03-14 15:45:01 +0800173
174 return gprs_llc_rcvmsg(msg, &tp);
175}
176
177static int bssgp_rx_suspend(struct msgb *msg, u_int16_t bvci)
178{
179 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
180 int data_len = msgb_l3len(msg) - sizeof(*bgph);
181 struct tlv_parsed tp;
182 int rc;
183
184 DEBUGP(DGPRS, "BSSGP SUSPEND\n");
185
186 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
187 if (rc < 0)
188 return rc;
189
190 if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) ||
191 !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA))
192 return -EIO;
193
194 /* SEND SUSPEND_ACK or SUSPEND_NACK */
195 /* FIXME */
196}
197
198static int bssgp_rx_resume(struct msgb *msg, u_int16_t bvci)
199{
200 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
201 int data_len = msgb_l3len(msg) - sizeof(*bgph);
202 struct tlv_parsed tp;
203 int rc;
204
205 DEBUGP(DGPRS, "BSSGP RESUME\n");
206
207 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
208 if (rc < 0)
209 return rc;
210
211 if (!TLVP_PRESENT(&tp, BSSGP_IE_TLLI) ||
212 !TLVP_PRESENT(&tp, BSSGP_IE_ROUTEING_AREA) ||
213 !TLVP_PRESENT(&tp, BSSGP_IE_SUSPEND_REF_NR))
214 return -EIO;
215
216 /* SEND RESUME_ACK or RESUME_NACK */
217 /* FIXME */
218}
219
220static int bssgp_rx_fc_bvc(struct msgb *msg, struct tlv_parsed *tp,
221 u_int16_t ns_bvci)
222{
223
224 DEBUGP(DGPRS, "BSSGP FC BVC\n");
225
226 if (!TLVP_PRESENT(tp, BSSGP_IE_TAG) ||
227 !TLVP_PRESENT(tp, BSSGP_IE_BVC_BUCKET_SIZE) ||
228 !TLVP_PRESENT(tp, BSSGP_IE_BUCKET_LEAK_RATE) ||
229 !TLVP_PRESENT(tp, BSSGP_IE_BMAX_DEFAULT_MS) ||
230 !TLVP_PRESENT(tp, BSSGP_IE_R_DEFAULT_MS))
231 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
232
233 /* Send FLOW_CONTROL_BVC_ACK */
Harald Welte24a655f2010-04-30 19:54:29 +0200234 return bssgp_tx_fc_bvc_ack(msgb_nsei(msg), *TLVP_VAL(tp, BSSGP_IE_TAG),
235 ns_bvci);
Harald Welte9ba50052010-03-14 15:45:01 +0800236}
237/* We expect msg->l3h to point to the BSSGP header */
238int gprs_bssgp_rcvmsg(struct msgb *msg, u_int16_t ns_bvci)
239{
240 struct bssgp_normal_hdr *bgph = (struct bssgp_normal_hdr *) msg->l3h;
241 struct tlv_parsed tp;
242 u_int8_t pdu_type = bgph->pdu_type;
243 int data_len = msgb_l3len(msg) - sizeof(*bgph);
244 u_int16_t bvci;
245 int rc = 0;
246
247 if (pdu_type != BSSGP_PDUT_UL_UNITDATA &&
248 pdu_type != BSSGP_PDUT_DL_UNITDATA)
249 rc = bssgp_tlv_parse(&tp, bgph->data, data_len);
250
251 switch (pdu_type) {
252 case BSSGP_PDUT_UL_UNITDATA:
253 /* some LLC data from the MS */
254 rc = bssgp_rx_ul_ud(msg, ns_bvci);
255 break;
256 case BSSGP_PDUT_RA_CAPABILITY:
257 /* BSS requests RA capability or IMSI */
258 DEBUGP(DGPRS, "BSSGP RA CAPABILITY UPDATE\n");
259 /* FIXME: send RA_CAPA_UPDATE_ACK */
260 break;
261 case BSSGP_PDUT_RADIO_STATUS:
262 DEBUGP(DGPRS, "BSSGP RADIO STATUS\n");
263 /* BSS informs us of some exception */
264 break;
265 case BSSGP_PDUT_SUSPEND:
266 /* MS wants to suspend */
267 rc = bssgp_rx_suspend(msg, ns_bvci);
268 break;
269 case BSSGP_PDUT_RESUME:
270 /* MS wants to resume */
271 rc = bssgp_rx_resume(msg, ns_bvci);
272 break;
273 case BSSGP_PDUT_FLUSH_LL:
274 /* BSS informs MS has moved to one cell to other cell */
275 DEBUGP(DGPRS, "BSSGP FLUSH LL\n");
276 /* Send FLUSH_LL_ACK */
277 break;
278 case BSSGP_PDUT_LLC_DISCARD:
279 /* BSS informs that some LLC PDU's have been discarded */
280 DEBUGP(DGPRS, "BSSGP LLC DISCARDED\n");
281 break;
282 case BSSGP_PDUT_FLOW_CONTROL_BVC:
283 /* BSS informs us of available bandwidth in Gb interface */
284 rc = bssgp_rx_fc_bvc(msg, &tp, ns_bvci);
285 break;
286 case BSSGP_PDUT_FLOW_CONTROL_MS:
287 /* BSS informs us of available bandwidth to one MS */
288 DEBUGP(DGPRS, "BSSGP FC MS\n");
289 /* Send FLOW_CONTROL_MS_ACK */
290 break;
291 case BSSGP_PDUT_BVC_BLOCK:
292 /* BSS tells us that BVC shall be blocked */
293 DEBUGP(DGPRS, "BSSGP BVC BLOCK ");
294 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) ||
295 !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE))
296 goto err_mand_ie;
297 bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
298 DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci,
299 bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE)));
300 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_BLOCK_ACK,
Harald Welte24a655f2010-04-30 19:54:29 +0200301 msgb_nsei(msg), bvci, ns_bvci);
Harald Welte9ba50052010-03-14 15:45:01 +0800302 break;
303 case BSSGP_PDUT_BVC_UNBLOCK:
304 /* BSS tells us that BVC shall be unblocked */
305 DEBUGP(DGPRS, "BSSGP BVC UNBLOCK ");
306 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI))
307 goto err_mand_ie;
308 bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
309 DEBUGPC(DGPRS, "BVCI=%u\n", bvci);
310 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_UNBLOCK_ACK,
Harald Welte24a655f2010-04-30 19:54:29 +0200311 msgb_nsei(msg), bvci, ns_bvci);
Harald Welte9ba50052010-03-14 15:45:01 +0800312 break;
313 case BSSGP_PDUT_BVC_RESET:
314 /* BSS tells us that BVC init is required */
315 DEBUGP(DGPRS, "BSSGP BVC RESET ");
316 if (!TLVP_PRESENT(&tp, BSSGP_IE_BVCI) ||
317 !TLVP_PRESENT(&tp, BSSGP_IE_CAUSE))
318 goto err_mand_ie;
319 bvci = ntohs(*(u_int16_t *)TLVP_VAL(&tp, BSSGP_IE_BVCI));
320 DEBUGPC(DGPRS, "BVCI=%u, cause=%s\n", bvci,
321 bssgp_cause_str(*TLVP_VAL(&tp, BSSGP_IE_CAUSE)));
322 rc = bssgp_tx_simple_bvci(BSSGP_PDUT_BVC_RESET_ACK,
Harald Welte24a655f2010-04-30 19:54:29 +0200323 msgb_nsei(msg), bvci, ns_bvci);
Harald Welte9ba50052010-03-14 15:45:01 +0800324 break;
325 case BSSGP_PDUT_STATUS:
326 /* Some exception has occurred */
327 case BSSGP_PDUT_DOWNLOAD_BSS_PFC:
328 case BSSGP_PDUT_CREATE_BSS_PFC_ACK:
329 case BSSGP_PDUT_CREATE_BSS_PFC_NACK:
330 case BSSGP_PDUT_MODIFY_BSS_PFC:
331 case BSSGP_PDUT_DELETE_BSS_PFC_ACK:
332 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x not [yet] implemented\n",
333 pdu_type);
334 break;
335 /* those only exist in the SGSN -> BSS direction */
336 case BSSGP_PDUT_DL_UNITDATA:
337 case BSSGP_PDUT_PAGING_PS:
338 case BSSGP_PDUT_PAGING_CS:
339 case BSSGP_PDUT_RA_CAPA_UPDATE_ACK:
340 case BSSGP_PDUT_SUSPEND_ACK:
341 case BSSGP_PDUT_SUSPEND_NACK:
342 case BSSGP_PDUT_RESUME_ACK:
343 case BSSGP_PDUT_RESUME_NACK:
344 case BSSGP_PDUT_FLUSH_LL_ACK:
345 case BSSGP_PDUT_FLOW_CONTROL_BVC_ACK:
346 case BSSGP_PDUT_FLOW_CONTROL_MS_ACK:
347 case BSSGP_PDUT_BVC_BLOCK_ACK:
348 case BSSGP_PDUT_BVC_UNBLOCK_ACK:
349 case BSSGP_PDUT_SGSN_INVOKE_TRACE:
350 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x only exists in DL\n",
351 pdu_type);
352 rc = -EINVAL;
353 break;
354 default:
355 DEBUGP(DGPRS, "BSSGP PDU type 0x%02x unknown\n", pdu_type);
356 break;
357 }
358
359 return rc;
360err_mand_ie:
361 return bssgp_tx_status(BSSGP_CAUSE_MISSING_MAND_IE, NULL, msg);
362}
363
364int gprs_bssgp_tx_dl_ud(struct msgb *msg)
365{
366 struct gsm_bts *bts;
367 struct bssgp_ud_hdr *budh;
368 u_int8_t llc_pdu_tlv_hdr_len = 2;
369 u_int8_t *llc_pdu_tlv, *qos_profile;
370 u_int16_t pdu_lifetime = 1000; /* centi-seconds */
371 u_int8_t qos_profile_default[3] = { 0x00, 0x00, 0x21 };
372 u_int16_t msg_len = msg->len;
373
374 if (!msg->trx) {
375 DEBUGP(DGPRS, "Cannot transmit DL-UD without TRX assigned\n");
376 return -EINVAL;
377 }
378
379 bts = msg->trx->bts;
380
381 if (msg->len > TVLV_MAX_ONEBYTE)
382 llc_pdu_tlv_hdr_len += 1;
383
384 /* prepend the tag and length of the LLC-PDU TLV */
385 llc_pdu_tlv = msgb_push(msg, llc_pdu_tlv_hdr_len);
386 llc_pdu_tlv[0] = BSSGP_IE_LLC_PDU;
387 if (llc_pdu_tlv_hdr_len > 2) {
388 llc_pdu_tlv[1] = msg_len >> 8;
389 llc_pdu_tlv[2] = msg_len & 0xff;
390 } else {
391 llc_pdu_tlv[1] = msg_len & 0x3f;
392 llc_pdu_tlv[1] |= 0x80;
393 }
394
395 /* FIXME: optional elements */
396
397 /* prepend the pdu lifetime */
398 pdu_lifetime = htons(pdu_lifetime);
399 msgb_tvlv_push(msg, BSSGP_IE_PDU_LIFETIME, 2, (u_int8_t *)&pdu_lifetime);
400
401 /* prepend the QoS profile, TLLI and pdu type */
402 budh = (struct bssgp_ud_hdr *) msgb_push(msg, sizeof(*budh));
403 memcpy(budh->qos_profile, qos_profile_default, sizeof(qos_profile_default));
Harald Welte510c3922010-04-30 16:33:12 +0200404 budh->tlli = htonl(msgb_tlli(msg));
Harald Welte9ba50052010-03-14 15:45:01 +0800405 budh->pdu_type = BSSGP_PDUT_DL_UNITDATA;
406
Harald Welte24a655f2010-04-30 19:54:29 +0200407 msgb_nsei(msg) = bts->gprs.nse.nsei;
408 msgb_bvci(msg) = bts->gprs.cell.bvci;
409
410 return gprs_ns_sendmsg(bssgp_nsi, msg);
Harald Welte9ba50052010-03-14 15:45:01 +0800411}