blob: 9f6f0059d731c3abd720d1bc5745eccb84930394 [file] [log] [blame]
Holger Hans Peter Freyther280cd512010-04-15 10:10:39 +02001/* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org>
2 * (C) 2009,2010 by On-Waves
3 * All Rights Reserved
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 */
20
21#include <osmocore/gsm0808.h>
22#include <osmocore/protocol/gsm_08_08.h>
23#include <osmocore/gsm48.h>
24
25#include <arpa/inet.h>
26
27#define BSSMAP_MSG_SIZE 512
28#define BSSMAP_MSG_HEADROOM 128
29
30struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, int _ci)
31{
32 uint8_t *data;
33 uint16_t *ci;
34 struct msgb* msg;
35 struct gsm48_loc_area_id *lai;
36
37 msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
38 "bssmap cmpl l3");
39 if (!msg)
40 return NULL;
41
42 /* create the bssmap header */
43 msg->l3h = msgb_put(msg, 2);
44 msg->l3h[0] = 0x0;
45
46 /* create layer 3 header */
47 data = msgb_put(msg, 1);
48 data[0] = BSS_MAP_MSG_COMPLETE_LAYER_3;
49
50 /* create the cell header */
51 data = msgb_put(msg, 3);
52 data[0] = GSM0808_IE_CELL_IDENTIFIER;
53 data[1] = 1 + sizeof(*lai) + 2;
54 data[2] = CELL_IDENT_WHOLE_GLOBAL;
55
56 lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
57 gsm48_generate_lai(lai, cc, nc, lac);
58
59 ci = (uint16_t *) msgb_put(msg, 2);
60 *ci = htons(_ci);
61
62 /* copy the layer3 data */
63 data = msgb_put(msg, msgb_l3len(msg_l3) + 2);
64 data[0] = GSM0808_IE_LAYER_3_INFORMATION;
65 data[1] = msgb_l3len(msg_l3);
66 memcpy(&data[2], msg_l3->l3h, data[1]);
67
68 /* update the size */
69 msg->l3h[1] = msgb_l3len(msg) - 2;
70
71 return msg;
72}
73
74struct msgb *gsm0808_create_reset(void)
75{
76 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
77 "bssmap: reset");
78 if (!msg)
79 return NULL;
80
81 msg->l3h = msgb_put(msg, 6);
82 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
83 msg->l3h[1] = 0x04;
84 msg->l3h[2] = 0x30;
85 msg->l3h[3] = 0x04;
86 msg->l3h[4] = 0x01;
87 msg->l3h[5] = 0x20;
88 return msg;
89}
90
91struct msgb *gsm0808_create_clear_complete(void)
92{
93 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
94 "bssmap: clear complete");
95 if (!msg)
96 return NULL;
97
98 msg->l3h = msgb_put(msg, 3);
99 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
100 msg->l3h[1] = 1;
101 msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE;
102
103 return msg;
104}
105
Holger Hans Peter Freyther81716d52010-04-17 06:16:35 +0200106struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id)
107{
108 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
109 "cipher-complete");
110 if (!msg)
111 return NULL;
112
113 /* send response with BSS override for A5/1... cheating */
114 msg->l3h = msgb_put(msg, 3);
115 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
116 msg->l3h[1] = 0xff;
117 msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_COMPLETE;
118
119 /* include layer3 in case we have at least two octets */
120 if (layer3 && msgb_l3len(layer3) > 2) {
121 msg->l4h = msgb_put(msg, msgb_l3len(layer3) + 2);
122 msg->l4h[0] = GSM0808_IE_LAYER_3_MESSAGE_CONTENTS;
123 msg->l4h[1] = msgb_l3len(layer3);
124 memcpy(&msg->l4h[2], layer3->l3h, msgb_l3len(layer3));
125 }
126
127 /* and the optional BSS message */
128 msg->l4h = msgb_put(msg, 2);
129 msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
130 msg->l4h[1] = alg_id;
131
132 /* update the size */
133 msg->l3h[1] = msgb_l3len(msg) - 2;
134 return msg;
135}
136
Holger Hans Peter Freyther280cd512010-04-15 10:10:39 +0200137struct msgb *gsm0808_create_cipher_reject(uint8_t cause)
138{
139 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
140 "bssmap: clear complete");
141 if (!msg)
142 return NULL;
143
144 msg->l3h = msgb_put(msg, 3);
145 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
146 msg->l3h[1] = 2;
147 msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT;
148 msg->l3h[3] = cause;
149
150 return msg;
151}
152
153struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, u_int8_t length)
154{
155 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
156 "classmark-update");
157 if (!msg)
158 return NULL;
159
160 msg->l3h = msgb_put(msg, 3);
161 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
162 msg->l3h[1] = 0xff;
163 msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE;
164
165 msg->l4h = msgb_put(msg, length);
166 memcpy(msg->l4h, classmark_data, length);
167
168 /* update the size */
169 msg->l3h[1] = msgb_l3len(msg) - 2;
170 return msg;
171}
172
173struct msgb *gsm0808_create_sapi_reject(uint8_t link_id)
174{
175 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
176 "bssmap: sapi 'n' reject");
177 if (!msg)
178 return NULL;
179
180 msg->l3h = msgb_put(msg, 5);
181 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
182 msg->l3h[1] = 3;
183 msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT;
184 msg->l3h[3] = link_id;
185 msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED;
186
187 return msg;
188}
189
Holger Hans Peter Freytherba6172a2010-04-17 06:21:49 +0200190struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause,
191 uint8_t chosen_channel, uint8_t encr_alg_id,
192 uint8_t speech_mode)
193{
194 u_int8_t *data;
195
196 struct msgb *msg = msgb_alloc(35, "bssmap: ass compl");
197 if (!msg)
198 return NULL;
199
200 msg->l3h = msgb_put(msg, 3);
201 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
202 msg->l3h[1] = 0xff;
203 msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE;
204
205 /* write 3.2.2.22 */
206 data = msgb_put(msg, 2);
207 data[0] = GSM0808_IE_RR_CAUSE;
208 data[1] = rr_cause;
209
210 /* write cirtcuit identity code 3.2.2.2 */
211 /* write cell identifier 3.2.2.17 */
212 /* write chosen channel 3.2.2.33 when BTS picked it */
213 data = msgb_put(msg, 2);
214 data[0] = GSM0808_IE_CHOSEN_CHANNEL;
215 data[1] = chosen_channel;
216
217 /* write chosen encryption algorithm 3.2.2.44 */
218 data = msgb_put(msg, 2);
219 data[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
220 data[1] = encr_alg_id;
221
222 /* write circuit pool 3.2.2.45 */
223 /* write speech version chosen: 3.2.2.51 when BTS picked it */
224 if (speech_mode != 0) {
225 data = msgb_put(msg, 2);
226 data[0] = GSM0808_IE_SPEECH_VERSION;
227 data[1] = speech_mode;
228 }
229
230 /* write LSA identifier 3.2.2.15 */
231
232
233 /* update the size */
234 msg->l3h[1] = msgb_l3len(msg) - 2;
235 return msg;
236}
237
Holger Hans Peter Freyther280cd512010-04-15 10:10:39 +0200238struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause)
239{
240 uint8_t *data;
241 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
242 "bssmap: ass fail");
243 if (!msg)
244 return NULL;
245
246 msg->l3h = msgb_put(msg, 6);
247 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
248 msg->l3h[1] = 0xff;
249 msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
250 msg->l3h[3] = GSM0808_IE_CAUSE;
251 msg->l3h[4] = 1;
252 msg->l3h[5] = cause;
253
254 /* RR cause 3.2.2.22 */
255 if (rr_cause) {
256 data = msgb_put(msg, 2);
257 data[0] = GSM0808_IE_RR_CAUSE;
258 data[1] = *rr_cause;
259 }
260
261 /* Circuit pool 3.22.45 */
262 /* Circuit pool list 3.2.2.46 */
263
264 /* update the size */
265 msg->l3h[1] = msgb_l3len(msg) - 2;
266 return msg;
267}
Holger Hans Peter Freyther7daa01c2010-04-17 05:14:36 +0200268
269static const struct tlv_definition bss_att_tlvdef = {
270 .def = {
271 [GSM0808_IE_IMSI] = { TLV_TYPE_TLV },
272 [GSM0808_IE_TMSI] = { TLV_TYPE_TLV },
273 [GSM0808_IE_CELL_IDENTIFIER_LIST] = { TLV_TYPE_TLV },
274 [GSM0808_IE_CHANNEL_NEEDED] = { TLV_TYPE_TV },
275 [GSM0808_IE_EMLPP_PRIORITY] = { TLV_TYPE_TV },
276 [GSM0808_IE_CHANNEL_TYPE] = { TLV_TYPE_TLV },
277 [GSM0808_IE_PRIORITY] = { TLV_TYPE_TLV },
278 [GSM0808_IE_CIRCUIT_IDENTITY_CODE] = { TLV_TYPE_TV },
279 [GSM0808_IE_DOWNLINK_DTX_FLAG] = { TLV_TYPE_TV },
280 [GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV },
281 [GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV },
282 [GSM0808_IE_GROUP_CALL_REFERENCE] = { TLV_TYPE_TLV },
283 [GSM0808_IE_TALKER_FLAG] = { TLV_TYPE_T },
284 [GSM0808_IE_CONFIG_EVO_INDI] = { TLV_TYPE_TV },
285 [GSM0808_IE_LSA_ACCESS_CTRL_SUPPR] = { TLV_TYPE_TV },
286 [GSM0808_IE_SERVICE_HANDOVER] = { TLV_TYPE_TV},
287 [GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV },
288 [GSM0808_IE_CIPHER_RESPONSE_MODE] = { TLV_TYPE_TV },
289 },
290};
291
292const struct tlv_definition *gsm0808_att_tlvdef()
293{
294 return &bss_att_tlvdef;
295}