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.
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
--- /dev/null
+#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 */
#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 \
#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);
{
struct gsm48_rrlayer *rr = &ms->rrlayer;
-#warning HACK!!!!!!
-return gsm48_rcv_rsl(ms, msg);
msgb_enqueue(&rr->rsl_upqueue, msg);
return 0;
/* FIXME: implement this */
LOGP(DRSL, LOGL_NOTICE, "unknown RSLms msg_discr 0x%02x\n",
rslh->msg_discr);
+ msgb_free(msg);
rc = -EINVAL;
break;
}
/* free msgb unless it is forwarded */
if (dldatastatelist[i].rout != gsm48_rr_data_ind)
-#warning HACK!!!!!!
-return rc;
msgb_free(msg);
return rc;
#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>
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;
}
{
printf("Layer1 Reset.\n");
dispatch_signal(SS_L1CTL, S_L1CTL_RESET, ms);
+
+ return 0;
}
/* Receive L1CTL_PM_RESP */
if (msgb_l2len(msg) < sizeof(*dl)) {
LOGP(DL1C, LOGL_ERROR, "Short Layer2 message: %u\n",
msgb_l2len(msg));
+ msgb_free(msg);
return -1;
}
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;
}
--- /dev/null
+/* 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;
+}
+
+
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) {
/* FIXME: check for contention resoultion */
DEBUGP(DLAPDM, "SABM command, multiple "
"frame established state\n");
+ msgb_free(msg);
return 0;
}
}
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;
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;
}
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 */
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);
* 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 */
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) {
default:
DEBUGP(DLAPDM,
"unsolicited UA response! (discarding) ");
+ msgb_free(msg);
return 0;
}
/* reset Timer T200 */
/* send notification to L3 */
rc = send_rslms_rll_simple(RSL_MT_EST_CONF, mctx);
break;
+ default:
+ msgb_free(msg);
}
return rc;
}
* 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) {
/* FIXME */
break;
}
+ msgb_free(msg);
return 0;
}
* 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
"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)) {
rc = lapdm_rx_i(msg, mctx);
else {
LOGP(DLAPDM, LOGL_ERROR, "unknown LAPDm format ");
+ msgb_free(msg);
rc = -EINVAL;
}
return rc;
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];
break;
case LAPDm_FMT_Bter:
/* FIXME */
+ msgb_free(msg);
break;
case LAPDm_FMT_Bbis:
/* directly pass up to layer3 */
msgb_pull_l2h(msg);
rc = send_rslms_rll_l3(RSL_MT_UNIT_DATA_IND, &mctx, msg);
break;
+ default:
+ msgb_free(msg);
}
return rc;
/* 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);
#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>
#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
#define _GNU_SOURCE
#include <getopt.h>
#include <stdlib.h>
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;
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);
int main(int argc, char **argv)
{
int rc;
- struct sockaddr_un local;
INIT_LLIST_HEAD(&ms_list);
log_init(&log_info);
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);
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) {
rc = -EINVAL;
break;
}
+ msgb_free(msg);
return rc;
}
/* FIXME: implement this */
LOGP(DRSL, LOGL_NOTICE, "unknown RSLms msg_discr 0x%02x\n",
rslh->msg_discr);
+ msgb_free(msg);
rc = -EINVAL;
break;
}