blob: 8d3d26fc9cf3e2d22ccbd8e1362bb4b8ae9bcb9b [file] [log] [blame]
Harald Welted32cbbb2015-11-11 21:23:23 +01001/* osmobts_sock.cpp
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +04002 *
3 * Copyright (C) 2012 Andreas Eversberg <jolly@eversberg.eu>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20#include <stdio.h>
21#include <unistd.h>
22#include <stdlib.h>
23#include <string.h>
24#include <errno.h>
25#include <assert.h>
26#include <sys/socket.h>
27#include <sys/un.h>
28extern "C" {
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040029#include <osmocom/core/select.h>
30#include <osmocom/core/msgb.h>
Max1187a772018-01-26 13:31:42 +010031#include <osmocom/core/linuxlist.h>
32#include <osmocom/core/logging.h>
33#include <osmocom/core/timer.h>
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040034}
35
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040036#include <pcu_l1_if.h>
37#include <gprs_debug.h>
38#include <gprs_bssgp_pcu.h>
Harald Welte68fc1272016-11-16 22:48:33 +010039#include <osmocom/pcu/pcuif_proto.h>
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020040#include <bts.h>
Holger Hans Peter Freyther9e21d842013-10-16 17:48:12 +020041#include <tbf.h>
Max6dc90b82018-02-19 17:17:28 +010042#include <pdch.h>
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040043
Andreas Eversberg0f4541b2013-01-16 09:17:24 +010044extern "C" {
45int l1if_close_pdch(void *obj);
46}
47
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040048/*
Harald Welted32cbbb2015-11-11 21:23:23 +010049 * osmo-bts PCU socket functions
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040050 */
51
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070052static struct {
Vadim Yanitskiy3ff1a3c2020-02-06 17:20:55 +070053 struct osmo_fd conn_bfd; /* fd for connection to the BTS */
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040054 struct osmo_timer_list timer; /* socket connect retry timer */
55 struct llist_head upqueue; /* queue for sending messages */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070056} pcu_sock_state;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040057
Stefan Sperling5b22fb72018-02-14 19:46:33 +010058static void pcu_sock_timeout(void *_priv)
59{
60 pcu_l1if_open();
61}
62
63static void pcu_tx_txt_retry(void *_priv)
64{
65 struct gprs_rlcmac_bts *bts = bts_main_data();
Stefan Sperling5b22fb72018-02-14 19:46:33 +010066
67 if (bts->active)
68 return;
69
Stefan Sperling5b22fb72018-02-14 19:46:33 +010070 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070071 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Stefan Sperling5b22fb72018-02-14 19:46:33 +010072}
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040073
74int pcu_sock_send(struct msgb *msg)
75{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040076 struct osmo_fd *conn_bfd;
77
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070078 conn_bfd = &pcu_sock_state.conn_bfd;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040079 if (conn_bfd->fd <= 0) {
80 LOGP(DL1IF, LOGL_NOTICE, "PCU socket not connected, dropping "
81 "message\n");
82 return -EIO;
83 }
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070084 msgb_enqueue(&pcu_sock_state.upqueue, msg);
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +020085 conn_bfd->when |= OSMO_FD_WRITE;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040086
87 return 0;
88}
89
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070090static void pcu_sock_close(int lost)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040091{
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070092 struct osmo_fd *bfd = &pcu_sock_state.conn_bfd;
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +020093 struct gprs_rlcmac_bts *bts = bts_main_data();
Holger Hans Peter Freyther964ddb62013-10-16 17:53:23 +020094 uint8_t trx, ts;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040095
Andreas Eversberga3c12fb2012-09-28 22:46:33 +020096 LOGP(DL1IF, LOGL_NOTICE, "PCU socket has %s connection\n",
97 (lost) ? "LOST" : "closed");
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040098
99 close(bfd->fd);
100 bfd->fd = -1;
101 osmo_fd_unregister(bfd);
102
103 /* flush the queue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700104 while (!llist_empty(&pcu_sock_state.upqueue)) {
105 struct msgb *msg = msgb_dequeue(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400106 msgb_free(msg);
107 }
108
109 /* disable all slots, kick all TBFs */
110 for (trx = 0; trx < 8; trx++) {
Maxcad867e2016-04-21 14:35:55 +0200111#ifdef ENABLE_DIRECT_PHY
Andreas Eversberg0f4541b2013-01-16 09:17:24 +0100112 if (bts->trx[trx].fl1h) {
113 l1if_close_pdch(bts->trx[trx].fl1h);
114 bts->trx[trx].fl1h = NULL;
115 }
Andreas Eversberg3afe56d2013-01-25 07:22:59 +0100116#endif
Andreas Eversbergadb2f182012-08-07 17:06:08 +0200117 for (ts = 0; ts < 8; ts++)
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200118 bts->trx[trx].pdch[ts].disable();
Max5a6bcfb2017-09-01 14:36:44 +0200119/* FIXME: NOT ALL RESOURCES are freed in this case... inconsistent with the other code. Share the code with pcu_l1if.c
120for the reset. */
Holger Hans Peter Freyther964ddb62013-10-16 17:53:23 +0200121 gprs_rlcmac_tbf::free_all(&bts->trx[trx]);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400122 }
123
Daniel Willmann6d8884d2014-06-04 18:30:59 +0200124 gprs_bssgp_destroy();
125 exit(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400126}
127
128static int pcu_sock_read(struct osmo_fd *bfd)
129{
Vadim Yanitskiyc7849c22019-08-23 17:38:43 +0200130 struct gsm_pcu_if pcu_prim;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400131 int rc;
132
Vadim Yanitskiyc7849c22019-08-23 17:38:43 +0200133 rc = recv(bfd->fd, &pcu_prim, sizeof(pcu_prim), 0);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200134 if (rc < 0 && errno == EAGAIN)
135 return 0; /* Try again later */
136 if (rc <= 0) {
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700137 pcu_sock_close(1);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200138 return -EIO;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400139 }
140
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200141 return pcu_rx(pcu_prim.msg_type, &pcu_prim);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400142}
143
144static int pcu_sock_write(struct osmo_fd *bfd)
145{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400146 int rc;
147
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700148 while (!llist_empty(&pcu_sock_state.upqueue)) {
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400149 struct msgb *msg, *msg2;
150 struct gsm_pcu_if *pcu_prim;
151
152 /* peek at the beginning of the queue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700153 msg = llist_entry(pcu_sock_state.upqueue.next, struct msgb, list);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400154 pcu_prim = (struct gsm_pcu_if *)msg->data;
155
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200156 bfd->when &= ~OSMO_FD_WRITE;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400157
158 /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
159 if (!msgb_length(msg)) {
160 LOGP(DL1IF, LOGL_ERROR, "message type (%d) with ZERO "
161 "bytes!\n", pcu_prim->msg_type);
162 goto dontsend;
163 }
164
165 /* try to send it over the socket */
166 rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
167 if (rc == 0)
168 goto close;
169 if (rc < 0) {
170 if (errno == EAGAIN) {
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200171 bfd->when |= OSMO_FD_WRITE;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400172 break;
173 }
174 goto close;
175 }
176
177dontsend:
178 /* _after_ we send it, we can deueue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700179 msg2 = msgb_dequeue(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400180 assert(msg == msg2);
181 msgb_free(msg);
182 }
183 return 0;
184
185close:
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700186 pcu_sock_close(1);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400187
188 return -1;
189}
190
191static int pcu_sock_cb(struct osmo_fd *bfd, unsigned int flags)
192{
193 int rc = 0;
194
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200195 if (flags & OSMO_FD_READ)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400196 rc = pcu_sock_read(bfd);
197 if (rc < 0)
198 return rc;
199
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200200 if (flags & OSMO_FD_WRITE)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400201 rc = pcu_sock_write(bfd);
202
203 return rc;
204}
205
206int pcu_l1if_open(void)
207{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400208 int rc;
Pau Espin Pedrolc4178e52017-08-08 15:03:50 +0200209 struct gprs_rlcmac_bts *bts = bts_main_data();
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400210
Harald Welte21848272015-11-12 01:07:41 +0100211 LOGP(DL1IF, LOGL_INFO, "Opening OsmoPCU L1 interface to OsmoBTS\n");
212
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700213 memset(&pcu_sock_state, 0x00, sizeof(pcu_sock_state));
214 INIT_LLIST_HEAD(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400215
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700216 rc = osmo_sock_unix_init_ofd(&pcu_sock_state.conn_bfd, SOCK_SEQPACKET, 0,
Vadim Yanitskiyaef6bf42019-08-23 16:50:01 +0200217 bts->pcu_sock_path, OSMO_SOCK_F_CONNECT);
218 if (rc < 0) {
219 LOGP(DL1IF, LOGL_ERROR, "Failed to connect to the BTS (%s). "
220 "Retrying...\n", bts->pcu_sock_path);
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700221 osmo_timer_setup(&pcu_sock_state.timer, pcu_sock_timeout, NULL);
222 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400223 return 0;
224 }
225
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700226 pcu_sock_state.conn_bfd.cb = pcu_sock_cb;
227 pcu_sock_state.conn_bfd.data = NULL;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400228
Maxb3df5862017-01-06 17:20:57 +0100229 LOGP(DL1IF, LOGL_NOTICE, "osmo-bts PCU socket %s has been connected\n",
Vadim Yanitskiyaef6bf42019-08-23 16:50:01 +0200230 bts->pcu_sock_path);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400231
Max0a8fae82017-03-08 18:53:30 +0100232 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
233
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100234 /* Schedule a timer so we keep trying until the BTS becomes active. */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700235 osmo_timer_setup(&pcu_sock_state.timer, pcu_tx_txt_retry, NULL);
236 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100237
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400238 return 0;
239}
240
241void pcu_l1if_close(void)
242{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400243 struct osmo_fd *bfd;
244
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700245 osmo_timer_del(&pcu_sock_state.timer);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400246
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700247 bfd = &pcu_sock_state.conn_bfd;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400248 if (bfd->fd > 0)
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700249 pcu_sock_close(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400250}