blob: a72a19bd55c0855139cecadbd4efe25f62dc894d [file] [log] [blame]
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +02001/* OpenBSC minimal LAPD implementation */
2
3/* (C) 2009 by oystein@homelien.no
4 * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
5 * (C) 2010 by Digium and Matthew Fredrickson <creslin@digium.com>
6 * (C) 2011 by Harald Welte <laforge@gnumonks.org>
Andreas Eversberga7ff0012011-09-26 11:29:30 +02007 * (C) 2011 by Andreas Eversberg <jolly@eversberg.eu>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +02008 *
9 * All Rights Reserved
10 *
Harald Welte323d39d2017-11-13 01:09:21 +090011 * SPDX-License-Identifier: GPL-2.0+
12
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020013 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 */
28
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020029#include "internal.h"
30
31#include <stdio.h>
32#include <string.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020033#include <errno.h>
34
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020035#include <osmocom/core/linuxlist.h>
36#include <osmocom/core/logging.h>
Harald Welte71d87b22011-07-18 14:49:56 +020037#include <osmocom/core/talloc.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020038#include <osmocom/core/msgb.h>
39#include <osmocom/core/timer.h>
Andreas Eversberga7ff0012011-09-26 11:29:30 +020040#include <osmocom/abis/lapd.h>
Pablo Neira Ayuso95306002012-08-22 16:43:59 +020041#include <osmocom/abis/lapd_pcap.h>
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020042
Andreas Eversberga7ff0012011-09-26 11:29:30 +020043#define LAPD_ADDR2(sapi, cr) ((((sapi) & 0x3f) << 2) | (((cr) & 0x1) << 1))
44#define LAPD_ADDR3(tei) ((((tei) & 0x7f) << 1) | 0x1)
45
46#define LAPD_ADDR_SAPI(addr) ((addr) >> 2)
47#define LAPD_ADDR_CR(addr) (((addr) >> 1) & 0x1)
48#define LAPD_ADDR_EA(addr) ((addr) & 0x1)
49#define LAPD_ADDR_TEI(addr) ((addr) >> 1)
50
51#define LAPD_CTRL_I4(ns) (((ns) & 0x7f) << 1)
52#define LAPD_CTRL_I5(nr, p) ((((nr) & 0x7f) << 1) | ((p) & 0x1))
53#define LAPD_CTRL_S4(s) ((((s) & 0x3) << 2) | 0x1)
54#define LAPD_CTRL_S5(nr, p) ((((nr) & 0x7f) << 1) | ((p) & 0x1))
55#define LAPD_CTRL_U4(u, p) ((((u) & 0x1c) << (5-2)) | (((p) & 0x1) << 4) | (((u) & 0x3) << 2) | 0x3)
56
57#define LAPD_CTRL_is_I(ctrl) (((ctrl) & 0x1) == 0)
58#define LAPD_CTRL_is_S(ctrl) (((ctrl) & 0x3) == 1)
59#define LAPD_CTRL_is_U(ctrl) (((ctrl) & 0x3) == 3)
60
61#define LAPD_CTRL_U_BITS(ctrl) ((((ctrl) & 0xC) >> 2) | ((ctrl) & 0xE0) >> 3)
62#define LAPD_CTRL_U_PF(ctrl) (((ctrl) >> 4) & 0x1)
63
64#define LAPD_CTRL_S_BITS(ctrl) (((ctrl) & 0xC) >> 2)
65#define LAPD_CTRL_S_PF(ctrl) (ctrl & 0x1)
66
67#define LAPD_CTRL_I_Ns(ctrl) (((ctrl) & 0xFE) >> 1)
68#define LAPD_CTRL_I_P(ctrl) (ctrl & 0x1)
69#define LAPD_CTRL_Nr(ctrl) (((ctrl) & 0xFE) >> 1)
70
71#define LAPD_LEN(len) ((len << 2) | 0x1)
72#define LAPD_EL 0x1
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +020073
Andreas Eversberg3c460442011-09-28 02:46:16 +020074#define LAPD_SET_K(n, o) {n,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o,o}
75
Andreas Eversberg3744b872011-09-27 12:12:36 +020076const struct lapd_profile lapd_profile_isdn = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +010077 .k = LAPD_SET_K(7,7),
78 .n200 = 3,
79 .n201 = 260,
80 .n202 = 3,
81 .t200_sec = 1, .t200_usec = 0,
82 .t201_sec = 1, .t201_usec = 0,
83 .t202_sec = 2, .t202_usec = 0,
84 .t203_sec = 10, .t203_usec = 0,
85 .short_address = 0
Andreas Eversberg3744b872011-09-27 12:12:36 +020086};
87
88const struct lapd_profile lapd_profile_abis = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +010089 .k = LAPD_SET_K(2,1),
90 .n200 = 3,
91 .n201 = 260,
92 .n202 = 0, /* infinite */
93 .t200_sec = 0, .t200_usec = 240000,
94 .t201_sec = 1, .t201_usec = 0,
95 .t202_sec = 2, .t202_usec = 0,
96 .t203_sec = 10, .t203_usec = 0,
97 .short_address = 0
Andreas Eversberg3744b872011-09-27 12:12:36 +020098};
99
Philipp0c7d5f42016-10-19 18:38:58 +0200100/* Ericssons OM2000 lapd dialect requires a sabm frame retransmission
101 * timeout of exactly 300 msek. Shorter or longer retransmission will
102 * cause the link establishment to fail permanently. Since the BTS is
103 * periodically scanning through all timeslots to find the timeslot
104 * where the bsc is transmitting its sabm frames the normal maximum
105 * retransmission (n200) of 3 is not enough. In order not to miss
Philipp Maierd75bac42017-02-01 13:51:03 +0100106 * the bts, n200 has been increased to 50, which is an educated
Philipp0c7d5f42016-10-19 18:38:58 +0200107 * guess. */
108
109const struct lapd_profile lapd_profile_abis_ericsson = {
110 .k = LAPD_SET_K(2,1),
Philipp Maierd75bac42017-02-01 13:51:03 +0100111 .n200 = 50,
Philipp0c7d5f42016-10-19 18:38:58 +0200112 .n201 = 260,
113 .n202 = 0, /* infinite */
114 .t200_sec = 0, .t200_usec = 300000,
115 .t201_sec = 1, .t201_usec = 0,
116 .t202_sec = 2, .t202_usec = 0,
117 .t203_sec = 10, .t203_usec = 0,
118 .short_address = 0
119};
120
Andreas Eversberg3744b872011-09-27 12:12:36 +0200121const struct lapd_profile lapd_profile_sat = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +0100122 .k = LAPD_SET_K(15,15),
123 .n200 = 5,
124 .n201 = 260,
125 .n202 = 5,
126 .t200_sec = 2, .t200_usec = 400000,
127 .t201_sec = 2, .t201_usec = 400000,
128 .t202_sec = 2, .t202_usec = 400000,
Holger Hans Peter Freyther4b6860d2013-03-09 17:32:33 +0100129 .t203_sec = 20, .t203_usec = 0,
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +0100130 .short_address = 1
Andreas Eversberg3744b872011-09-27 12:12:36 +0200131};
132
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200133typedef enum {
134 LAPD_TEI_NONE = 0,
135 LAPD_TEI_ASSIGNED,
136 LAPD_TEI_ACTIVE,
137} lapd_tei_state;
138
139const char *lapd_tei_states[] = {
140 "NONE",
141 "ASSIGNED",
142 "ACTIVE",
143};
144
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200145/* Structure representing an allocated TEI within a LAPD instance. */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200146struct lapd_tei {
147 struct llist_head list;
148 struct lapd_instance *li;
149 uint8_t tei;
150 lapd_tei_state state;
151
152 struct llist_head sap_list;
153};
154
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200155/* Structure representing a SAP within a TEI. It includes exactly one datalink
156 * instance. */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200157struct lapd_sap {
158 struct llist_head list;
159 struct lapd_tei *tei;
160 uint8_t sapi;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200161
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200162 struct lapd_datalink dl;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200163};
164
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200165/* Resolve TEI structure from given numeric TEI */
166static struct lapd_tei *teip_from_tei(struct lapd_instance *li, uint8_t tei)
167{
168 struct lapd_tei *lt;
169
170 llist_for_each_entry(lt, &li->tei_list, list) {
171 if (lt->tei == tei)
172 return lt;
173 }
174 return NULL;
175};
176
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200177/* Change state of TEI */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200178static void lapd_tei_set_state(struct lapd_tei *teip, int newstate)
179{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200180 LOGP(DLLAPD, LOGL_INFO, "LAPD state change on TEI %d: %s -> %s\n",
181 teip->tei, lapd_tei_states[teip->state],
182 lapd_tei_states[newstate]);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200183 teip->state = newstate;
184};
185
186/* Allocate a new TEI */
187struct lapd_tei *lapd_tei_alloc(struct lapd_instance *li, uint8_t tei)
188{
189 struct lapd_tei *teip;
190
191 teip = talloc_zero(li, struct lapd_tei);
192 if (!teip)
193 return NULL;
194
195 teip->li = li;
196 teip->tei = tei;
197 llist_add(&teip->list, &li->tei_list);
198 INIT_LLIST_HEAD(&teip->sap_list);
199
200 lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
201
202 return teip;
203}
204
205/* Find a SAP within a given TEI */
206static struct lapd_sap *lapd_sap_find(struct lapd_tei *teip, uint8_t sapi)
207{
208 struct lapd_sap *sap;
209
210 llist_for_each_entry(sap, &teip->sap_list, list) {
211 if (sap->sapi == sapi)
212 return sap;
213 }
214
215 return NULL;
216}
217
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200218static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg);
219static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200220
221/* Allocate a new SAP within a given TEI */
222static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi)
223{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200224 struct lapd_sap *sap;
225 struct lapd_datalink *dl;
226 struct lapd_instance *li;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200227 struct lapd_profile *profile;
228 int k;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200229
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200230 sap = talloc_zero(teip, struct lapd_sap);
231 if (!sap)
232 return NULL;
233
Philipp Maier027e1192016-12-08 17:17:33 +0100234 LOGP(DLLAPD, LOGL_NOTICE,
235 "LAPD Allocating SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n",
236 sapi, teip->tei, &sap->dl, sap);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200237
238 sap->sapi = sapi;
239 sap->tei = teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200240 dl = &sap->dl;
241 li = teip->li;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200242 profile = &li->profile;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200243
Andreas Eversberg3c460442011-09-28 02:46:16 +0200244 k = profile->k[sapi & 0x3f];
245 LOGP(DLLAPD, LOGL_NOTICE, "k=%d N200=%d N201=%d T200=%d.%d T203=%d.%d"
246 "\n", k, profile->n200, profile->n201, profile->t200_sec,
247 profile->t200_usec, profile->t203_sec, profile->t203_usec);
Andreas Eversberg3744b872011-09-27 12:12:36 +0200248 lapd_dl_init(dl, k, 128, profile->n201);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200249 dl->use_sabme = 1; /* use SABME instead of SABM (GSM) */
250 dl->send_ph_data_req = send_ph_data_req;
251 dl->send_dlsap = send_dlsap;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200252 dl->n200 = profile->n200;
253 dl->n200_est_rel = profile->n200;
254 dl->t200_sec = profile->t200_sec; dl->t200_usec = profile->t200_usec;
255 dl->t203_sec = profile->t203_sec; dl->t203_usec = profile->t203_usec;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200256 dl->lctx.dl = &sap->dl;
257 dl->lctx.sapi = sapi;
258 dl->lctx.tei = teip->tei;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200259 dl->lctx.n201 = profile->n201;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200260
261 lapd_set_mode(&sap->dl, (teip->li->network_side) ? LAPD_MODE_NETWORK
262 : LAPD_MODE_USER);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200263
264 llist_add(&sap->list, &teip->sap_list);
265
266 return sap;
267}
268
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200269/* Free SAP instance, including the datalink */
270static void lapd_sap_free(struct lapd_sap *sap)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200271{
Philipp Maier027e1192016-12-08 17:17:33 +0100272 LOGP(DLLAPD, LOGL_NOTICE,
273 "LAPD Freeing SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n",
274 sap->sapi, sap->tei->tei, &sap->dl, sap);
275
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200276 /* free datalink structures and timers */
277 lapd_dl_exit(&sap->dl);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200278
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200279 llist_del(&sap->list);
280 talloc_free(sap);
281}
282
283/* Free TEI instance */
284static void lapd_tei_free(struct lapd_tei *teip)
285{
286 struct lapd_sap *sap, *sap2;
287
288 llist_for_each_entry_safe(sap, sap2, &teip->sap_list, list) {
289 lapd_sap_free(sap);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200290 }
291
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200292 llist_del(&teip->list);
293 talloc_free(teip);
294}
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200295
296/* Input function into TEI manager */
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200297static int lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200298{
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200299 uint8_t entity;
300 uint8_t ref;
301 uint8_t mt;
302 uint8_t action;
303 uint8_t e;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200304 uint8_t resp[8];
305 struct lapd_tei *teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200306 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200307
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200308 if (len < 5) {
309 LOGP(DLLAPD, LOGL_ERROR, "LAPD TEIMGR frame receive len %d < 5"
310 ", ignoring\n", len);
311 return -EINVAL;
312 };
313
314 entity = data[0];
315 ref = data[1];
316 mt = data[3];
317 action = data[4] >> 1;
318 e = data[4] & 1;
319
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200320 DEBUGP(DLLAPD, "LAPD TEIMGR: entity %x, ref %x, mt %x, action %x, "
321 "e %x\n", entity, ref, mt, action, e);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200322
323 switch (mt) {
324 case 0x01: /* IDENTITY REQUEST */
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200325 DEBUGP(DLLAPD, "LAPD TEIMGR: identity request for TEI %u\n",
326 action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200327
328 teip = teip_from_tei(li, action);
329 if (!teip) {
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200330 LOGP(DLLAPD, LOGL_INFO, "TEI MGR: New TEI %u\n",
331 action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200332 teip = lapd_tei_alloc(li, action);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200333 if (!teip)
334 return -ENOMEM;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200335 }
336
337 /* Send ACCEPT */
338 memmove(resp, "\xfe\xff\x03\x0f\x00\x00\x02\x00", 8);
339 resp[7] = (action << 1) | 1;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200340 msg = msgb_alloc_headroom(56, 56, "DL EST");
341 msg->l2h = msgb_push(msg, 8);
342 memcpy(msg->l2h, resp, 8);
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200343
344 /* write to PCAP file, if enabled. */
345 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
346
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200347 LOGP(DLLAPD, LOGL_DEBUG, "TX: %s\n",
348 osmo_hexdump(msg->data, msg->len));
349 li->transmit_cb(msg, li->transmit_cbdata);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200350
351 if (teip->state == LAPD_TEI_NONE)
352 lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
353 break;
354 default:
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200355 LOGP(DLLAPD, LOGL_NOTICE, "LAPD TEIMGR: unknown mt %x "
356 "action %x\n", mt, action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200357 break;
358 };
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200359
360 return 0;
361}
362
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200363/* General input function for any data received for this LAPD instance */
364int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200365{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200366 int i;
367 struct lapd_msg_ctx lctx;
368 int rc;
369 struct lapd_sap *sap;
370 struct lapd_tei *teip;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200371
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200372 /* write to PCAP file, if enabled. */
373 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_INPUT, msg);
374
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200375 LOGP(DLLAPD, LOGL_DEBUG, "RX: %s\n", osmo_hexdump(msg->data, msg->len));
376 if (msg->len < 2) {
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200377 LOGP(DLLAPD, LOGL_ERROR, "LAPD frame receive len %d < 2, "
378 "ignoring\n", msg->len);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200379 *error = LAPD_ERR_BAD_LEN;
380 return -EINVAL;
381 };
382 msg->l2h = msg->data;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200383
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200384 memset(&lctx, 0, sizeof(lctx));
385
386 i = 0;
387 /* adress field */
388 lctx.sapi = LAPD_ADDR_SAPI(msg->l2h[i]);
389 lctx.cr = LAPD_ADDR_CR(msg->l2h[i]);
390 lctx.lpd = 0;
391 if (!LAPD_ADDR_EA(msg->l2h[i])) {
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200392 if (msg->len < 3) {
393 LOGP(DLLAPD, LOGL_ERROR, "LAPD frame with TEI receive "
394 "len %d < 3, ignoring\n", msg->len);
395 *error = LAPD_ERR_BAD_LEN;
396 return -EINVAL;
397 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200398 i++;
399 lctx.tei = LAPD_ADDR_TEI(msg->l2h[i]);
400 }
401 i++;
402 /* control field */
403 if (LAPD_CTRL_is_I(msg->l2h[i])) {
404 lctx.format = LAPD_FORM_I;
405 lctx.n_send = LAPD_CTRL_I_Ns(msg->l2h[i]);
406 i++;
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200407 if (msg->len < 3 && i == 2) {
408 LOGP(DLLAPD, LOGL_ERROR, "LAPD I frame without TEI "
409 "receive len %d < 3, ignoring\n", msg->len);
410 *error = LAPD_ERR_BAD_LEN;
411 return -EINVAL;
412 };
413 if (msg->len < 4 && i == 3) {
414 LOGP(DLLAPD, LOGL_ERROR, "LAPD I frame with TEI "
415 "receive len %d < 4, ignoring\n", msg->len);
416 *error = LAPD_ERR_BAD_LEN;
417 return -EINVAL;
418 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200419 lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]);
420 lctx.p_f = LAPD_CTRL_I_P(msg->l2h[i]);
421 } else if (LAPD_CTRL_is_S(msg->l2h[i])) {
422 lctx.format = LAPD_FORM_S;
423 lctx.s_u = LAPD_CTRL_S_BITS(msg->l2h[i]);
424 i++;
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200425 if (msg->len < 3 && i == 2) {
426 LOGP(DLLAPD, LOGL_ERROR, "LAPD S frame without TEI "
427 "receive len %d < 3, ignoring\n", msg->len);
428 *error = LAPD_ERR_BAD_LEN;
429 return -EINVAL;
430 };
431 if (msg->len < 4 && i == 3) {
432 LOGP(DLLAPD, LOGL_ERROR, "LAPD S frame with TEI "
433 "receive len %d < 4, ignoring\n", msg->len);
434 *error = LAPD_ERR_BAD_LEN;
435 return -EINVAL;
436 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200437 lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]);
438 lctx.p_f = LAPD_CTRL_S_PF(msg->l2h[i]);
439 } else if (LAPD_CTRL_is_U(msg->l2h[i])) {
440 lctx.format = LAPD_FORM_U;
441 lctx.s_u = LAPD_CTRL_U_BITS(msg->l2h[i]);
442 lctx.p_f = LAPD_CTRL_U_PF(msg->l2h[i]);
443 } else
444 lctx.format = LAPD_FORM_UKN;
445 i++;
446 /* length */
447 msg->l3h = msg->l2h + i;
448 msgb_pull(msg, i);
449 lctx.length = msg->len;
450
451 /* perform TEI assignment, if received */
452 if (lctx.tei == 127) {
453 rc = lapd_tei_receive(li, msg->data, msg->len);
454 msgb_free(msg);
455 return rc;
456 }
457
458 /* resolve TEI and SAPI */
459 teip = teip_from_tei(li, lctx.tei);
460 if (!teip) {
461 LOGP(DLLAPD, LOGL_NOTICE, "LAPD Unknown TEI %u\n", lctx.tei);
462 *error = LAPD_ERR_UNKNOWN_TEI;
463 msgb_free(msg);
464 return -EINVAL;
465 }
466 sap = lapd_sap_find(teip, lctx.sapi);
467 if (!sap) {
468 LOGP(DLLAPD, LOGL_INFO, "LAPD No SAP for TEI=%u / SAPI=%u, "
469 "allocating\n", lctx.tei, lctx.sapi);
470 sap = lapd_sap_alloc(teip, lctx.sapi);
471 if (!sap) {
472 *error = LAPD_ERR_NO_MEM;
473 msgb_free(msg);
474 return -ENOMEM;
475 }
476 }
477 lctx.dl = &sap->dl;
478 lctx.n201 = lctx.dl->maxf;
479
480 if (msg->len > lctx.n201) {
481 LOGP(DLLAPD, LOGL_ERROR, "message len %d > N201(%d) "
482 "(discarding)\n", msg->len, lctx.n201);
483 msgb_free(msg);
484 *error = LAPD_ERR_BAD_LEN;
485 return -EINVAL;
486 }
487
488 /* send to LAPD */
489 return lapd_ph_data_ind(msg, &lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200490}
491
492/* Start a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
493int lapd_sap_start(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
494{
495 struct lapd_sap *sap;
496 struct lapd_tei *teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200497 struct osmo_dlsap_prim dp;
498 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200499
500 teip = teip_from_tei(li, tei);
501 if (!teip)
502 teip = lapd_tei_alloc(li, tei);
503
504 sap = lapd_sap_find(teip, sapi);
505 if (sap)
506 return -EEXIST;
507
508 sap = lapd_sap_alloc(teip, sapi);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200509 if (!sap)
510 return -ENOMEM;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200511
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200512 LOGP(DLLAPD, LOGL_NOTICE, "LAPD DL-ESTABLISH request TEI=%d SAPI=%d\n",
513 tei, sapi);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200514
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200515 /* prepare prim */
516 msg = msgb_alloc_headroom(56, 56, "DL EST");
517 msg->l3h = msg->data;
518 osmo_prim_init(&dp.oph, 0, PRIM_DL_EST, PRIM_OP_REQUEST, msg);
519
520 /* send to L2 */
521 return lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200522}
523
524/* Stop a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
525int lapd_sap_stop(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
526{
527 struct lapd_tei *teip;
528 struct lapd_sap *sap;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200529 struct osmo_dlsap_prim dp;
530 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200531
532 teip = teip_from_tei(li, tei);
533 if (!teip)
534 return -ENODEV;
535
536 sap = lapd_sap_find(teip, sapi);
537 if (!sap)
538 return -ENODEV;
539
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200540 LOGP(DLLAPD, LOGL_NOTICE, "LAPD DL-RELEASE request TEI=%d SAPI=%d\n",
541 tei, sapi);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200542
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200543 /* prepare prim */
544 msg = msgb_alloc_headroom(56, 56, "DL REL");
545 msg->l3h = msg->data;
546 osmo_prim_init(&dp.oph, 0, PRIM_DL_REL, PRIM_OP_REQUEST, msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200547
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200548 /* send to L2 */
549 return lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200550}
551
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200552/* Transmit Data (DL-DATA request) on the given LAPD Instance / TEI / SAPI */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200553void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200554 struct msgb *msg)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200555{
556 struct lapd_tei *teip = teip_from_tei(li, tei);
557 struct lapd_sap *sap;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200558 struct osmo_dlsap_prim dp;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200559
560 if (!teip) {
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200561 LOGP(DLLAPD, LOGL_ERROR, "LAPD Cannot transmit on "
Harald Welte4ca16c72011-08-16 14:01:49 +0200562 "non-existing TEI %u\n", tei);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200563 msgb_free(msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200564 return;
565 }
566
567 sap = lapd_sap_find(teip, sapi);
568 if (!sap) {
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200569 LOGP(DLLAPD, LOGL_INFO, "LAPD Tx on unknown SAPI=%u "
570 "in TEI=%u\n", sapi, tei);
571 msgb_free(msg);
572 return;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200573 }
574
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200575 /* prepare prim */
576 msg->l3h = msg->data;
577 osmo_prim_init(&dp.oph, 0, PRIM_DL_DATA, PRIM_OP_REQUEST, msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200578
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200579 /* send to L2 */
580 lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200581};
582
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200583static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg)
584{
585 struct lapd_datalink *dl = lctx->dl;
586 struct lapd_sap *sap =
587 container_of(dl, struct lapd_sap, dl);
588 struct lapd_instance *li = sap->tei->li;
589 int format = lctx->format;
590 int addr_len;
591
592 /* control field */
593 switch (format) {
594 case LAPD_FORM_I:
595 msg->l2h = msgb_push(msg, 2);
596 msg->l2h[0] = LAPD_CTRL_I4(lctx->n_send);
597 msg->l2h[1] = LAPD_CTRL_I5(lctx->n_recv, lctx->p_f);
598 break;
599 case LAPD_FORM_S:
600 msg->l2h = msgb_push(msg, 2);
601 msg->l2h[0] = LAPD_CTRL_S4(lctx->s_u);
602 msg->l2h[1] = LAPD_CTRL_S5(lctx->n_recv, lctx->p_f);
603 break;
604 case LAPD_FORM_U:
605 msg->l2h = msgb_push(msg, 1);
606 msg->l2h[0] = LAPD_CTRL_U4(lctx->s_u, lctx->p_f);
607 break;
608 default:
609 msgb_free(msg);
610 return -EINVAL;
611 }
612 /* address field */
Andreas Eversberg3744b872011-09-27 12:12:36 +0200613 if (li->profile.short_address && lctx->tei == 0)
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200614 addr_len = 1;
615 else
616 addr_len = 2;
617 msg->l2h = msgb_push(msg, addr_len);
618 msg->l2h[0] = LAPD_ADDR2(lctx->sapi, lctx->cr);
619 if (addr_len == 1)
620 msg->l2h[0] |= 0x1;
621 else
622 msg->l2h[1] = LAPD_ADDR3(lctx->tei);
623
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200624 /* write to PCAP file, if enabled. */
625 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
626
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200627 /* forward frame to L1 */
628 LOGP(DLLAPD, LOGL_DEBUG, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
629 li->transmit_cb(msg, li->transmit_cbdata);
630
631 return 0;
632}
633
634/* A DL-SAP message is received from datalink instance and forwarded to L3 */
635static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
636{
637 struct lapd_datalink *dl = lctx->dl;
638 struct lapd_sap *sap =
639 container_of(dl, struct lapd_sap, dl);
640 struct lapd_instance *li;
641 uint8_t tei, sapi;
642 char *op = (dp->oph.operation == PRIM_OP_INDICATION) ? "indication"
643 : "confirm";
644
645 li = sap->tei->li;
646 tei = lctx->tei;
647 sapi = lctx->sapi;
648
649 switch (dp->oph.primitive) {
650 case PRIM_DL_EST:
651 LOGP(DLLAPD, LOGL_NOTICE, "LAPD DL-ESTABLISH %s TEI=%d "
652 "SAPI=%d\n", op, lctx->tei, lctx->sapi);
653 break;
654 case PRIM_DL_REL:
655 LOGP(DLLAPD, LOGL_NOTICE, "LAPD DL-RELEASE %s TEI=%d "
656 "SAPI=%d\n", op, lctx->tei, lctx->sapi);
657 lapd_sap_free(sap);
658 /* note: sap and dl is now gone, don't use it anymore */
659 break;
660 default:
661 ;
662 }
663
664 li->receive_cb(dp, tei, sapi, li->receive_cbdata);
665
666 return 0;
667}
668
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200669/* Allocate a new LAPD instance */
670struct lapd_instance *lapd_instance_alloc(int network_side,
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200671 void (*tx_cb)(struct msgb *msg, void *cbdata), void *tx_cbdata,
672 void (*rx_cb)(struct osmo_dlsap_prim *odp, uint8_t tei, uint8_t sapi,
673 void *rx_cbdata), void *rx_cbdata,
Andreas Eversberg3744b872011-09-27 12:12:36 +0200674 const struct lapd_profile *profile)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200675{
676 struct lapd_instance *li;
677
678 li = talloc_zero(NULL, struct lapd_instance);
679 if (!li)
680 return NULL;
681
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200682 li->network_side = network_side;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200683 li->transmit_cb = tx_cb;
684 li->transmit_cbdata = tx_cbdata;
685 li->receive_cb = rx_cb;
686 li->receive_cbdata = rx_cbdata;
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200687 li->pcap_fd = -1;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200688 memcpy(&li->profile, profile, sizeof(li->profile));
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200689
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200690 INIT_LLIST_HEAD(&li->tei_list);
691
692 return li;
693}
Harald Welte14078ea2011-08-24 09:45:11 +0200694
Philipp0c7d5f42016-10-19 18:38:58 +0200695/* Change lapd-profile on the fly (use with caution!) */
696void lapd_instance_set_profile(struct lapd_instance *li,
697 const struct lapd_profile *profile)
698{
699 memcpy(&li->profile, profile, sizeof(li->profile));
700}
701
Harald Welte14078ea2011-08-24 09:45:11 +0200702void lapd_instance_free(struct lapd_instance *li)
703{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200704 struct lapd_tei *teip, *teip2;
Harald Weltef350e252011-08-26 07:55:26 +0200705
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200706 /* Free all TEI instances */
707 llist_for_each_entry_safe(teip, teip2, &li->tei_list, list) {
708 lapd_tei_free(teip);
Harald Weltef350e252011-08-26 07:55:26 +0200709 }
710
Harald Welte14078ea2011-08-24 09:45:11 +0200711 talloc_free(li);
712}