Moved layer 1 <-> layer 2 interface from main.c to a seperate file of

liblayer23. Other applications using liblayer23 don't need to re-implement it.

Messages from layer 1 are not freed in layer2_read() anymore. They will be
freed by the upper layers. The layers may also decide to queue or to forward
the messages. In general: A message is always discarded by the message handler
and not after calling the message handler.
This commit is contained in:
Andreas.Eversberg 2010-05-22 10:46:20 +00:00
parent 6ca03ff7e6
commit 9359a91504
9 changed files with 219 additions and 118 deletions

View File

@ -28,7 +28,4 @@ int l1ctl_tx_echo_req(struct osmocom_ms *ms, unsigned int len);
int l1ctl_tx_pm_req_range(struct osmocom_ms *ms, uint16_t arfcn_from,
uint16_t arfcm_to);
extern int osmo_send_l1(struct osmocom_ms *ms, struct msgb *msg);
#endif

View File

@ -0,0 +1,8 @@
#ifndef _L1L2_INTERFACE_H
#define _L1L2_INTERFACE_H
int layer2_open(struct osmocom_ms *ms, const char *socket_path);
int layer2_close(struct osmocom_ms *ms);
int osmo_send_l1(struct osmocom_ms *ms, struct msgb *msg);
#endif /* _L1L2_INTERFACE_H */

View File

@ -3,7 +3,7 @@ AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS)
#AM_LDFLAGS = $(LIBOSMOCORE_LIBS)
noinst_LIBRARIES = liblayer23.a libvty.a
liblayer23_a_SOURCES = l1ctl.c gsmtap_util.c lapdm.c rslms.c \
liblayer23_a_SOURCES = l1l2_interface.c l1ctl.c gsmtap_util.c lapdm.c rslms.c \
layer3.c logging.c bcch_scan.c \
gsm48_cc.c transaction.c gsm48_mm.c gsm48_rr.c \
gsm322.c support.c subscriber.c sysinfo.c networks.c \

View File

@ -53,8 +53,9 @@
#include <osmocore/gsm48.h>
#include <osmocore/bitvec.h>
#include <osmocom/logging.h>
#include <osmocom/osmocom_data.h>
#include <osmocom/l1l2_interface.h>
#include <osmocom/logging.h>
static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg);
static int gsm48_rr_dl_est(struct osmocom_ms *ms);
@ -273,8 +274,6 @@ static int gsm48_rx_rll(struct msgb *msg, struct osmocom_ms *ms)
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
#warning HACK!!!!!!
return gsm48_rcv_rsl(ms, msg);
msgb_enqueue(&rr->rsl_upqueue, msg);
return 0;
@ -294,6 +293,7 @@ static int gsm48_rx_rsl(struct msgb *msg, struct osmocom_ms *ms)
/* FIXME: implement this */
LOGP(DRSL, LOGL_NOTICE, "unknown RSLms msg_discr 0x%02x\n",
rslh->msg_discr);
msgb_free(msg);
rc = -EINVAL;
break;
}
@ -3237,8 +3237,6 @@ static int gsm48_rcv_rsl(struct osmocom_ms *ms, struct msgb *msg)
/* free msgb unless it is forwarded */
if (dldatastatelist[i].rout != gsm48_rr_data_ind)
#warning HACK!!!!!!
return rc;
msgb_free(msg);
return rc;

View File

@ -42,6 +42,7 @@
#include <osmocom/l1ctl.h>
#include <osmocom/osmocom_data.h>
#include <osmocom/l1l2_interface.h>
#include <osmocom/lapdm.h>
#include <osmocom/logging.h>
#include <osmocom/gsmtap_util.h>
@ -142,6 +143,7 @@ static int rx_ph_data_ind(struct osmocom_ms *ms, struct msgb *msg)
if (msgb_l3len(msg) < sizeof(*ccch)) {
LOGP(DL1C, LOGL_ERROR, "MSG too short Data Ind: %u\n",
msgb_l3len(msg));
msgb_free(msg);
return -1;
}
@ -334,6 +336,8 @@ static int rx_l1_reset(struct osmocom_ms *ms)
{
printf("Layer1 Reset.\n");
dispatch_signal(SS_L1CTL, S_L1CTL_RESET, ms);
return 0;
}
/* Receive L1CTL_PM_RESP */
@ -364,6 +368,7 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
if (msgb_l2len(msg) < sizeof(*dl)) {
LOGP(DL1C, LOGL_ERROR, "Short Layer2 message: %u\n",
msgb_l2len(msg));
msgb_free(msg);
return -1;
}
@ -376,20 +381,24 @@ int l1ctl_recv(struct osmocom_ms *ms, struct msgb *msg)
switch (l1h->msg_type) {
case L1CTL_FBSB_RESP:
rc = rx_l1_fbsb_resp(ms, msg);
msgb_free(msg);
break;
case L1CTL_DATA_IND:
rc = rx_ph_data_ind(ms, msg);
break;
case L1CTL_RESET:
rc = rx_l1_reset(ms);
msgb_free(msg);
break;
case L1CTL_PM_RESP:
rc = rx_l1_pm_resp(ms, msg);
msgb_free(msg);
if (l1h->flags & L1CTL_F_DONE)
dispatch_signal(SS_L1CTL, S_L1CTL_PM_DONE, ms);
break;
default:
fprintf(stderr, "Unknown MSG: %u\n", l1h->msg_type);
msgb_free(msg);
break;
}

