[LAPD] Support multiple instances of LAPD
We cannot afford static/global state, as we may have multiple E1 lines, each having its own LAPD instance. Furthermore, we might even have multiple LAPD instances on the same E1 line (think of a multi-drop setup). This also implements dynamic TEI allocation, i.e. no hardcoded TEI list anymore.
This commit is contained in:
parent
0ae575536a
commit
d38f10593a
|
@ -87,7 +87,11 @@ struct e1inp_ts {
|
||||||
/* ip.access driver has one fd for each ts */
|
/* ip.access driver has one fd for each ts */
|
||||||
struct bsc_fd fd;
|
struct bsc_fd fd;
|
||||||
} ipaccess;
|
} ipaccess;
|
||||||
|
struct {
|
||||||
|
/* DAHDI driver has one fd for each ts */
|
||||||
|
struct bsc_fd fd;
|
||||||
|
struct lapd_instance *lapd;
|
||||||
|
} dahdi;
|
||||||
} driver;
|
} driver;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ static int handle_ts1_read(struct bsc_fd *bfd)
|
||||||
lapd_mph_type prim;
|
lapd_mph_type prim;
|
||||||
unsigned int sapi, tei;
|
unsigned int sapi, tei;
|
||||||
int ilen, ret;
|
int ilen, ret;
|
||||||
|
uint8_t *idata;
|
||||||
|
|
||||||
if (!msg)
|
if (!msg)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
@ -81,7 +82,9 @@ static int handle_ts1_read(struct bsc_fd *bfd)
|
||||||
|
|
||||||
DEBUGP(DMI, "<= len = %d, sapi(%d) tei(%d)", ret, sapi, tei);
|
DEBUGP(DMI, "<= len = %d, sapi(%d) tei(%d)", ret, sapi, tei);
|
||||||
|
|
||||||
uint8_t *idata = lapd_receive(msg->data, msg->len, &ilen, &prim, bfd);
|
idata = lapd_receive(e1i_ts->driver.dahdi.lapd, msg->data, msg->len, &ilen, &prim);
|
||||||
|
if (!idata)
|
||||||
|
return -EIO;
|
||||||
|
|
||||||
msgb_pull(msg, 2);
|
msgb_pull(msg, 2);
|
||||||
|
|
||||||
|
@ -126,7 +129,7 @@ static int ts_want_write(struct e1inp_ts *e1i_ts)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
e1i_ts->driver.misdn.fd.when |= BSC_FD_WRITE;
|
e1i_ts->driver.dahdi.fd.when |= BSC_FD_WRITE;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -167,7 +170,7 @@ static int handle_ts1_write(struct bsc_fd *bfd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
lapd_transmit(sign_link->tei, msg->data, msg->len, bfd);
|
lapd_transmit(e1i_ts->driver.dahdi.lapd, sign_link->tei, msg->data, msg->len);
|
||||||
msgb_free(msg);
|
msgb_free(msg);
|
||||||
|
|
||||||
/* set tx delay timer for next event */
|
/* set tx delay timer for next event */
|
||||||
|
@ -353,7 +356,7 @@ void dahdi_set_bufinfo(int fd, int as_sigchan)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dahdi_e1_setup(struct e1inp_line *line, int release_l2)
|
static int dahdi_e1_setup(struct e1inp_line *line)
|
||||||
{
|
{
|
||||||
int ts, ret;
|
int ts, ret;
|
||||||
|
|
||||||
|
@ -362,7 +365,7 @@ static int dahdi_e1_setup(struct e1inp_line *line, int release_l2)
|
||||||
unsigned int idx = ts-1;
|
unsigned int idx = ts-1;
|
||||||
char openstr[128];
|
char openstr[128];
|
||||||
struct e1inp_ts *e1i_ts = &line->ts[idx];
|
struct e1inp_ts *e1i_ts = &line->ts[idx];
|
||||||
struct bsc_fd *bfd = &e1i_ts->driver.misdn.fd;
|
struct bsc_fd *bfd = &e1i_ts->driver.dahdi.fd;
|
||||||
|
|
||||||
bfd->data = line;
|
bfd->data = line;
|
||||||
bfd->priv_nr = ts;
|
bfd->priv_nr = ts;
|
||||||
|
@ -382,6 +385,7 @@ static int dahdi_e1_setup(struct e1inp_line *line, int release_l2)
|
||||||
}
|
}
|
||||||
bfd->when = BSC_FD_READ;
|
bfd->when = BSC_FD_READ;
|
||||||
dahdi_set_bufinfo(bfd->fd, 1);
|
dahdi_set_bufinfo(bfd->fd, 1);
|
||||||
|
e1i_ts->driver.dahdi.lapd = lapd_instance_alloc(dahdi_write_msg, bfd);
|
||||||
break;
|
break;
|
||||||
case E1INP_TS_TYPE_TRAU:
|
case E1INP_TS_TYPE_TRAU:
|
||||||
bfd->fd = open(openstr, O_RDWR | O_NONBLOCK);
|
bfd->fd = open(openstr, O_RDWR | O_NONBLOCK);
|
||||||
|
@ -417,24 +421,16 @@ static int dahdi_e1_setup(struct e1inp_line *line, int release_l2)
|
||||||
|
|
||||||
static int dahdi_e1_line_update(struct e1inp_line *line)
|
static int dahdi_e1_line_update(struct e1inp_line *line)
|
||||||
{
|
{
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (line->driver != &dahdi_driver)
|
if (line->driver != &dahdi_driver)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
init_flip_bits();
|
return dahdi_e1_setup(line);
|
||||||
|
|
||||||
ret = dahdi_e1_setup(line, 1);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
lapd_transmit_cb = dahdi_write_msg;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int e1inp_dahdi_init(void)
|
int e1inp_dahdi_init(void)
|
||||||
{
|
{
|
||||||
|
init_flip_bits();
|
||||||
|
|
||||||
/* register the driver with the core */
|
/* register the driver with the core */
|
||||||
return e1inp_driver_register(&dahdi_driver);
|
return e1inp_driver_register(&dahdi_driver);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,26 @@
|
||||||
|
/* OpenBSC minimal LAPD implementation */
|
||||||
|
|
||||||
/*
|
/* (C) 2009 by oystein@homelien.no
|
||||||
* minimal standalone network-side lap-d implementation
|
* (C) 2011 by Harald Welte <laforge@gnumonks.org>
|
||||||
* oystein@homelien.no, 2009
|
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||||
|
* (C) 2010 by Digium and Matthew Fredrickson <creslin@digium.com>
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -9,7 +28,10 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "lapd.h"
|
#include "lapd.h"
|
||||||
#include "openbsc/debug.h"
|
|
||||||
|
#include <osmocore/linuxlist.h>
|
||||||
|
#include <osmocore/talloc.h>
|
||||||
|
#include <openbsc/debug.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LAPD_TEI_NONE = 0,
|
LAPD_TEI_NONE = 0,
|
||||||
|
@ -70,17 +92,18 @@ const char *lapd_cmd_types[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *lapd_msg_types = "?ISU";
|
const char *lapd_msg_types = "?ISU";
|
||||||
const int network_side = 1; /* 0 for user side */
|
|
||||||
|
|
||||||
typedef struct {
|
struct lapd_tei {
|
||||||
int tei;
|
struct llist_head list;
|
||||||
int sapi;
|
|
||||||
|
uint8_t tei;
|
||||||
|
uint8_t sapi;
|
||||||
/* A valid N(R) value is one that is in the range V(A) ≤ N(R) ≤ V(S). */
|
/* A valid N(R) value is one that is in the range V(A) ≤ N(R) ≤ V(S). */
|
||||||
int vs; /* next to be transmitted */
|
int vs; /* next to be transmitted */
|
||||||
int va; /* last acked by peer */
|
int va; /* last acked by peer */
|
||||||
int vr; /* next expected to be received */
|
int vr; /* next expected to be received */
|
||||||
lapd_tei_state state;
|
lapd_tei_state state;
|
||||||
} lapd_tei_t;
|
};
|
||||||
|
|
||||||
/* 3.5.2.2 Send state variable V(S)
|
/* 3.5.2.2 Send state variable V(S)
|
||||||
* Each point-to-point data link connection endpoint shall have an associated V(S) when using I frame
|
* Each point-to-point data link connection endpoint shall have an associated V(S) when using I frame
|
||||||
|
@ -117,63 +140,59 @@ typedef struct {
|
||||||
* of N(R) is set equal to V(R). N(R) indicates that the data link layer entity transmitting the N(R) has
|
* of N(R) is set equal to V(R). N(R) indicates that the data link layer entity transmitting the N(R) has
|
||||||
* correctly received all I frames numbered up to and including N(R) − 1.
|
* correctly received all I frames numbered up to and including N(R) − 1.
|
||||||
*/
|
*/
|
||||||
void (*lapd_transmit_cb) (uint8_t * data, int len, void *cbdata);
|
|
||||||
|
|
||||||
static lapd_tei_t tei_list[] = {
|
static struct lapd_tei *teip_from_tei(struct lapd_instance *li, uint8_t tei)
|
||||||
{25, 62,},
|
|
||||||
{1, 0,},
|
|
||||||
{-1},
|
|
||||||
};
|
|
||||||
|
|
||||||
static lapd_tei_t *teip_from_tei(int tei)
|
|
||||||
{
|
{
|
||||||
lapd_tei_t *p;
|
struct lapd_tei *lt;
|
||||||
for (p = tei_list; p->tei != -1; p++) {
|
|
||||||
if (p->tei == tei)
|
llist_for_each_entry(lt, &li->tei_list, list) {
|
||||||
return p;
|
if (lt->tei == tei)
|
||||||
};
|
return lt;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void lapd_tei_set_state(lapd_tei_t * teip, int newstate)
|
static void lapd_tei_set_state(struct lapd_tei *teip, int newstate)
|
||||||
{
|
{
|
||||||
DEBUGP(DMI, "state change on tei %d: %s -> %s\n", teip->tei,
|
DEBUGP(DMI, "state change on tei %d: %s -> %s\n", teip->tei,
|
||||||
lapd_tei_states[teip->state], lapd_tei_states[newstate]);
|
lapd_tei_states[teip->state], lapd_tei_states[newstate]);
|
||||||
teip->state = newstate;
|
teip->state = newstate;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void lapd_tei_receive(uint8_t * data, int len, void *cbdata)
|
static void lapd_tei_receive(struct lapd_instance *li, uint8_t *data, int len)
|
||||||
{
|
{
|
||||||
int entity = data[0];
|
int entity = data[0];
|
||||||
int ref = data[1];
|
int ref = data[1];
|
||||||
int mt = data[3];
|
int mt = data[3];
|
||||||
int action = data[4] >> 1;
|
int action = data[4] >> 1;
|
||||||
int e = data[4] & 1;
|
int e = data[4] & 1;
|
||||||
|
int tei;
|
||||||
|
uint8_t resp[8];
|
||||||
|
struct lapd_tei *teip;
|
||||||
|
|
||||||
DEBUGP(DMI, "tei mgmt: entity %x, ref %x, mt %x, action %x, e %x\n", entity, ref, mt, action, e);
|
DEBUGP(DMI, "tei mgmt: entity %x, ref %x, mt %x, action %x, e %x\n", entity, ref, mt, action, e);
|
||||||
|
|
||||||
switch (mt) {
|
switch (mt) {
|
||||||
case 0x01:{ // identity request
|
case 0x01: /* IDENTITY REQUEST */
|
||||||
int tei = action;
|
DEBUGP(DMI, "TEIMGR: identity request for TEI %u\n", tei);
|
||||||
uint8_t resp[8];
|
|
||||||
lapd_tei_t *teip;
|
|
||||||
|
|
||||||
DEBUGP(DMI, "tei mgmt: identity request, accepting "
|
teip = teip_from_tei(li, tei);
|
||||||
"tei %d\n", tei);
|
if (!teip) {
|
||||||
|
LOGP(DMI, LOGL_INFO, "TEI MGR: New TEI %u\n", tei);
|
||||||
|
teip = talloc_zero(li, struct lapd_tei);
|
||||||
|
teip->tei = tei;
|
||||||
|
llist_add(&teip->list, &li->tei_list);
|
||||||
|
lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send ACCEPT */
|
||||||
memmove(resp, "\xfe\xff\x03\x0f\x00\x00\x02\x00", 8);
|
memmove(resp, "\xfe\xff\x03\x0f\x00\x00\x02\x00", 8);
|
||||||
resp[7] = (tei << 1) | 1;
|
resp[7] = (tei << 1) | 1;
|
||||||
lapd_transmit_cb(resp, 8, cbdata);
|
li->transmit_cb(resp, 8, li->cbdata);
|
||||||
|
|
||||||
teip = teip_from_tei(tei);
|
|
||||||
if (!teip) {
|
|
||||||
LOGP(DMI, LOGL_NOTICE, "Message for unknown "
|
|
||||||
"TEI %u, LAPD code supports only "
|
|
||||||
"TEI 25, 1, 2\n", tei);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (teip->state == LAPD_TEI_NONE)
|
if (teip->state == LAPD_TEI_NONE)
|
||||||
lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
|
lapd_tei_set_state(teip, LAPD_TEI_ASSIGNED);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
LOGP(DMI, LOGL_NOTICE, "tei mgmt: unknown mt %x action %x\n",
|
LOGP(DMI, LOGL_NOTICE, "tei mgmt: unknown mt %x action %x\n",
|
||||||
mt, action);
|
mt, action);
|
||||||
|
@ -181,13 +200,13 @@ static void lapd_tei_receive(uint8_t * data, int len, void *cbdata)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t *lapd_receive(uint8_t * data, int len, int *ilen, lapd_mph_type * prim,
|
uint8_t *lapd_receive(struct lapd_instance *li, uint8_t * data, unsigned int len,
|
||||||
void *cbdata)
|
int *ilen, lapd_mph_type *prim)
|
||||||
{
|
{
|
||||||
uint8_t sapi, cr, tei, command;
|
uint8_t sapi, cr, tei, command;
|
||||||
int pf, ns, nr;
|
int pf, ns, nr;
|
||||||
uint8_t *contents;
|
uint8_t *contents;
|
||||||
lapd_tei_t *teip;
|
struct lapd_tei *teip;
|
||||||
|
|
||||||
uint8_t resp[8];
|
uint8_t resp[8];
|
||||||
int l = 0;
|
int l = 0;
|
||||||
|
@ -209,7 +228,7 @@ uint8_t *lapd_receive(uint8_t * data, int len, int *ilen, lapd_mph_type * prim,
|
||||||
sapi = data[0] >> 2;
|
sapi = data[0] >> 2;
|
||||||
cr = (data[0] >> 1) & 1;
|
cr = (data[0] >> 1) & 1;
|
||||||
tei = data[1] >> 1;
|
tei = data[1] >> 1;
|
||||||
command = network_side ^ cr;
|
command = li->network_side ^ cr;
|
||||||
//DEBUGP(DMI, " address sapi %x tei %d cmd %d cr %d\n", sapi, tei, command, cr);
|
//DEBUGP(DMI, " address sapi %x tei %d cmd %d cr %d\n", sapi, tei, command, cr);
|
||||||
|
|
||||||
if (len < 3) {
|
if (len < 3) {
|
||||||
|
@ -288,9 +307,9 @@ uint8_t *lapd_receive(uint8_t * data, int len, int *ilen, lapd_mph_type * prim,
|
||||||
*ilen = len - (contents - data);
|
*ilen = len - (contents - data);
|
||||||
|
|
||||||
if (tei == 127)
|
if (tei == 127)
|
||||||
lapd_tei_receive(contents, *ilen, cbdata);
|
lapd_tei_receive(li, contents, *ilen);
|
||||||
|
|
||||||
teip = teip_from_tei(tei);
|
teip = teip_from_tei(li, tei);
|
||||||
|
|
||||||
DEBUGP(DMI, "<- %c %s sapi %x tei %3d cmd %x pf %x ns %3d nr %3d "
|
DEBUGP(DMI, "<- %c %s sapi %x tei %3d cmd %x pf %x ns %3d nr %3d "
|
||||||
"ilen %d teip %p vs %d va %d vr %d len %d\n",
|
"ilen %d teip %p vs %d va %d vr %d len %d\n",
|
||||||
|
@ -330,7 +349,7 @@ uint8_t *lapd_receive(uint8_t * data, int len, int *ilen, lapd_mph_type * prim,
|
||||||
resp[l++] = data[0];
|
resp[l++] = data[0];
|
||||||
resp[l++] = (tei << 1) | 1;
|
resp[l++] = (tei << 1) | 1;
|
||||||
resp[l++] = 0x73;
|
resp[l++] = 0x73;
|
||||||
lapd_transmit_cb(resp, l, cbdata);
|
li->transmit_cb(resp, l, li->cbdata);
|
||||||
if (teip->state != LAPD_TEI_ACTIVE) {
|
if (teip->state != LAPD_TEI_ACTIVE) {
|
||||||
if (teip->state == LAPD_TEI_ASSIGNED) {
|
if (teip->state == LAPD_TEI_ASSIGNED) {
|
||||||
lapd_tei_set_state(teip,
|
lapd_tei_set_state(teip,
|
||||||
|
@ -341,11 +360,11 @@ uint8_t *lapd_receive(uint8_t * data, int len, int *ilen, lapd_mph_type * prim,
|
||||||
DEBUGP(DMI, "rr in strange state, send rej\n");
|
DEBUGP(DMI, "rr in strange state, send rej\n");
|
||||||
|
|
||||||
// rej
|
// rej
|
||||||
resp[l++] = (teip-> sapi << 2) | (network_side ? 0 : 2);
|
resp[l++] = (teip-> sapi << 2) | (li->network_side ? 0 : 2);
|
||||||
resp[l++] = (tei << 1) | 1;
|
resp[l++] = (tei << 1) | 1;
|
||||||
resp[l++] = 0x09; //rej
|
resp[l++] = 0x09; //rej
|
||||||
resp[l++] = ((teip->vr + 1) << 1) | 0;
|
resp[l++] = ((teip->vr + 1) << 1) | 0;
|
||||||
lapd_transmit_cb(resp, l, cbdata);
|
li->transmit_cb(resp, l, li->cbdata);
|
||||||
pf = 0; // dont reply
|
pf = 0; // dont reply
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -366,13 +385,12 @@ uint8_t *lapd_receive(uint8_t * data, int len, int *ilen, lapd_mph_type * prim,
|
||||||
DEBUGP(DMI, "rr in strange " "state, send rej\n");
|
DEBUGP(DMI, "rr in strange " "state, send rej\n");
|
||||||
|
|
||||||
// rej
|
// rej
|
||||||
resp[l++] = (teip-> sapi << 2) | (network_side ? 0 : 2);
|
resp[l++] = (teip-> sapi << 2) | (li->network_side ? 0 : 2);
|
||||||
resp[l++] = (tei << 1) | 1;
|
resp[l++] = (tei << 1) | 1;
|
||||||
resp[l++] = 0x09; //rej
|
resp[l++] = 0x09; //rej
|
||||||
resp[l++] =
|
resp[l++] =
|
||||||
((teip->vr + 1) << 1) | 0;
|
((teip->vr + 1) << 1) | 0;
|
||||||
lapd_transmit_cb(resp, l,
|
li->transmit_cb(resp, l, li->cbdata);
|
||||||
cbdata);
|
|
||||||
pf = 0; // dont reply
|
pf = 0; // dont reply
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
@ -385,7 +403,7 @@ uint8_t *lapd_receive(uint8_t * data, int len, int *ilen, lapd_mph_type * prim,
|
||||||
resp[l++] = 0x01; // rr
|
resp[l++] = 0x01; // rr
|
||||||
resp[l++] = (LAPD_NR(teip) << 1) | (data[3] & 1); // pf bit from req
|
resp[l++] = (LAPD_NR(teip) << 1) | (data[3] & 1); // pf bit from req
|
||||||
|
|
||||||
lapd_transmit_cb(resp, l, cbdata);
|
li->transmit_cb(resp, l, li->cbdata);
|
||||||
|
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
|
@ -403,7 +421,7 @@ uint8_t *lapd_receive(uint8_t * data, int len, int *ilen, lapd_mph_type * prim,
|
||||||
resp[l++] = data[0];
|
resp[l++] = data[0];
|
||||||
resp[l++] = (tei << 1) | 1;
|
resp[l++] = (tei << 1) | 1;
|
||||||
resp[l++] = 0x73;
|
resp[l++] = 0x73;
|
||||||
lapd_transmit_cb(resp, l, cbdata);
|
li->transmit_cb(resp, l, li->cbdata);
|
||||||
lapd_tei_set_state(teip, LAPD_TEI_NONE);
|
lapd_tei_set_state(teip, LAPD_TEI_NONE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -425,7 +443,7 @@ uint8_t *lapd_receive(uint8_t * data, int len, int *ilen, lapd_mph_type * prim,
|
||||||
resp[l++] = 0x01; // rr
|
resp[l++] = 0x01; // rr
|
||||||
resp[l++] = (LAPD_NR(teip) << 1) | (data[3] & 1); // pf bit from req
|
resp[l++] = (LAPD_NR(teip) << 1) | (data[3] & 1); // pf bit from req
|
||||||
|
|
||||||
lapd_transmit_cb(resp, l, cbdata);
|
li->transmit_cb(resp, l, li->cbdata);
|
||||||
|
|
||||||
if (cmd != 0) {
|
if (cmd != 0) {
|
||||||
*prim = LAPD_DL_DATA_IND;
|
*prim = LAPD_DL_DATA_IND;
|
||||||
|
@ -439,12 +457,18 @@ uint8_t *lapd_receive(uint8_t * data, int len, int *ilen, lapd_mph_type * prim,
|
||||||
return NULL;
|
return NULL;
|
||||||
};
|
};
|
||||||
|
|
||||||
void lapd_transmit(int tei, uint8_t * data, int len, void *cbdata)
|
void lapd_transmit(struct lapd_instance *li, uint8_t tei,
|
||||||
|
uint8_t *data, unsigned int len)
|
||||||
{
|
{
|
||||||
//printf("lapd_transmit %d, %d\n", tei, len);
|
//printf("lapd_transmit %d, %d\n", tei, len);
|
||||||
//hexdump(data, len);
|
//hexdump(data, len);
|
||||||
lapd_tei_t *teip = teip_from_tei(tei);
|
struct lapd_tei *teip = teip_from_tei(li, tei);
|
||||||
//printf("teip %p\n", teip);
|
|
||||||
|
if (!teip) {
|
||||||
|
LOGP(DMI, LOGL_ERROR, "Cannot transmit on non-existing "
|
||||||
|
"TEI %u\n", tei);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* prepend stuff */
|
/* prepend stuff */
|
||||||
uint8_t buf[10000];
|
uint8_t buf[10000];
|
||||||
|
@ -452,12 +476,29 @@ void lapd_transmit(int tei, uint8_t * data, int len, void *cbdata)
|
||||||
memmove(buf + 4, data, len);
|
memmove(buf + 4, data, len);
|
||||||
len += 4;
|
len += 4;
|
||||||
|
|
||||||
buf[0] = (teip->sapi << 2) | (network_side ? 2 : 0);
|
buf[0] = (teip->sapi << 2) | (li->network_side ? 2 : 0);
|
||||||
buf[1] = (teip->tei << 1) | 1;
|
buf[1] = (teip->tei << 1) | 1;
|
||||||
buf[2] = (LAPD_NS(teip) << 1);
|
buf[2] = (LAPD_NS(teip) << 1);
|
||||||
buf[3] = (LAPD_NR(teip) << 1) | 0;
|
buf[3] = (LAPD_NR(teip) << 1) | 0;
|
||||||
|
|
||||||
teip->vs = (teip->vs + 1) & 0x7f;
|
teip->vs = (teip->vs + 1) & 0x7f;
|
||||||
|
|
||||||
lapd_transmit_cb(buf, len, cbdata);
|
li->transmit_cb(buf, len, li->cbdata);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct lapd_instance *lapd_instance_alloc(void (*tx_cb)(uint8_t *data, int len,
|
||||||
|
void *cbdata), void *cbdata)
|
||||||
|
{
|
||||||
|
struct lapd_instance *li;
|
||||||
|
|
||||||
|
li = talloc_zero(NULL, struct lapd_instance);
|
||||||
|
if (!li)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
li->transmit_cb = tx_cb;
|
||||||
|
li->cbdata = cbdata;
|
||||||
|
li->network_side = 1;
|
||||||
|
INIT_LLIST_HEAD(&li->tei_list);
|
||||||
|
|
||||||
|
return li;
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <osmocore/linuxlist.h>
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
LAPD_MPH_NONE = 0,
|
LAPD_MPH_NONE = 0,
|
||||||
|
|
||||||
|
@ -14,10 +16,22 @@ typedef enum {
|
||||||
|
|
||||||
} lapd_mph_type;
|
} lapd_mph_type;
|
||||||
|
|
||||||
extern uint8_t *lapd_receive(uint8_t *data, int len, int *ilen, lapd_mph_type *prim, void *cbdata);
|
struct lapd_instance {
|
||||||
|
struct llist_head list; /* list of LAPD instances */
|
||||||
|
int network_side;
|
||||||
|
|
||||||
extern void (*lapd_transmit_cb)(uint8_t *data, int len, void *cbdata);
|
void (*transmit_cb)(uint8_t *data, int len, void *cbdata);
|
||||||
|
void *cbdata;
|
||||||
|
|
||||||
extern void lapd_transmit(int tei, uint8_t *data, int len, void *cbdata);
|
struct llist_head tei_list; /* list of TEI in this LAPD instance */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern uint8_t *lapd_receive(struct lapd_instance *li, uint8_t *data, unsigned int len,
|
||||||
|
int *ilen, lapd_mph_type *prim);
|
||||||
|
|
||||||
|
extern void lapd_transmit(struct lapd_instance *li, uint8_t tei, uint8_t *data, unsigned int len);
|
||||||
|
|
||||||
|
struct lapd_instance *lapd_instance_alloc(void (*tx_cb)(uint8_t *data, int len,
|
||||||
|
void *cbdata), void *cbdata);
|
||||||
|
|
||||||
#endif /* OPENBSC_LAPD_H */
|
#endif /* OPENBSC_LAPD_H */
|
||||||
|
|
Loading…
Reference in New Issue