blob: 4321696efea05c5b32bf6cf5d5091363588aa7b2 [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" {
29#include <osmocom/core/talloc.h>
30#include <osmocom/core/select.h>
31#include <osmocom/core/msgb.h>
Max1187a772018-01-26 13:31:42 +010032#include <osmocom/core/linuxlist.h>
33#include <osmocom/core/logging.h>
34#include <osmocom/core/timer.h>
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040035}
36
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040037#include <pcu_l1_if.h>
38#include <gprs_debug.h>
39#include <gprs_bssgp_pcu.h>
Harald Welte68fc1272016-11-16 22:48:33 +010040#include <osmocom/pcu/pcuif_proto.h>
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020041#include <bts.h>
Holger Hans Peter Freyther9e21d842013-10-16 17:48:12 +020042#include <tbf.h>
Max6dc90b82018-02-19 17:17:28 +010043#include <pdch.h>
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040044
Andreas Eversberge266bd42012-07-13 14:00:21 +020045extern void *tall_pcu_ctx;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040046
Andreas Eversberg0f4541b2013-01-16 09:17:24 +010047extern "C" {
48int l1if_close_pdch(void *obj);
49}
50
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040051/*
Harald Welted32cbbb2015-11-11 21:23:23 +010052 * osmo-bts PCU socket functions
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040053 */
54
55struct pcu_sock_state {
56 struct osmo_fd conn_bfd; /* fd for connection to lcr */
57 struct osmo_timer_list timer; /* socket connect retry timer */
58 struct llist_head upqueue; /* queue for sending messages */
59} *pcu_sock_state = NULL;
60
Stefan Sperling5b22fb72018-02-14 19:46:33 +010061static void pcu_sock_timeout(void *_priv)
62{
63 pcu_l1if_open();
64}
65
66static void pcu_tx_txt_retry(void *_priv)
67{
68 struct gprs_rlcmac_bts *bts = bts_main_data();
69 struct pcu_sock_state *state = pcu_sock_state;
70
71 if (bts->active)
72 return;
73
74 LOGP(DL1IF, LOGL_INFO, "Sending version %s to BTS.\n", PACKAGE_VERSION);
75 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
76 osmo_timer_schedule(&state->timer, 5, 0);
77}
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040078
79int pcu_sock_send(struct msgb *msg)
80{
81 struct pcu_sock_state *state = pcu_sock_state;
82 struct osmo_fd *conn_bfd;
83
84 if (!state) {
85 LOGP(DL1IF, LOGL_NOTICE, "PCU socket not created, dropping "
86 "message\n");
87 return -EINVAL;
88 }
89 conn_bfd = &state->conn_bfd;
90 if (conn_bfd->fd <= 0) {
91 LOGP(DL1IF, LOGL_NOTICE, "PCU socket not connected, dropping "
92 "message\n");
93 return -EIO;
94 }
95 msgb_enqueue(&state->upqueue, msg);
96 conn_bfd->when |= BSC_FD_WRITE;
97
98 return 0;
99}
100
Andreas Eversberga3c12fb2012-09-28 22:46:33 +0200101static void pcu_sock_close(struct pcu_sock_state *state, int lost)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400102{
103 struct osmo_fd *bfd = &state->conn_bfd;
Holger Hans Peter Freytherb6acfda2013-10-17 19:41:11 +0200104 struct gprs_rlcmac_bts *bts = bts_main_data();
Holger Hans Peter Freyther964ddb62013-10-16 17:53:23 +0200105 uint8_t trx, ts;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400106
Andreas Eversberga3c12fb2012-09-28 22:46:33 +0200107 LOGP(DL1IF, LOGL_NOTICE, "PCU socket has %s connection\n",
108 (lost) ? "LOST" : "closed");
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400109
110 close(bfd->fd);
111 bfd->fd = -1;
112 osmo_fd_unregister(bfd);
113
114 /* flush the queue */
115 while (!llist_empty(&state->upqueue)) {
116 struct msgb *msg = msgb_dequeue(&state->upqueue);
117 msgb_free(msg);
118 }
119
120 /* disable all slots, kick all TBFs */
121 for (trx = 0; trx < 8; trx++) {
Maxcad867e2016-04-21 14:35:55 +0200122#ifdef ENABLE_DIRECT_PHY
Andreas Eversberg0f4541b2013-01-16 09:17:24 +0100123 if (bts->trx[trx].fl1h) {
124 l1if_close_pdch(bts->trx[trx].fl1h);
125 bts->trx[trx].fl1h = NULL;
126 }
Andreas Eversberg3afe56d2013-01-25 07:22:59 +0100127#endif
Andreas Eversbergadb2f182012-08-07 17:06:08 +0200128 for (ts = 0; ts < 8; ts++)
Holger Hans Peter Freyther17b0d832013-10-19 17:37:48 +0200129 bts->trx[trx].pdch[ts].disable();
Max5a6bcfb2017-09-01 14:36:44 +0200130/* FIXME: NOT ALL RESOURCES are freed in this case... inconsistent with the other code. Share the code with pcu_l1if.c
131for the reset. */
Holger Hans Peter Freyther964ddb62013-10-16 17:53:23 +0200132 gprs_rlcmac_tbf::free_all(&bts->trx[trx]);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400133 }
134
Daniel Willmann6d8884d2014-06-04 18:30:59 +0200135 gprs_bssgp_destroy();
136 exit(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400137}
138
139static int pcu_sock_read(struct osmo_fd *bfd)
140{
141 struct pcu_sock_state *state = (struct pcu_sock_state *)bfd->data;
Vadim Yanitskiyc7849c22019-08-23 17:38:43 +0200142 struct gsm_pcu_if pcu_prim;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400143 int rc;
144
Vadim Yanitskiyc7849c22019-08-23 17:38:43 +0200145 rc = recv(bfd->fd, &pcu_prim, sizeof(pcu_prim), 0);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200146 if (rc < 0 && errno == EAGAIN)
147 return 0; /* Try again later */
148 if (rc <= 0) {
149 pcu_sock_close(state, 1);
150 return -EIO;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400151 }
152
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200153 return pcu_rx(pcu_prim.msg_type, &pcu_prim);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400154}
155
156static int pcu_sock_write(struct osmo_fd *bfd)
157{
158 struct pcu_sock_state *state = (struct pcu_sock_state *)bfd->data;
159 int rc;
160
161 while (!llist_empty(&state->upqueue)) {
162 struct msgb *msg, *msg2;
163 struct gsm_pcu_if *pcu_prim;
164
165 /* peek at the beginning of the queue */
166 msg = llist_entry(state->upqueue.next, struct msgb, list);
167 pcu_prim = (struct gsm_pcu_if *)msg->data;
168
169 bfd->when &= ~BSC_FD_WRITE;
170
171 /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
172 if (!msgb_length(msg)) {
173 LOGP(DL1IF, LOGL_ERROR, "message type (%d) with ZERO "
174 "bytes!\n", pcu_prim->msg_type);
175 goto dontsend;
176 }
177
178 /* try to send it over the socket */
179 rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
180 if (rc == 0)
181 goto close;
182 if (rc < 0) {
183 if (errno == EAGAIN) {
184 bfd->when |= BSC_FD_WRITE;
185 break;
186 }
187 goto close;
188 }
189
190dontsend:
191 /* _after_ we send it, we can deueue */
192 msg2 = msgb_dequeue(&state->upqueue);
193 assert(msg == msg2);
194 msgb_free(msg);
195 }
196 return 0;
197
198close:
Andreas Eversberga3c12fb2012-09-28 22:46:33 +0200199 pcu_sock_close(state, 1);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400200
201 return -1;
202}
203
204static int pcu_sock_cb(struct osmo_fd *bfd, unsigned int flags)
205{
206 int rc = 0;
207
208 if (flags & BSC_FD_READ)
209 rc = pcu_sock_read(bfd);
210 if (rc < 0)
211 return rc;
212
213 if (flags & BSC_FD_WRITE)
214 rc = pcu_sock_write(bfd);
215
216 return rc;
217}
218
219int pcu_l1if_open(void)
220{
221 struct pcu_sock_state *state;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400222 int rc;
Pau Espin Pedrolc4178e52017-08-08 15:03:50 +0200223 struct gprs_rlcmac_bts *bts = bts_main_data();
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400224
Harald Welte21848272015-11-12 01:07:41 +0100225 LOGP(DL1IF, LOGL_INFO, "Opening OsmoPCU L1 interface to OsmoBTS\n");
226
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400227 state = pcu_sock_state;
228 if (!state) {
Andreas Eversberge266bd42012-07-13 14:00:21 +0200229 state = talloc_zero(tall_pcu_ctx, struct pcu_sock_state);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400230 if (!state)
231 return -ENOMEM;
232 INIT_LLIST_HEAD(&state->upqueue);
233 }
234
Vadim Yanitskiyaef6bf42019-08-23 16:50:01 +0200235 rc = osmo_sock_unix_init_ofd(&state->conn_bfd, SOCK_SEQPACKET, 0,
236 bts->pcu_sock_path, OSMO_SOCK_F_CONNECT);
237 if (rc < 0) {
238 LOGP(DL1IF, LOGL_ERROR, "Failed to connect to the BTS (%s). "
239 "Retrying...\n", bts->pcu_sock_path);
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100240 osmo_timer_setup(&state->timer, pcu_sock_timeout, NULL);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400241 osmo_timer_schedule(&state->timer, 5, 0);
242 return 0;
243 }
244
Vadim Yanitskiyaef6bf42019-08-23 16:50:01 +0200245 state->conn_bfd.cb = pcu_sock_cb;
246 state->conn_bfd.data = state;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400247
Maxb3df5862017-01-06 17:20:57 +0100248 LOGP(DL1IF, LOGL_NOTICE, "osmo-bts PCU socket %s has been connected\n",
Vadim Yanitskiyaef6bf42019-08-23 16:50:01 +0200249 bts->pcu_sock_path);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400250
251 pcu_sock_state = state;
252
Max0a8fae82017-03-08 18:53:30 +0100253 LOGP(DL1IF, LOGL_INFO, "Sending version %s to BTS.\n", PACKAGE_VERSION);
254 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
255
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100256 /* Schedule a timer so we keep trying until the BTS becomes active. */
257 osmo_timer_setup(&state->timer, pcu_tx_txt_retry, NULL);
258 osmo_timer_schedule(&state->timer, 5, 0);
259
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400260 return 0;
261}
262
263void pcu_l1if_close(void)
264{
265 struct pcu_sock_state *state = pcu_sock_state;
266 struct osmo_fd *bfd;
267
268 if (!state)
269 return;
270
Holger Hans Peter Freyther51c57042013-07-13 11:52:50 +0200271 osmo_timer_del(&state->timer);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400272
273 bfd = &state->conn_bfd;
274 if (bfd->fd > 0)
Andreas Eversberga3c12fb2012-09-28 22:46:33 +0200275 pcu_sock_close(state, 0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400276 talloc_free(state);
277 pcu_sock_state = NULL;
278}