/* Sysmocom femtobts L1 proxy */ /* (C) 2011 by Harald Welte * * All Rights Reserved * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation; either version 3 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 Affero General Public License * along with this program. If not, see . * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "femtobts.h" #include "l1_if.h" #include "l1_transp.h" #include "l1_fwd.h" static const uint16_t fwd_udp_ports[_NUM_MQ_READ] = { [MQ_SYS_READ] = L1FWD_SYS_PORT, [MQ_L1_READ] = L1FWD_L1_PORT, [MQ_DBG_READ] = L1FWD_DBG_PORT, }; static const struct value_string l1t_mq_names[] = { { MQ_SYS_READ, "SYS" }, { MQ_L1_READ, "L1" }, { MQ_DBG_READ, "DBG" }, { 0, NULL } }; struct l1fwd_hdl { struct sockaddr_storage remote_sa; socklen_t remote_sa_len; struct osmo_wqueue udp_wq[_NUM_MQ_READ]; struct femtol1_hdl *fl1h; }; /* callback when there's a new L1 primitive coming in from the HW */ int l1if_handle_l1prim(struct femtol1_hdl *fl1h, struct msgb *msg) { struct l1fwd_hdl *l1fh = fl1h->priv; /* Enqueue message to UDP socket */ return osmo_wqueue_enqueue(&l1fh->udp_wq[MQ_L1_READ], msg); } /* callback when there's a new SYS primitive coming in from the HW */ int l1if_handle_sysprim(struct femtol1_hdl *fl1h, struct msgb *msg) { struct l1fwd_hdl *l1fh = fl1h->priv; /* Enqueue message to UDP socket */ return osmo_wqueue_enqueue(&l1fh->udp_wq[MQ_SYS_READ], msg); } /* callback when there's a new DBG primitive coming in from the HW */ int l1if_handle_dbg(struct femtol1_hdl *fl1h, struct msgb *msg) { struct l1fwd_hdl *l1fh = fl1h->priv; /* Enqueue message to UDP socket */ return osmo_wqueue_enqueue(&l1fh->udp_wq[MQ_DBG_READ], msg); } /* data has arrived on the udp socket */ static int udp_read_cb(struct osmo_fd *ofd) { struct msgb *msg = msgb_alloc_headroom(2048, 128, "udp_rx"); struct l1fwd_hdl *l1fh = ofd->data; struct femtol1_hdl *fl1h = l1fh->fl1h; int rc; if (!msg) return -ENOMEM; msg->l1h = msg->data; l1fh->remote_sa_len = sizeof(l1fh->remote_sa); rc = recvfrom(ofd->fd, msg->l1h, msgb_tailroom(msg), 0, (struct sockaddr *) &l1fh->remote_sa, &l1fh->remote_sa_len); if (rc < 0) { perror("read from udp"); msgb_free(msg); return rc; } else if (rc == 0) { perror("len=0 read from udp"); msgb_free(msg); return rc; } msgb_put(msg, rc); DEBUGP(DL1C, "UDP: Received %u bytes for %s queue\n", rc, get_value_string(l1t_mq_names, ofd->priv_nr)); /* put the message into the right queue */ if (ofd->priv_nr == MQ_SYS_WRITE) rc = osmo_wqueue_enqueue(&fl1h->write_q[MQ_SYS_WRITE], msg); else rc = osmo_wqueue_enqueue(&fl1h->write_q[MQ_L1_WRITE], msg); return rc; } /* callback when we can write to the UDP socket */ static int udp_write_cb(struct osmo_fd *ofd, struct msgb *msg) { int rc; struct l1fwd_hdl *l1fh = ofd->data; DEBUGP(DL1C, "UDP: Writing %u bytes for %s queue\n", msgb_l1len(msg), get_value_string(l1t_mq_names, ofd->priv_nr)); rc = sendto(ofd->fd, msg->l1h, msgb_l1len(msg), 0, (const struct sockaddr *)&l1fh->remote_sa, l1fh->remote_sa_len); if (rc < 0) { LOGP(DL1C, LOGL_ERROR, "error writing to L1 msg_queue: %s\n", strerror(errno)); return rc; } else if (rc < msgb_l1len(msg)) { LOGP(DL1C, LOGL_ERROR, "short write to L1 msg_queue: " "%u < %u\n", rc, msgb_l1len(msg)); return -EIO; } return 0; } int main(int argc, char **argv) { struct l1fwd_hdl *l1fh; struct femtol1_hdl *fl1h; int rc, i; printf("sizeof(GsmL1_Prim_t) = %lu\n", sizeof(GsmL1_Prim_t)); printf("sizeof(FemtoBts_Prim_t) = %lu\n", sizeof(FemtoBts_Prim_t)); bts_log_init(NULL); /* allocate new femtol1_handle */ fl1h = talloc_zero(NULL, struct femtol1_hdl); INIT_LLIST_HEAD(&fl1h->wlc_list); /* open the actual hardware transport */ rc = l1if_transport_open(fl1h); if (rc < 0) exit(1); /* create our fwd handle */ l1fh = talloc_zero(NULL, struct l1fwd_hdl); l1fh->fl1h = fl1h; fl1h->priv = l1fh; /* Open UDP */ for (i = 0; i < 3; i++) { struct osmo_wqueue *wq = &l1fh->udp_wq[i]; osmo_wqueue_init(wq, 10); wq->write_cb = udp_write_cb; wq->read_cb = udp_read_cb; wq->bfd.when |= BSC_FD_READ; wq->bfd.data = l1fh; wq->bfd.priv_nr = i; rc = osmo_sock_init_ofd(&wq->bfd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, NULL, fwd_udp_ports[i], OSMO_SOCK_F_BIND); if (rc < 0) { perror("sock_init"); exit(1); } } while (1) { rc = osmo_select_main(0); if (rc < 0) { perror("select"); exit(1); } } exit(0); }