blob: 39738a5ee1dff800242816bfed3a5a15913250ee [file] [log] [blame]
Jonathan Santos03fd8d02011-05-25 13:54:02 -04001/* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface
2 * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */
3
4/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
5 * (C) 2008, 2009, 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009 by Mike Haben <michael.haben@btinternet.com>
7 *
8 * All Rights Reserved
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU Affero General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Affero General Public License for more details.
19 *
20 * You should have received a copy of the GNU Affero General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <string.h>
29#include <errno.h>
30
31#include <openbsc/debug.h>
32#include <openbsc/gsm_data.h>
33#include <openbsc/gsm_04_08.h>
34#include <openbsc/gsm_04_80.h>
35#include <openbsc/bsc_api.h>
36
Jonathan Santos5a45b152011-08-17 15:33:57 -040037#include <osmocom/gsm/gsm0480.h>
38#include <osmocom/gsm/gsm_utils.h>
39#include <osmocom/core/msgb.h>
40#include <osmocom/gsm/tlv.h>
Jonathan Santos03fd8d02011-05-25 13:54:02 -040041
Jonathan Santos5a45b152011-08-17 15:33:57 -040042static inline unsigned char *msgb_wrap_with_TL(struct msgb *msgb, uint8_t tag)
Jonathan Santos03fd8d02011-05-25 13:54:02 -040043{
44 uint8_t *data = msgb_push(msgb, 2);
45
46 data[0] = tag;
47 data[1] = msgb->len - 2;
48 return data;
49}
50
Jonathan Santos5a45b152011-08-17 15:33:57 -040051static inline unsigned char *msgb_push_TLV1(struct msgb *msgb, uint8_t tag,
52 uint8_t value)
Jonathan Santos03fd8d02011-05-25 13:54:02 -040053{
54 uint8_t *data = msgb_push(msgb, 3);
55
56 data[0] = tag;
57 data[1] = 1;
58 data[2] = value;
59 return data;
60}
61
62
63/* Send response to a mobile-originated ProcessUnstructuredSS-Request */
64int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn,
65 const struct msgb *in_msg, const char *response_text,
66 const struct ussd_request *req)
67{
68 struct msgb *msg = gsm48_msgb_alloc();
69 struct gsm48_hdr *gh;
Jonathan Santos5a45b152011-08-17 15:33:57 -040070 uint8_t *ptr8;
Jonathan Santos03fd8d02011-05-25 13:54:02 -040071 int response_len;
72
73 /* First put the payload text into the message */
74 ptr8 = msgb_put(msg, 0);
75 response_len = gsm_7bit_encode(ptr8, response_text);
76 msgb_put(msg, response_len);
77
78 /* Then wrap it as an Octet String */
79 msgb_wrap_with_TL(msg, ASN1_OCTET_STRING_TAG);
80
81 /* Pre-pend the DCS octet string */
82 msgb_push_TLV1(msg, ASN1_OCTET_STRING_TAG, 0x0F);
83
84 /* Then wrap these as a Sequence */
85 msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG);
86
87 /* Pre-pend the operation code */
88 msgb_push_TLV1(msg, GSM0480_OPERATION_CODE,
89 GSM0480_OP_CODE_PROCESS_USS_REQ);
90
91 /* Wrap the operation code and IA5 string as a sequence */
92 msgb_wrap_with_TL(msg, GSM_0480_SEQUENCE_TAG);
93
94 /* Pre-pend the invoke ID */
95 msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
96
97 /* Wrap this up as a Return Result component */
98 msgb_wrap_with_TL(msg, GSM0480_CTYPE_RETURN_RESULT);
99
100 /* Wrap the component in a Facility message */
101 msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
102
103 /* And finally pre-pend the L3 header */
104 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
105 gh->proto_discr = GSM48_PDISC_NC_SS | req->transaction_id
106 | (1<<7); /* TI direction = 1 */
107 gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
108
109 return gsm0808_submit_dtap(conn, msg, 0, 0);
110}
111
112int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn,
113 const struct msgb *in_msg,
114 const struct ussd_request *req)
115{
116 struct msgb *msg = gsm48_msgb_alloc();
117 struct gsm48_hdr *gh;
118
119 /* First insert the problem code */
120 msgb_push_TLV1(msg, GSM_0480_PROBLEM_CODE_TAG_GENERAL,
121 GSM_0480_GEN_PROB_CODE_UNRECOGNISED);
122
123 /* Before it insert the invoke ID */
124 msgb_push_TLV1(msg, GSM0480_COMPIDTAG_INVOKE_ID, req->invoke_id);
125
126 /* Wrap this up as a Reject component */
127 msgb_wrap_with_TL(msg, GSM0480_CTYPE_REJECT);
128
129 /* Wrap the component in a Facility message */
130 msgb_wrap_with_TL(msg, GSM0480_IE_FACILITY);
131
132 /* And finally pre-pend the L3 header */
133 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
134 gh->proto_discr = GSM48_PDISC_NC_SS;
135 gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */
136 gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
137
138 return gsm0808_submit_dtap(conn, msg, 0, 0);
139}
140
141int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text)
142{
143 struct gsm48_hdr *gh;
144 struct msgb *msg;
145
146 msg = gsm0480_create_unstructuredSS_Notify(level, text);
147 if (!msg)
148 return -1;
149
150 gsm0480_wrap_invoke(msg, GSM0480_OP_CODE_USS_NOTIFY, 0);
151 gsm0480_wrap_facility(msg);
152
153 /* And finally pre-pend the L3 header */
154 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
155 gh->proto_discr = GSM48_PDISC_NC_SS;
156 gh->msg_type = GSM0480_MTYPE_REGISTER;
157
158 return gsm0808_submit_dtap(conn, msg, 0, 0);
159}
160
161int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn)
162{
163 struct gsm48_hdr *gh;
164 struct msgb *msg;
165
166 msg = gsm48_msgb_alloc();
167 if (!msg)
168 return -1;
169
170 gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh));
171 gh->proto_discr = GSM48_PDISC_NC_SS;
172 gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE;
173
174 return gsm0808_submit_dtap(conn, msg, 0, 0);
175}