View File

@ -0,0 +1,161 @@
/* Layer 1 socket interface of layer2/3 stack */
/* (C) 2010 by Holger Hans Peter Freyther
* (C) 2010 by Harald Welte <laforge@gnumonks.org>
*
* 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 <osmocom/osmocom_data.h>
#include <osmocom/l1ctl.h>
#include <osmocom/logging.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <arpa/inet.h>
#define _GNU_SOURCE
#include <unistd.h>
#include <errno.h>
#include <string.h>
#define GSM_L2_LENGTH 256
static int layer2_read(struct bsc_fd *fd)
{
struct msgb *msg;
u_int16_t len;
int rc;
msg = msgb_alloc(GSM_L2_LENGTH, "Layer2");
if (!msg) {
LOGP(DL1C, LOGL_ERROR, "Failed to allocate msg.\n");
return -ENOMEM;
}
rc = read(fd->fd, &len, sizeof(len));
if (rc < sizeof(len)) {
msgb_free(msg);
return rc;
}
len = ntohs(len);
if (len > GSM_L2_LENGTH) {
LOGP(DL1C, LOGL_ERROR, "Length is too big: %u\n", len);
msgb_free(msg);
return -EINVAL;
}
msg->l1h = msgb_put(msg, len);
rc = read(fd->fd, msg->l1h, msgb_l1len(msg));
if (rc != msgb_l1len(msg)) {
LOGP(DL1C, LOGL_ERROR, "Can not read data: len=%d rc=%d "
"errno=%d\n", len, rc, errno);
msgb_free(msg);
return rc;
}
l1ctl_recv((struct osmocom_ms *) fd->data, msg);
return 0;
}
static int layer2_write(struct bsc_fd *fd, struct msgb *msg)
{
int rc;
rc = write(fd->fd, msg->data, msg->len);
if (rc != msg->len) {
LOGP(DL1C, LOGL_ERROR, "Failed to write data: rc: %d\n", rc);
return rc;
}
return 0;
}
int layer2_open(struct osmocom_ms *ms, const char *socket_path)
{
int rc;
struct sockaddr_un local;
ms->wq.bfd.fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (ms->wq.bfd.fd < 0) {
fprintf(stderr, "Failed to create unix domain socket.\n");
return ms->wq.bfd.fd;
}
local.sun_family = AF_UNIX;
strncpy(local.sun_path, socket_path, sizeof(local.sun_path));
local.sun_path[sizeof(local.sun_path) - 1] = '\0';
rc = connect(ms->wq.bfd.fd, (struct sockaddr *) &local,
sizeof(local.sun_family) + strlen(local.sun_path));
if (rc < 0) {
fprintf(stderr, "Failed to connect to '%s'.\n", local.sun_path);
close(ms->wq.bfd.fd);
return rc;
}
write_queue_init(&ms->wq, 100);
ms->wq.bfd.data = ms;
ms->wq.bfd.when = BSC_FD_READ;
ms->wq.read_cb = layer2_read;
ms->wq.write_cb = layer2_write;
rc = bsc_register_fd(&ms->wq.bfd);
if (rc != 0) {
fprintf(stderr, "Failed to register fd.\n");
return rc;
}
return 0;
}
int layer2_close(struct osmocom_ms *ms)
{
close(ms->wq.bfd.fd);
bsc_unregister_fd(&ms->wq.bfd);
return 0;
}
int osmo_send_l1(struct osmocom_ms *ms, struct msgb *msg)
{
uint16_t *len;
DEBUGP(DL1C, "Sending: '%s'\n", hexdump(msg->data, msg->len));
if (msg->l1h != msg->data)
LOGP(DL1C, LOGL_ERROR, "Message L1 header != Message Data\n");
/* prepend 16bit length before sending */
len = (uint16_t *) msgb_push(msg, sizeof(*len));
*len = htons(msg->len - sizeof(*len));
if (write_queue_enqueue(&ms->wq, msg) != 0) {
LOGP(DL1C, LOGL_ERROR, "Failed to enqueue msg.\n");
msgb_free(msg);
return -1;
}
return 0;
}

