blob: 5c0a6b62a1557e5958414d27637bf7ef26b4546e [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
Harald Welteb9031882020-05-02 21:09:15 +020076#define LOGLI(li, level, fmt, args ...) \
77 LOGP(DLLAPD, level, "%s: " fmt, (li)->name, ## args)
78
79#define LOGTEI(teip, level, fmt, args ...) \
80 LOGP(DLLAPD, level, "(%s-T%u): " fmt, (teip)->li->name, (teip)->tei, ## args)
81
82#define LOGSAP(sap, level, fmt, args ...) \
83 LOGP(DLLAPD, level, "%s: " fmt, (sap)->dl.name, ## args)
84
Harald Welte47c247b2020-07-03 19:05:44 +020085#define DLSAP_MSGB_SIZE 128
Harald Welteea7da442020-07-03 19:05:07 +020086#define DLSAP_MSGB_HEADROOM 56
87
Andreas Eversberg3744b872011-09-27 12:12:36 +020088const struct lapd_profile lapd_profile_isdn = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +010089 .k = LAPD_SET_K(7,7),
90 .n200 = 3,
91 .n201 = 260,
92 .n202 = 3,
93 .t200_sec = 1, .t200_usec = 0,
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
100const struct lapd_profile lapd_profile_abis = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +0100101 .k = LAPD_SET_K(2,1),
102 .n200 = 3,
103 .n201 = 260,
104 .n202 = 0, /* infinite */
105 .t200_sec = 0, .t200_usec = 240000,
106 .t201_sec = 1, .t201_usec = 0,
107 .t202_sec = 2, .t202_usec = 0,
108 .t203_sec = 10, .t203_usec = 0,
109 .short_address = 0
Andreas Eversberg3744b872011-09-27 12:12:36 +0200110};
111
Philipp0c7d5f42016-10-19 18:38:58 +0200112/* Ericssons OM2000 lapd dialect requires a sabm frame retransmission
113 * timeout of exactly 300 msek. Shorter or longer retransmission will
114 * cause the link establishment to fail permanently. Since the BTS is
115 * periodically scanning through all timeslots to find the timeslot
116 * where the bsc is transmitting its sabm frames the normal maximum
117 * retransmission (n200) of 3 is not enough. In order not to miss
Philipp Maierd75bac42017-02-01 13:51:03 +0100118 * the bts, n200 has been increased to 50, which is an educated
Philipp0c7d5f42016-10-19 18:38:58 +0200119 * guess. */
120
121const struct lapd_profile lapd_profile_abis_ericsson = {
122 .k = LAPD_SET_K(2,1),
Philipp Maierd75bac42017-02-01 13:51:03 +0100123 .n200 = 50,
Philipp0c7d5f42016-10-19 18:38:58 +0200124 .n201 = 260,
125 .n202 = 0, /* infinite */
126 .t200_sec = 0, .t200_usec = 300000,
127 .t201_sec = 1, .t201_usec = 0,
128 .t202_sec = 2, .t202_usec = 0,
129 .t203_sec = 10, .t203_usec = 0,
130 .short_address = 0
131};
132
Andreas Eversberg3744b872011-09-27 12:12:36 +0200133const struct lapd_profile lapd_profile_sat = {
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +0100134 .k = LAPD_SET_K(15,15),
135 .n200 = 5,
136 .n201 = 260,
137 .n202 = 5,
138 .t200_sec = 2, .t200_usec = 400000,
139 .t201_sec = 2, .t201_usec = 400000,
140 .t202_sec = 2, .t202_usec = 400000,
Holger Hans Peter Freyther4b6860d2013-03-09 17:32:33 +0100141 .t203_sec = 20, .t203_usec = 0,
Pablo Neira Ayusof42280b2012-03-12 18:17:31 +0100142 .short_address = 1
Andreas Eversberg3744b872011-09-27 12:12:36 +0200143};
144
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200145typedef enum {
146 LAPD_TEI_NONE = 0,
147 LAPD_TEI_ASSIGNED,
148 LAPD_TEI_ACTIVE,
149} lapd_tei_state;
150
151const char *lapd_tei_states[] = {
152 "NONE",
153 "ASSIGNED",
154 "ACTIVE",
155};
156
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200157/* Structure representing an allocated TEI within a LAPD instance. */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200158struct lapd_tei {
159 struct llist_head list;
160 struct lapd_instance *li;
161 uint8_t tei;
162 lapd_tei_state state;
163
164 struct llist_head sap_list;
165};
166
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200167/* Structure representing a SAP within a TEI. It includes exactly one datalink
168 * instance. */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200169struct lapd_sap {
170 struct llist_head list;
171 struct lapd_tei *tei;
172 uint8_t sapi;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200173
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200174 struct lapd_datalink dl;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200175};
176
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200177/* Resolve TEI structure from given numeric TEI */
178static struct lapd_tei *teip_from_tei(struct lapd_instance *li, uint8_t tei)
179{
180 struct lapd_tei *lt;
181
182 llist_for_each_entry(lt, &li->tei_list, list) {
183 if (lt->tei == tei)
184 return lt;
185 }
186 return NULL;
187};
188
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200189/* Change state of TEI */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200190static void lapd_tei_set_state(struct lapd_tei *teip, int newstate)
191{
Harald Welteb9031882020-05-02 21:09:15 +0200192 LOGTEI(teip, LOGL_INFO, "LAPD state change on TEI %d: %s -> %s\n",
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200193 teip->tei, lapd_tei_states[teip->state],
194 lapd_tei_states[newstate]);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200195 teip->state = newstate;
196};
197
198/* Allocate a new TEI */
199struct lapd_tei *lapd_tei_alloc(struct lapd_instance *li, uint8_t tei)
200{
201 struct lapd_tei *teip;
202
203 teip = talloc_zero(li, struct lapd_tei);
204 if (!teip)
205 return NULL;
206
207 teip->li = li;
208 teip->tei = tei;
209 llist_add(&teip->list, &li->tei_list);
210 INIT_LLIST_HEAD(&teip->sap_list);
211
212 lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
213
214 return teip;
215}
216
217/* Find a SAP within a given TEI */
218static struct lapd_sap *lapd_sap_find(struct lapd_tei *teip, uint8_t sapi)
219{
220 struct lapd_sap *sap;
221
222 llist_for_each_entry(sap, &teip->sap_list, list) {
223 if (sap->sapi == sapi)
224 return sap;
225 }
226
227 return NULL;
228}
229
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200230static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg);
231static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200232
233/* Allocate a new SAP within a given TEI */
234static struct lapd_sap *lapd_sap_alloc(struct lapd_tei *teip, uint8_t sapi)
235{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200236 struct lapd_sap *sap;
237 struct lapd_datalink *dl;
Harald Welteb9031882020-05-02 21:09:15 +0200238 struct lapd_instance *li = teip->li;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200239 struct lapd_profile *profile;
Harald Welteb9031882020-05-02 21:09:15 +0200240 char name[256];
Andreas Eversberg3744b872011-09-27 12:12:36 +0200241 int k;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200242
Harald Welteb9031882020-05-02 21:09:15 +0200243 snprintf(name, sizeof(name), "(%s-T%u-S%u)", li->name, teip->tei, sapi);
244
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200245 sap = talloc_zero(teip, struct lapd_sap);
246 if (!sap)
247 return NULL;
248
Philipp Maier027e1192016-12-08 17:17:33 +0100249 LOGP(DLLAPD, LOGL_NOTICE,
Harald Welteb9031882020-05-02 21:09:15 +0200250 "%s: LAPD Allocating SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n",
251 name, sapi, teip->tei, &sap->dl, sap);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200252
253 sap->sapi = sapi;
254 sap->tei = teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200255 dl = &sap->dl;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200256 profile = &li->profile;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200257
Andreas Eversberg3c460442011-09-28 02:46:16 +0200258 k = profile->k[sapi & 0x3f];
Harald Welteb9031882020-05-02 21:09:15 +0200259 LOGP(DLLAPD, LOGL_NOTICE, "%s: k=%d N200=%d N201=%d T200=%d.%d T203=%d.%d\n",
260 name, k, profile->n200, profile->n201, profile->t200_sec,
Andreas Eversberg3c460442011-09-28 02:46:16 +0200261 profile->t200_usec, profile->t203_sec, profile->t203_usec);
Andreas Eversberg3744b872011-09-27 12:12:36 +0200262 lapd_dl_init(dl, k, 128, profile->n201);
Harald Welteb9031882020-05-02 21:09:15 +0200263 lapd_dl_set_name(dl, name);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200264 dl->use_sabme = 1; /* use SABME instead of SABM (GSM) */
265 dl->send_ph_data_req = send_ph_data_req;
266 dl->send_dlsap = send_dlsap;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200267 dl->n200 = profile->n200;
268 dl->n200_est_rel = profile->n200;
269 dl->t200_sec = profile->t200_sec; dl->t200_usec = profile->t200_usec;
270 dl->t203_sec = profile->t203_sec; dl->t203_usec = profile->t203_usec;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200271 dl->lctx.dl = &sap->dl;
272 dl->lctx.sapi = sapi;
273 dl->lctx.tei = teip->tei;
Andreas Eversberg3744b872011-09-27 12:12:36 +0200274 dl->lctx.n201 = profile->n201;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200275
276 lapd_set_mode(&sap->dl, (teip->li->network_side) ? LAPD_MODE_NETWORK
277 : LAPD_MODE_USER);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200278
279 llist_add(&sap->list, &teip->sap_list);
280
281 return sap;
282}
283
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200284/* Free SAP instance, including the datalink */
285static void lapd_sap_free(struct lapd_sap *sap)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200286{
Harald Welteb9031882020-05-02 21:09:15 +0200287 LOGSAP(sap, LOGL_NOTICE,
Philipp Maier027e1192016-12-08 17:17:33 +0100288 "LAPD Freeing SAP for SAPI=%u / TEI=%u (dl=%p, sap=%p)\n",
289 sap->sapi, sap->tei->tei, &sap->dl, sap);
290
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200291 /* free datalink structures and timers */
292 lapd_dl_exit(&sap->dl);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200293
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200294 llist_del(&sap->list);
295 talloc_free(sap);
296}
297
298/* Free TEI instance */
299static void lapd_tei_free(struct lapd_tei *teip)
300{
301 struct lapd_sap *sap, *sap2;
302
303 llist_for_each_entry_safe(sap, sap2, &teip->sap_list, list) {
304 lapd_sap_free(sap);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200305 }
306
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200307 llist_del(&teip->list);
308 talloc_free(teip);
309}
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200310
311/* Input function into TEI manager */
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200312static int lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200313{
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200314 uint8_t entity;
315 uint8_t ref;
316 uint8_t mt;
317 uint8_t action;
318 uint8_t e;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200319 uint8_t resp[8];
320 struct lapd_tei *teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200321 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200322
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200323 if (len < 5) {
Harald Welteb9031882020-05-02 21:09:15 +0200324 LOGLI(li, LOGL_ERROR, "LAPD TEIMGR frame receive len %d < 5"
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200325 ", ignoring\n", len);
326 return -EINVAL;
327 };
328
329 entity = data[0];
330 ref = data[1];
331 mt = data[3];
332 action = data[4] >> 1;
333 e = data[4] & 1;
334
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200335 DEBUGP(DLLAPD, "LAPD TEIMGR: entity %x, ref %x, mt %x, action %x, "
336 "e %x\n", entity, ref, mt, action, e);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200337
338 switch (mt) {
339 case 0x01: /* IDENTITY REQUEST */
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200340 DEBUGP(DLLAPD, "LAPD TEIMGR: identity request for TEI %u\n",
341 action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200342
343 teip = teip_from_tei(li, action);
344 if (!teip) {
Harald Welteb9031882020-05-02 21:09:15 +0200345 LOGLI(li, LOGL_INFO, "TEI MGR: New TEI %u\n",
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200346 action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200347 teip = lapd_tei_alloc(li, action);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200348 if (!teip)
349 return -ENOMEM;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200350 }
351
352 /* Send ACCEPT */
353 memmove(resp, "\xfe\xff\x03\x0f\x00\x00\x02\x00", 8);
354 resp[7] = (action << 1) | 1;
Harald Welteea7da442020-07-03 19:05:07 +0200355 msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL EST");
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200356 msg->l2h = msgb_push(msg, 8);
357 memcpy(msg->l2h, resp, 8);
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200358
359 /* write to PCAP file, if enabled. */
360 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
361
Harald Welteb9031882020-05-02 21:09:15 +0200362 LOGTEI(teip, LOGL_DEBUG, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200363 li->transmit_cb(msg, li->transmit_cbdata);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200364
365 if (teip->state == LAPD_TEI_NONE)
366 lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
367 break;
368 default:
Harald Welteb9031882020-05-02 21:09:15 +0200369 LOGLI(li, LOGL_NOTICE, "LAPD TEIMGR: unknown mt %x action %x\n", mt, action);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200370 break;
371 };
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200372
373 return 0;
374}
375
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200376/* General input function for any data received for this LAPD instance */
377int lapd_receive(struct lapd_instance *li, struct msgb *msg, int *error)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200378{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200379 int i;
380 struct lapd_msg_ctx lctx;
381 int rc;
382 struct lapd_sap *sap;
383 struct lapd_tei *teip;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200384
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200385 /* write to PCAP file, if enabled. */
386 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_INPUT, msg);
387
Harald Welteb9031882020-05-02 21:09:15 +0200388 LOGLI(li, LOGL_DEBUG, "RX: %s\n", osmo_hexdump(msg->data, msg->len));
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200389 if (msg->len < 2) {
Harald Welteb9031882020-05-02 21:09:15 +0200390 LOGLI(li, LOGL_ERROR, "LAPD frame receive len %d < 2, ignoring\n", msg->len);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200391 *error = LAPD_ERR_BAD_LEN;
392 return -EINVAL;
393 };
394 msg->l2h = msg->data;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200395
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200396 memset(&lctx, 0, sizeof(lctx));
397
398 i = 0;
399 /* adress field */
400 lctx.sapi = LAPD_ADDR_SAPI(msg->l2h[i]);
401 lctx.cr = LAPD_ADDR_CR(msg->l2h[i]);
402 lctx.lpd = 0;
403 if (!LAPD_ADDR_EA(msg->l2h[i])) {
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200404 if (msg->len < 3) {
Harald Welteb9031882020-05-02 21:09:15 +0200405 LOGLI(li, LOGL_ERROR, "LAPD frame with TEI receive "
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200406 "len %d < 3, ignoring\n", msg->len);
407 *error = LAPD_ERR_BAD_LEN;
408 return -EINVAL;
409 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200410 i++;
411 lctx.tei = LAPD_ADDR_TEI(msg->l2h[i]);
412 }
413 i++;
414 /* control field */
415 if (LAPD_CTRL_is_I(msg->l2h[i])) {
416 lctx.format = LAPD_FORM_I;
417 lctx.n_send = LAPD_CTRL_I_Ns(msg->l2h[i]);
418 i++;
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200419 if (msg->len < 3 && i == 2) {
Harald Welteb9031882020-05-02 21:09:15 +0200420 LOGLI(li, LOGL_ERROR, "LAPD I frame without TEI "
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200421 "receive len %d < 3, ignoring\n", msg->len);
422 *error = LAPD_ERR_BAD_LEN;
423 return -EINVAL;
424 };
425 if (msg->len < 4 && i == 3) {
Harald Welteb9031882020-05-02 21:09:15 +0200426 LOGLI(li, LOGL_ERROR, "LAPD I frame with TEI "
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200427 "receive len %d < 4, ignoring\n", msg->len);
428 *error = LAPD_ERR_BAD_LEN;
429 return -EINVAL;
430 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200431 lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]);
432 lctx.p_f = LAPD_CTRL_I_P(msg->l2h[i]);
433 } else if (LAPD_CTRL_is_S(msg->l2h[i])) {
434 lctx.format = LAPD_FORM_S;
435 lctx.s_u = LAPD_CTRL_S_BITS(msg->l2h[i]);
436 i++;
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200437 if (msg->len < 3 && i == 2) {
Harald Welteb9031882020-05-02 21:09:15 +0200438 LOGLI(li, LOGL_ERROR, "LAPD S frame without TEI "
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200439 "receive len %d < 3, ignoring\n", msg->len);
440 *error = LAPD_ERR_BAD_LEN;
441 return -EINVAL;
442 };
443 if (msg->len < 4 && i == 3) {
Harald Welteb9031882020-05-02 21:09:15 +0200444 LOGLI(li, LOGL_ERROR, "LAPD S frame with TEI "
Andreas Eversberg8aaed052011-10-01 04:10:57 +0200445 "receive len %d < 4, ignoring\n", msg->len);
446 *error = LAPD_ERR_BAD_LEN;
447 return -EINVAL;
448 };
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200449 lctx.n_recv = LAPD_CTRL_Nr(msg->l2h[i]);
450 lctx.p_f = LAPD_CTRL_S_PF(msg->l2h[i]);
451 } else if (LAPD_CTRL_is_U(msg->l2h[i])) {
452 lctx.format = LAPD_FORM_U;
453 lctx.s_u = LAPD_CTRL_U_BITS(msg->l2h[i]);
454 lctx.p_f = LAPD_CTRL_U_PF(msg->l2h[i]);
455 } else
456 lctx.format = LAPD_FORM_UKN;
457 i++;
458 /* length */
459 msg->l3h = msg->l2h + i;
460 msgb_pull(msg, i);
461 lctx.length = msg->len;
462
463 /* perform TEI assignment, if received */
464 if (lctx.tei == 127) {
465 rc = lapd_tei_receive(li, msg->data, msg->len);
466 msgb_free(msg);
467 return rc;
468 }
469
470 /* resolve TEI and SAPI */
471 teip = teip_from_tei(li, lctx.tei);
472 if (!teip) {
Harald Welteb9031882020-05-02 21:09:15 +0200473 LOGLI(li, LOGL_NOTICE, "LAPD Unknown TEI %u\n", lctx.tei);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200474 *error = LAPD_ERR_UNKNOWN_TEI;
475 msgb_free(msg);
476 return -EINVAL;
477 }
478 sap = lapd_sap_find(teip, lctx.sapi);
479 if (!sap) {
Harald Welteb9031882020-05-02 21:09:15 +0200480 LOGTEI(teip, LOGL_INFO, "LAPD No SAP for TEI=%u / SAPI=%u, "
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200481 "allocating\n", lctx.tei, lctx.sapi);
482 sap = lapd_sap_alloc(teip, lctx.sapi);
483 if (!sap) {
484 *error = LAPD_ERR_NO_MEM;
485 msgb_free(msg);
486 return -ENOMEM;
487 }
488 }
489 lctx.dl = &sap->dl;
490 lctx.n201 = lctx.dl->maxf;
491
492 if (msg->len > lctx.n201) {
Harald Welteb9031882020-05-02 21:09:15 +0200493 LOGSAP(sap, LOGL_ERROR, "message len %d > N201(%d) "
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200494 "(discarding)\n", msg->len, lctx.n201);
495 msgb_free(msg);
496 *error = LAPD_ERR_BAD_LEN;
497 return -EINVAL;
498 }
499
500 /* send to LAPD */
501 return lapd_ph_data_ind(msg, &lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200502}
503
504/* Start a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
505int lapd_sap_start(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
506{
507 struct lapd_sap *sap;
508 struct lapd_tei *teip;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200509 struct osmo_dlsap_prim dp;
510 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200511
512 teip = teip_from_tei(li, tei);
513 if (!teip)
514 teip = lapd_tei_alloc(li, tei);
515
516 sap = lapd_sap_find(teip, sapi);
517 if (sap)
518 return -EEXIST;
519
520 sap = lapd_sap_alloc(teip, sapi);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200521 if (!sap)
522 return -ENOMEM;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200523
Harald Welteb9031882020-05-02 21:09:15 +0200524 LOGSAP(sap, LOGL_NOTICE, "LAPD DL-ESTABLISH request TEI=%d SAPI=%d\n", tei, sapi);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200525
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200526 /* prepare prim */
Harald Welteea7da442020-07-03 19:05:07 +0200527 msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL EST");
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200528 msg->l3h = msg->data;
529 osmo_prim_init(&dp.oph, 0, PRIM_DL_EST, PRIM_OP_REQUEST, msg);
530
531 /* send to L2 */
532 return lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200533}
534
535/* Stop a (user-side) SAP for the specified TEI/SAPI on the LAPD instance */
536int lapd_sap_stop(struct lapd_instance *li, uint8_t tei, uint8_t sapi)
537{
538 struct lapd_tei *teip;
539 struct lapd_sap *sap;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200540 struct osmo_dlsap_prim dp;
541 struct msgb *msg;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200542
543 teip = teip_from_tei(li, tei);
544 if (!teip)
545 return -ENODEV;
546
547 sap = lapd_sap_find(teip, sapi);
548 if (!sap)
549 return -ENODEV;
550
Harald Welteb9031882020-05-02 21:09:15 +0200551 LOGSAP(sap, LOGL_NOTICE, "LAPD DL-RELEASE request TEI=%d SAPI=%d\n", tei, sapi);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200552
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200553 /* prepare prim */
Harald Welteea7da442020-07-03 19:05:07 +0200554 msg = msgb_alloc_headroom(DLSAP_MSGB_SIZE, DLSAP_MSGB_HEADROOM, "DL REL");
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200555 msg->l3h = msg->data;
556 osmo_prim_init(&dp.oph, 0, PRIM_DL_REL, PRIM_OP_REQUEST, msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200557
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200558 /* send to L2 */
559 return lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200560}
561
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200562/* Transmit Data (DL-DATA request) on the given LAPD Instance / TEI / SAPI */
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200563void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t sapi,
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200564 struct msgb *msg)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200565{
566 struct lapd_tei *teip = teip_from_tei(li, tei);
567 struct lapd_sap *sap;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200568 struct osmo_dlsap_prim dp;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200569
570 if (!teip) {
Harald Welteb9031882020-05-02 21:09:15 +0200571 LOGLI(li, LOGL_ERROR, "LAPD Cannot transmit on non-existing TEI %u\n", tei);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200572 msgb_free(msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200573 return;
574 }
575
576 sap = lapd_sap_find(teip, sapi);
577 if (!sap) {
Harald Welteb9031882020-05-02 21:09:15 +0200578 LOGTEI(teip, LOGL_INFO, "LAPD Tx on unknown SAPI=%u in TEI=%u\n", sapi, tei);
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200579 msgb_free(msg);
580 return;
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200581 }
582
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200583 /* prepare prim */
584 msg->l3h = msg->data;
585 osmo_prim_init(&dp.oph, 0, PRIM_DL_DATA, PRIM_OP_REQUEST, msg);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200586
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200587 /* send to L2 */
588 lapd_recv_dlsap(&dp, &sap->dl.lctx);
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200589};
590
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200591static int send_ph_data_req(struct lapd_msg_ctx *lctx, struct msgb *msg)
592{
593 struct lapd_datalink *dl = lctx->dl;
594 struct lapd_sap *sap =
595 container_of(dl, struct lapd_sap, dl);
596 struct lapd_instance *li = sap->tei->li;
597 int format = lctx->format;
598 int addr_len;
599
600 /* control field */
601 switch (format) {
602 case LAPD_FORM_I:
603 msg->l2h = msgb_push(msg, 2);
604 msg->l2h[0] = LAPD_CTRL_I4(lctx->n_send);
605 msg->l2h[1] = LAPD_CTRL_I5(lctx->n_recv, lctx->p_f);
606 break;
607 case LAPD_FORM_S:
608 msg->l2h = msgb_push(msg, 2);
609 msg->l2h[0] = LAPD_CTRL_S4(lctx->s_u);
610 msg->l2h[1] = LAPD_CTRL_S5(lctx->n_recv, lctx->p_f);
611 break;
612 case LAPD_FORM_U:
613 msg->l2h = msgb_push(msg, 1);
614 msg->l2h[0] = LAPD_CTRL_U4(lctx->s_u, lctx->p_f);
615 break;
616 default:
617 msgb_free(msg);
618 return -EINVAL;
619 }
620 /* address field */
Andreas Eversberg3744b872011-09-27 12:12:36 +0200621 if (li->profile.short_address && lctx->tei == 0)
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200622 addr_len = 1;
623 else
624 addr_len = 2;
625 msg->l2h = msgb_push(msg, addr_len);
626 msg->l2h[0] = LAPD_ADDR2(lctx->sapi, lctx->cr);
627 if (addr_len == 1)
628 msg->l2h[0] |= 0x1;
629 else
630 msg->l2h[1] = LAPD_ADDR3(lctx->tei);
631
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200632 /* write to PCAP file, if enabled. */
633 osmo_pcap_lapd_write(li->pcap_fd, OSMO_LAPD_PCAP_OUTPUT, msg);
634
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200635 /* forward frame to L1 */
Harald Welteb9031882020-05-02 21:09:15 +0200636 LOGDL(dl, LOGL_DEBUG, "TX: %s\n", osmo_hexdump(msg->data, msg->len));
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200637 li->transmit_cb(msg, li->transmit_cbdata);
638
639 return 0;
640}
641
642/* A DL-SAP message is received from datalink instance and forwarded to L3 */
643static int send_dlsap(struct osmo_dlsap_prim *dp, struct lapd_msg_ctx *lctx)
644{
645 struct lapd_datalink *dl = lctx->dl;
646 struct lapd_sap *sap =
647 container_of(dl, struct lapd_sap, dl);
648 struct lapd_instance *li;
649 uint8_t tei, sapi;
650 char *op = (dp->oph.operation == PRIM_OP_INDICATION) ? "indication"
651 : "confirm";
652
653 li = sap->tei->li;
654 tei = lctx->tei;
655 sapi = lctx->sapi;
656
657 switch (dp->oph.primitive) {
658 case PRIM_DL_EST:
Harald Welteb9031882020-05-02 21:09:15 +0200659 LOGDL(dl, LOGL_NOTICE, "LAPD DL-ESTABLISH %s TEI=%d "
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200660 "SAPI=%d\n", op, lctx->tei, lctx->sapi);
661 break;
662 case PRIM_DL_REL:
Harald Welteb9031882020-05-02 21:09:15 +0200663 LOGDL(dl, LOGL_NOTICE, "LAPD DL-RELEASE %s TEI=%d "
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200664 "SAPI=%d\n", op, lctx->tei, lctx->sapi);
665 lapd_sap_free(sap);
666 /* note: sap and dl is now gone, don't use it anymore */
667 break;
668 default:
669 ;
670 }
671
672 li->receive_cb(dp, tei, sapi, li->receive_cbdata);
673
674 return 0;
675}
676
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200677/* Allocate a new LAPD instance */
Harald Welteb9031882020-05-02 21:09:15 +0200678struct lapd_instance *lapd_instance_alloc2(int network_side,
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200679 void (*tx_cb)(struct msgb *msg, void *cbdata), void *tx_cbdata,
Harald Welteb9031882020-05-02 21:09:15 +0200680 void (*rx_cb)(struct osmo_dlsap_prim *odp, uint8_t tei, uint8_t sapi,
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200681 void *rx_cbdata), void *rx_cbdata,
Harald Welteb9031882020-05-02 21:09:15 +0200682 const struct lapd_profile *profile, const char *name)
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200683{
684 struct lapd_instance *li;
685
686 li = talloc_zero(NULL, struct lapd_instance);
687 if (!li)
688 return NULL;
689
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200690 li->network_side = network_side;
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200691 li->transmit_cb = tx_cb;
692 li->transmit_cbdata = tx_cbdata;
693 li->receive_cb = rx_cb;
694 li->receive_cbdata = rx_cbdata;
Pablo Neira Ayuso95306002012-08-22 16:43:59 +0200695 li->pcap_fd = -1;
Harald Welteb9031882020-05-02 21:09:15 +0200696 li->name = talloc_strdup(li, name);
Andreas Eversberg3744b872011-09-27 12:12:36 +0200697 memcpy(&li->profile, profile, sizeof(li->profile));
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200698
Pablo Neira Ayuso0ba77d52011-06-05 18:32:44 +0200699 INIT_LLIST_HEAD(&li->tei_list);
700
701 return li;
702}
Harald Welte14078ea2011-08-24 09:45:11 +0200703
Harald Welteb9031882020-05-02 21:09:15 +0200704struct lapd_instance *lapd_instance_alloc(int network_side,
705 void (*tx_cb)(struct msgb *msg, void *cbdata), void *tx_cbdata,
706 void (*rx_cb)(struct osmo_dlsap_prim *odp, uint8_t tei, uint8_t sapi,
707 void *rx_cbdata), void *rx_cbdata,
708 const struct lapd_profile *profile)
709{
710 return lapd_instance_alloc2(network_side, tx_cbdata, tx_cb, rx_cb, rx_cbdata, profile, NULL);
711}
712
713
Philipp0c7d5f42016-10-19 18:38:58 +0200714/* Change lapd-profile on the fly (use with caution!) */
715void lapd_instance_set_profile(struct lapd_instance *li,
716 const struct lapd_profile *profile)
717{
718 memcpy(&li->profile, profile, sizeof(li->profile));
719}
720
Harald Welte14078ea2011-08-24 09:45:11 +0200721void lapd_instance_free(struct lapd_instance *li)
722{
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200723 struct lapd_tei *teip, *teip2;
Harald Weltef350e252011-08-26 07:55:26 +0200724
Andreas Eversberga7ff0012011-09-26 11:29:30 +0200725 /* Free all TEI instances */
726 llist_for_each_entry_safe(teip, teip2, &li->tei_list, list) {
727 lapd_tei_free(teip);
Harald Weltef350e252011-08-26 07:55:26 +0200728 }
729
Harald Welte14078ea2011-08-24 09:45:11 +0200730 talloc_free(li);
731}