1 /* (C) 2009,2010 by Holger Hans Peter Freyther <zecke@selfish.org>
2 * (C) 2009,2010 by On-Waves
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.
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.
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.
21 #include <osmocore/gsm0808.h>
22 #include <osmocore/protocol/gsm_08_08.h>
23 #include <osmocore/gsm48.h>
25 #include <arpa/inet.h>
27 #define BSSMAP_MSG_SIZE 512
28 #define BSSMAP_MSG_HEADROOM 128
30 static void put_data_16(uint8_t *data, const uint16_t val)
32 memcpy(data, &val, sizeof(val));
35 struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, uint16_t _ci)
40 struct gsm48_loc_area_id *lai;
42 msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
47 /* create the bssmap header */
48 msg->l3h = msgb_put(msg, 2);
51 /* create layer 3 header */
52 data = msgb_put(msg, 1);
53 data[0] = BSS_MAP_MSG_COMPLETE_LAYER_3;
55 /* create the cell header */
56 data = msgb_put(msg, 3);
57 data[0] = GSM0808_IE_CELL_IDENTIFIER;
58 data[1] = 1 + sizeof(*lai) + 2;
59 data[2] = CELL_IDENT_WHOLE_GLOBAL;
61 lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai));
62 gsm48_generate_lai(lai, cc, nc, lac);
64 ci = msgb_put(msg, 2);
65 put_data_16(ci, htons(_ci));
67 /* copy the layer3 data */
68 data = msgb_put(msg, msgb_l3len(msg_l3) + 2);
69 data[0] = GSM0808_IE_LAYER_3_INFORMATION;
70 data[1] = msgb_l3len(msg_l3);
71 memcpy(&data[2], msg_l3->l3h, data[1]);
74 msg->l3h[1] = msgb_l3len(msg) - 2;
79 struct msgb *gsm0808_create_reset(void)
81 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
86 msg->l3h = msgb_put(msg, 6);
87 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
96 struct msgb *gsm0808_create_clear_complete(void)
98 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
99 "bssmap: clear complete");
103 msg->l3h = msgb_put(msg, 3);
104 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
106 msg->l3h[2] = BSS_MAP_MSG_CLEAR_COMPLETE;
111 struct msgb *gsm0808_create_cipher_complete(struct msgb *layer3, uint8_t alg_id)
113 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
118 /* send response with BSS override for A5/1... cheating */
119 msg->l3h = msgb_put(msg, 3);
120 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
122 msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_COMPLETE;
124 /* include layer3 in case we have at least two octets */
125 if (layer3 && msgb_l3len(layer3) > 2) {
126 msg->l4h = msgb_put(msg, msgb_l3len(layer3) + 2);
127 msg->l4h[0] = GSM0808_IE_LAYER_3_MESSAGE_CONTENTS;
128 msg->l4h[1] = msgb_l3len(layer3);
129 memcpy(&msg->l4h[2], layer3->l3h, msgb_l3len(layer3));
132 /* and the optional BSS message */
133 msg->l4h = msgb_put(msg, 2);
134 msg->l4h[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
135 msg->l4h[1] = alg_id;
137 /* update the size */
138 msg->l3h[1] = msgb_l3len(msg) - 2;
142 struct msgb *gsm0808_create_cipher_reject(uint8_t cause)
144 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
145 "bssmap: clear complete");
149 msg->l3h = msgb_put(msg, 3);
150 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
152 msg->l3h[2] = BSS_MAP_MSG_CIPHER_MODE_REJECT;
158 struct msgb *gsm0808_create_classmark_update(const uint8_t *classmark_data, uint8_t length)
160 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
165 msg->l3h = msgb_put(msg, 3);
166 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
168 msg->l3h[2] = BSS_MAP_MSG_CLASSMARK_UPDATE;
170 msg->l4h = msgb_put(msg, length);
171 memcpy(msg->l4h, classmark_data, length);
173 /* update the size */
174 msg->l3h[1] = msgb_l3len(msg) - 2;
178 struct msgb *gsm0808_create_sapi_reject(uint8_t link_id)
180 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
181 "bssmap: sapi 'n' reject");
185 msg->l3h = msgb_put(msg, 5);
186 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
188 msg->l3h[2] = BSS_MAP_MSG_SAPI_N_REJECT;
189 msg->l3h[3] = link_id;
190 msg->l3h[4] = GSM0808_CAUSE_BSS_NOT_EQUIPPED;
195 struct msgb *gsm0808_create_assignment_completed(struct gsm_lchan *lchan, uint8_t rr_cause,
196 uint8_t chosen_channel, uint8_t encr_alg_id,
201 struct msgb *msg = msgb_alloc(35, "bssmap: ass compl");
205 msg->l3h = msgb_put(msg, 3);
206 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
208 msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_COMPLETE;
211 data = msgb_put(msg, 2);
212 data[0] = GSM0808_IE_RR_CAUSE;
215 /* write cirtcuit identity code 3.2.2.2 */
216 /* write cell identifier 3.2.2.17 */
217 /* write chosen channel 3.2.2.33 when BTS picked it */
218 data = msgb_put(msg, 2);
219 data[0] = GSM0808_IE_CHOSEN_CHANNEL;
220 data[1] = chosen_channel;
222 /* write chosen encryption algorithm 3.2.2.44 */
223 data = msgb_put(msg, 2);
224 data[0] = GSM0808_IE_CHOSEN_ENCR_ALG;
225 data[1] = encr_alg_id;
227 /* write circuit pool 3.2.2.45 */
228 /* write speech version chosen: 3.2.2.51 when BTS picked it */
229 if (speech_mode != 0) {
230 data = msgb_put(msg, 2);
231 data[0] = GSM0808_IE_SPEECH_VERSION;
232 data[1] = speech_mode;
235 /* write LSA identifier 3.2.2.15 */
238 /* update the size */
239 msg->l3h[1] = msgb_l3len(msg) - 2;
243 struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause)
246 struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
251 msg->l3h = msgb_put(msg, 6);
252 msg->l3h[0] = BSSAP_MSG_BSS_MANAGEMENT;
254 msg->l3h[2] = BSS_MAP_MSG_ASSIGMENT_FAILURE;
255 msg->l3h[3] = GSM0808_IE_CAUSE;
259 /* RR cause 3.2.2.22 */
261 data = msgb_put(msg, 2);
262 data[0] = GSM0808_IE_RR_CAUSE;
266 /* Circuit pool 3.22.45 */
267 /* Circuit pool list 3.2.2.46 */
269 /* update the size */
270 msg->l3h[1] = msgb_l3len(msg) - 2;
274 void gsm0808_prepend_dtap_header(struct msgb *msg, uint8_t link_id)
276 uint8_t *hh = msgb_push(msg, 3);
277 hh[0] = BSSAP_MSG_DTAP;
279 hh[2] = msg->len - 3;
282 static const struct tlv_definition bss_att_tlvdef = {
284 [GSM0808_IE_IMSI] = { TLV_TYPE_TLV },
285 [GSM0808_IE_TMSI] = { TLV_TYPE_TLV },
286 [GSM0808_IE_CELL_IDENTIFIER_LIST] = { TLV_TYPE_TLV },
287 [GSM0808_IE_CHANNEL_NEEDED] = { TLV_TYPE_TV },
288 [GSM0808_IE_EMLPP_PRIORITY] = { TLV_TYPE_TV },
289 [GSM0808_IE_CHANNEL_TYPE] = { TLV_TYPE_TLV },
290 [GSM0808_IE_PRIORITY] = { TLV_TYPE_TLV },
291 [GSM0808_IE_CIRCUIT_IDENTITY_CODE] = { TLV_TYPE_TV },
292 [GSM0808_IE_DOWNLINK_DTX_FLAG] = { TLV_TYPE_TV },
293 [GSM0808_IE_INTERFERENCE_BAND_TO_USE] = { TLV_TYPE_TV },
294 [GSM0808_IE_CLASSMARK_INFORMATION_T2] = { TLV_TYPE_TLV },
295 [GSM0808_IE_GROUP_CALL_REFERENCE] = { TLV_TYPE_TLV },
296 [GSM0808_IE_TALKER_FLAG] = { TLV_TYPE_T },
297 [GSM0808_IE_CONFIG_EVO_INDI] = { TLV_TYPE_TV },
298 [GSM0808_IE_LSA_ACCESS_CTRL_SUPPR] = { TLV_TYPE_TV },
299 [GSM0808_IE_SERVICE_HANDOVER] = { TLV_TYPE_TV},
300 [GSM0808_IE_ENCRYPTION_INFORMATION] = { TLV_TYPE_TLV },
301 [GSM0808_IE_CIPHER_RESPONSE_MODE] = { TLV_TYPE_TV },
302 [GSM0808_IE_CELL_IDENTIFIER] = { TLV_TYPE_TLV },
303 [GSM0808_IE_CHOSEN_CHANNEL] = { TLV_TYPE_TV },
304 [GSM0808_IE_LAYER_3_INFORMATION] = { TLV_TYPE_TLV },
308 const struct tlv_definition *gsm0808_att_tlvdef()
310 return &bss_att_tlvdef;