View File

@ -305,8 +305,10 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
DEBUGPC(DLAPDM, "SABM ");
/* Must be Format B */
rc = check_length_ind(msg->l2h[2]);
if (rc < 0)
if (rc < 0) {
msgb_free(msg);
return rc;
}
length = msg->l2h[2] >> 2;
/* FIXME: G.4.5 check */
if (dl->state == LAPDm_STATE_MF_EST) {
@ -316,6 +318,7 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
/* FIXME: check for contention resoultion */
DEBUGP(DLAPDM, "SABM command, multiple "
"frame established state\n");
msgb_free(msg);
return 0;
}
}
@ -337,23 +340,27 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
DEBUGPC(DLAPDM, "DM ");
if (!LAPDm_CTRL_PF_BIT(mctx->ctrl)) {
/* 5.4.1.2 DM responses with the F bit set to "0" shall be ignored. */
msgb_free(msg);
return 0;
}
switch (dl->state) {
case LAPDm_STATE_IDLE:
/* 5.4.5 all other frame types shall be discarded */
DEBUGPC(DLAPDM, "state=IDLE (discarding) ");
msgb_free(msg);
return 0;
case LAPDm_STATE_MF_EST:
if (LAPDm_CTRL_PF_BIT(mctx->ctrl) == 1)
DEBUGPC(DLAPDM, "unsolicited DM resposne ");
else
DEBUGPC(DLAPDM, "unsolicited DM resposne, multiple frame established state ");
msgb_free(msg);
return 0;
case LAPDm_STATE_TIMER_RECOV:
/* DM is normal in case PF = 1 */
if (LAPDm_CTRL_PF_BIT(mctx->ctrl) == 0) {
DEBUGPC(DLAPDM, "unsolicited DM resposne, multiple frame established state ");
msgb_free(msg);
return 0;
}
break;
@ -369,8 +376,10 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
msg->l3h = msg->l2h + 2;
} else {
rc = check_length_ind(msg->l2h[2]);
if (rc < 0)
if (rc < 0) {
msgb_free(msg);
return rc;
}
length = msg->l2h[2] >> 2;
msg->l3h = msg->l2h + 3;
}
@ -378,6 +387,7 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
if (length == 0) {
/* 5.3.3 UI frames received with the length indicator set to "0" shall be ignored */
DEBUGP(DLAPDM, "length=0 (discarding) ");
msgb_free(msg);
return 0;
}
/* FIXME: G.4.5 check */
@ -388,6 +398,7 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
default:
/* 5.3.3 UI frames with invalid SAPI values shall be discarded */
DEBUGP(DLAPDM, "sapi=%u (discarding) ", LAPDm_ADDR_SAPI(mctx->ctrl));
msgb_free(msg);
return 0;
}
msgb_pull_l2h(msg);
@ -403,8 +414,10 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
* parameters" is sent to the mobile management entity. */
LOGP(DLAPDM, LOGL_ERROR,
"U frame iwth incorrect parameters ");
msgb_free(msg);
return -EIO;
}
msgb_free(msg);
switch (dl->state) {
case LAPDm_STATE_IDLE:
/* FIXME: send DM with F=P */
@ -420,6 +433,7 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
if (!LAPDm_CTRL_PF_BIT(mctx->ctrl)) {
/* 5.4.1.2 A UA response with the F bit set to "0" shall be ignored. */
DEBUGP(DLAPDM, "F=0 (discarding) ");
msgb_free(msg);
return 0;
}
switch (dl->state) {
@ -430,6 +444,7 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
default:
DEBUGP(DLAPDM,
"unsolicited UA response! (discarding) ");
msgb_free(msg);
return 0;
}
/* reset Timer T200 */
@ -441,6 +456,8 @@ static int lapdm_rx_u(struct msgb *msg, struct lapdm_msg_ctx *mctx)
/* send notification to L3 */
rc = send_rslms_rll_simple(RSL_MT_EST_CONF, mctx);
break;
default:
msgb_free(msg);
}
return rc;
}
@ -457,6 +474,7 @@ static int lapdm_rx_s(struct msgb *msg, struct lapdm_msg_ctx *mctx)
* with the M bit set to "1", an MDL-ERROR-INDICATION
* primitive with cause "S frame with incorrect
* parameters" is sent to the mobile management entity. */
msgb_free(msg);
return -EIO;
}
switch (dl->state) {
@ -476,6 +494,7 @@ static int lapdm_rx_s(struct msgb *msg, struct lapdm_msg_ctx *mctx)
/* FIXME */
break;
}
msgb_free(msg);
return 0;
}
@ -495,6 +514,7 @@ static int lapdm_rx_i(struct msgb *msg, struct lapdm_msg_ctx *mctx)
* to a numerical value L>N201 or L=0, an MDL-ERROR-INDICATION
* primitive with cause "I frame with incorrect length"
* is sent to the mobile management entity. */
msgb_free(msg);
return -EIO;
}
/* FIXME: G.4.2 If the numerical value of L is L<N201 and the M
@ -522,8 +542,10 @@ static int lapdm_rx_i(struct msgb *msg, struct lapdm_msg_ctx *mctx)
"V_recv=%u ", ns, dl->V_recv);
/* FIXME: 5.7.1: N(s) sequence error */
/* discard data */
msgb_free(msg);
return -EIO;
}
msgb_free(msg);
/* Check for P bit */
if (LAPDm_CTRL_PF_BIT(mctx->ctrl)) {
@ -578,6 +600,7 @@ static int lapdm_ph_data_ind(struct msgb *msg, struct lapdm_msg_ctx *mctx)
rc = lapdm_rx_i(msg, mctx);
else {
LOGP(DLAPDM, LOGL_ERROR, "unknown LAPDm format ");
msgb_free(msg);
rc = -EINVAL;
}
return rc;
@ -626,6 +649,7 @@ int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le, struct l1ctl_info_
if (!(mctx.addr & 0x01)) {
LOGP(DLAPDM, LOGL_ERROR, "we don't support "
"multibyte addresses (discarding)\n");
msgb_free(msg);
return -EINVAL;
}
mctx.ctrl = msg->l2h[1];
@ -635,6 +659,7 @@ int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le, struct l1ctl_info_
break;
case LAPDm_FMT_Bter:
/* FIXME */
msgb_free(msg);
break;
case LAPDm_FMT_Bbis:
/* directly pass up to layer3 */
@ -643,6 +668,8 @@ int l2_ph_data_ind(struct msgb *msg, struct lapdm_entity *le, struct l1ctl_info_
msgb_pull_l2h(msg);
rc = send_rslms_rll_l3(RSL_MT_UNIT_DATA_IND, &mctx, msg);
break;
default:
msgb_free(msg);
}
return rc;
@ -847,8 +874,10 @@ int rslms_recvmsg(struct msgb *msg, struct osmocom_ms *ms)
/* input function that L2 calls when sending messages up to L3 */
int rslms_sendmsg(struct msgb *msg, struct osmocom_ms *ms)
{
if (!ms->l2_entity.msg_handler)
if (!ms->l2_entity.msg_handler) {
msgb_free(msg);
return -EIO;
}
/* call the layer2 message handler that is registered */
return ms->l2_entity.msg_handler(msg, ms);

View File

@ -23,6 +23,7 @@
#include <osmocom/osmocom_data.h>
#include <osmocom/l1ctl.h>
#include <osmocom/l1l2_interface.h>
#include <osmocom/layer3.h>
#include <osmocom/lapdm.h>
#include <osmocom/gsmtap_util.h>
@ -36,9 +37,6 @@
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/un.h>
#define _GNU_SOURCE
#include <getopt.h>
#include <stdlib.h>
@ -49,8 +47,6 @@
struct log_target *stderr_target;
#define GSM_L2_LENGTH 256
void *l23_ctx = NULL;
static char *socket_path = "/tmp/osmocom_l2";
struct llist_head ms_list;
@ -59,82 +55,6 @@ static uint32_t gsmtap_ip = 0;
int (*l23_app_work) (struct osmocom_ms *ms) = NULL;
int (*l23_app_exit) (struct osmocom_ms *ms) = NULL;
static int layer2_read(struct bsc_fd *fd)
{
struct msgb *msg;
u_int16_t len;
int rc;
msg = msgb_alloc(GSM_L2_LENGTH, "Layer2");
if (!msg) {
LOGP(DL1C, LOGL_ERROR, "Failed to allocate msg.\n");
return -1;
}
rc = read(fd->fd, &len, sizeof(len));
if (rc < sizeof(len)) {
LOGP(DL1C, LOGL_ERROR, "Short read. Error.\n");
exit(2);
}
len = ntohs(len);
if (len > GSM_L2_LENGTH) {
LOGP(DL1C, LOGL_ERROR, "Length is too big: %u\n", len);
msgb_free(msg);
return -1;
}
msg->l1h = msgb_put(msg, len);
rc = read(fd->fd, msg->l1h, msgb_l1len(msg));
if (rc != msgb_l1len(msg)) {
LOGP(DL1C, LOGL_ERROR, "Can not read data: len=%d rc=%d "
"errno=%d\n", len, rc, errno);
msgb_free(msg);
return -1;
}
l1ctl_recv((struct osmocom_ms *) fd->data, msg);
msgb_free(msg);
return 0;
}
static int layer2_write(struct bsc_fd *fd, struct msgb *msg)
{
int rc;
rc = write(fd->fd, msg->data, msg->len);
if (rc != msg->len) {
LOGP(DL1C, LOGL_ERROR, "Failed to write data: rc: %d\n", rc);
return -1;
}
return 0;
}
int osmo_send_l1(struct osmocom_ms *ms, struct msgb *msg)
{
uint16_t *len;
DEBUGP(DL1C, "Sending: '%s'\n", hexdump(msg->data, msg->len));
if (msg->l1h != msg->data)
LOGP(DL1C, LOGL_ERROR, "Message L1 header != Message Data\n");
/* prepend 16bit length before sending */
len = (uint16_t *) msgb_push(msg, sizeof(*len));
*len = htons(msg->len - sizeof(*len));
if (write_queue_enqueue(&ms->wq, msg) != 0) {
LOGP(DL1C, LOGL_ERROR, "Failed to enqueue msg.\n");
msgb_free(msg);
return -1;
}
return 0;
}
static void print_usage(const char *app)
{
printf("Usage: %s\n", app);
@ -214,7 +134,6 @@ void sighandler(int sigset)
int main(int argc, char **argv)
{
int rc;
struct sockaddr_un local;
INIT_LLIST_HEAD(&ms_list);
log_init(&log_info);
@ -237,29 +156,12 @@ int main(int argc, char **argv)
handle_options(argc, argv);
ms->wq.bfd.fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (ms->wq.bfd.fd < 0) {
fprintf(stderr, "Failed to create unix domain socket.\n");
exit(1);
}
local.sun_family = AF_UNIX;
strncpy(local.sun_path, socket_path, sizeof(local.sun_path));
local.sun_path[sizeof(local.sun_path) - 1] = '\0';
rc = connect(ms->wq.bfd.fd, (struct sockaddr *) &local,
sizeof(local.sun_family) + strlen(local.sun_path));
rc = layer2_open(ms, socket_path);
if (rc < 0) {
fprintf(stderr, "Failed to connect to '%s'.\n", local.sun_path);
fprintf(stderr, "Failed during layer2_open()\n");
exit(1);
}
write_queue_init(&ms->wq, 100);
ms->wq.bfd.data = ms;
ms->wq.bfd.when = BSC_FD_READ;
ms->wq.read_cb = layer2_read;
ms->wq.write_cb = layer2_write;
lapdm_init(&ms->l2_entity.lapdm_dcch, ms);
lapdm_init(&ms->l2_entity.lapdm_acch, ms);
@ -267,11 +169,6 @@ int main(int argc, char **argv)
if (rc < 0)
exit(1);
if (bsc_register_fd(&ms->wq.bfd) != 0) {
fprintf(stderr, "Failed to register fd.\n");
exit(1);
}
if (gsmtap_ip) {
rc = gsmtap_init(gsmtap_ip);
if (rc < 0) {

View File

@ -122,6 +122,7 @@ static int rslms_rx_rll(struct msgb *msg, struct osmocom_ms *ms)
rc = -EINVAL;
break;
}
msgb_free(msg);
return rc;
}
@ -139,6 +140,7 @@ static int layer3_from_layer2(struct msgb *msg, struct osmocom_ms *ms)
/* FIXME: implement this */
LOGP(DRSL, LOGL_NOTICE, "unknown RSLms msg_discr 0x%02x\n",
rslh->msg_discr);
msgb_free(msg);
rc = -EINVAL;
break;
}