blob: 4e1171fc44b5b2782a92e32f591d6c22ee425d1c [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>
Pau Espin Pedrole91c4c72021-01-18 17:54:30 +010028
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>
Pau Espin Pedrole91c4c72021-01-18 17:54:30 +010034
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040035
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 +010044int l1if_close_pdch(void *obj);
Andreas Eversberg0f4541b2013-01-16 09:17:24 +010045
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040046/*
Harald Welted32cbbb2015-11-11 21:23:23 +010047 * osmo-bts PCU socket functions
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040048 */
49
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070050static struct {
Vadim Yanitskiy3ff1a3c2020-02-06 17:20:55 +070051 struct osmo_fd conn_bfd; /* fd for connection to the BTS */
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040052 struct osmo_timer_list timer; /* socket connect retry timer */
53 struct llist_head upqueue; /* queue for sending messages */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070054} pcu_sock_state;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040055
Stefan Sperling5b22fb72018-02-14 19:46:33 +010056static void pcu_sock_timeout(void *_priv)
57{
58 pcu_l1if_open();
59}
60
61static void pcu_tx_txt_retry(void *_priv)
62{
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010063 struct gprs_rlcmac_bts *bts;
64 bool retry = llist_empty(&the_pcu->bts_list);
Stefan Sperling5b22fb72018-02-14 19:46:33 +010065
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010066 llist_for_each_entry(bts, &the_pcu->bts_list, list) {
67 if (bts->active)
68 continue;
69 retry = true;
70 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
71 break;
72 }
Stefan Sperling5b22fb72018-02-14 19:46:33 +010073
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010074 /* If no BTS (or not all) yet active, retry */
75 if (retry)
76 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Stefan Sperling5b22fb72018-02-14 19:46:33 +010077}
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040078
79int pcu_sock_send(struct msgb *msg)
80{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040081 struct osmo_fd *conn_bfd;
82
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070083 conn_bfd = &pcu_sock_state.conn_bfd;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040084 if (conn_bfd->fd <= 0) {
85 LOGP(DL1IF, LOGL_NOTICE, "PCU socket not connected, dropping "
86 "message\n");
87 return -EIO;
88 }
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070089 msgb_enqueue(&pcu_sock_state.upqueue, msg);
Harald Welte2bbdf2e2020-10-19 12:59:13 +020090 osmo_fd_write_enable(conn_bfd);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040091
92 return 0;
93}
94
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070095static void pcu_sock_close(int lost)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040096{
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070097 struct osmo_fd *bfd = &pcu_sock_state.conn_bfd;
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010098 struct gprs_rlcmac_bts *bts;
Holger Hans Peter Freyther964ddb62013-10-16 17:53:23 +020099 uint8_t trx, ts;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400100
Andreas Eversberga3c12fb2012-09-28 22:46:33 +0200101 LOGP(DL1IF, LOGL_NOTICE, "PCU socket has %s connection\n",
102 (lost) ? "LOST" : "closed");
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400103
104 close(bfd->fd);
105 bfd->fd = -1;
106 osmo_fd_unregister(bfd);
107
108 /* flush the queue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700109 while (!llist_empty(&pcu_sock_state.upqueue)) {
110 struct msgb *msg = msgb_dequeue(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400111 msgb_free(msg);
112 }
113
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100114 llist_for_each_entry(bts, &the_pcu->bts_list, list) {
115 /* disable all slots, kick all TBFs */
116 for (trx = 0; trx < 8; trx++) {
Maxcad867e2016-04-21 14:35:55 +0200117#ifdef ENABLE_DIRECT_PHY
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100118 if (bts->trx[trx].fl1h) {
119 l1if_close_pdch(bts->trx[trx].fl1h);
120 bts->trx[trx].fl1h = NULL;
121 }
Andreas Eversberg3afe56d2013-01-25 07:22:59 +0100122#endif
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100123 for (ts = 0; ts < 8; ts++)
124 pdch_disable(&bts->trx[trx].pdch[ts]);
125 /* FIXME: NOT ALL RESOURCES are freed in this case... inconsistent with the other code. Share the code with pcu_l1if.c
126 for the reset. */
127 bts_trx_free_all_tbf(&bts->trx[trx]);
128 }
129 gprs_bssgp_destroy(bts);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400130 }
Daniel Willmann6d8884d2014-06-04 18:30:59 +0200131 exit(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400132}
133
134static int pcu_sock_read(struct osmo_fd *bfd)
135{
Vadim Yanitskiyc7849c22019-08-23 17:38:43 +0200136 struct gsm_pcu_if pcu_prim;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400137 int rc;
138
Vadim Yanitskiyc7849c22019-08-23 17:38:43 +0200139 rc = recv(bfd->fd, &pcu_prim, sizeof(pcu_prim), 0);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200140 if (rc < 0 && errno == EAGAIN)
141 return 0; /* Try again later */
142 if (rc <= 0) {
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700143 pcu_sock_close(1);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200144 return -EIO;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400145 }
146
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200147 return pcu_rx(pcu_prim.msg_type, &pcu_prim);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400148}
149
150static int pcu_sock_write(struct osmo_fd *bfd)
151{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400152 int rc;
153
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700154 while (!llist_empty(&pcu_sock_state.upqueue)) {
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400155 struct msgb *msg, *msg2;
156 struct gsm_pcu_if *pcu_prim;
157
158 /* peek at the beginning of the queue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700159 msg = llist_entry(pcu_sock_state.upqueue.next, struct msgb, list);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400160 pcu_prim = (struct gsm_pcu_if *)msg->data;
161
Harald Welte2bbdf2e2020-10-19 12:59:13 +0200162 osmo_fd_write_disable(bfd);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400163
164 /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
165 if (!msgb_length(msg)) {
166 LOGP(DL1IF, LOGL_ERROR, "message type (%d) with ZERO "
167 "bytes!\n", pcu_prim->msg_type);
168 goto dontsend;
169 }
170
171 /* try to send it over the socket */
172 rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
173 if (rc == 0)
174 goto close;
175 if (rc < 0) {
176 if (errno == EAGAIN) {
Harald Welte2bbdf2e2020-10-19 12:59:13 +0200177 osmo_fd_write_enable(bfd);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400178 break;
179 }
180 goto close;
181 }
182
183dontsend:
184 /* _after_ we send it, we can deueue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700185 msg2 = msgb_dequeue(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400186 assert(msg == msg2);
187 msgb_free(msg);
188 }
189 return 0;
190
191close:
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700192 pcu_sock_close(1);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400193
194 return -1;
195}
196
197static int pcu_sock_cb(struct osmo_fd *bfd, unsigned int flags)
198{
199 int rc = 0;
200
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200201 if (flags & OSMO_FD_READ)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400202 rc = pcu_sock_read(bfd);
203 if (rc < 0)
204 return rc;
205
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200206 if (flags & OSMO_FD_WRITE)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400207 rc = pcu_sock_write(bfd);
208
209 return rc;
210}
211
212int pcu_l1if_open(void)
213{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400214 int rc;
Harald Welte21848272015-11-12 01:07:41 +0100215 LOGP(DL1IF, LOGL_INFO, "Opening OsmoPCU L1 interface to OsmoBTS\n");
216
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700217 memset(&pcu_sock_state, 0x00, sizeof(pcu_sock_state));
218 INIT_LLIST_HEAD(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400219
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700220 rc = osmo_sock_unix_init_ofd(&pcu_sock_state.conn_bfd, SOCK_SEQPACKET, 0,
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100221 the_pcu->pcu_sock_path, OSMO_SOCK_F_CONNECT);
Vadim Yanitskiyaef6bf42019-08-23 16:50:01 +0200222 if (rc < 0) {
223 LOGP(DL1IF, LOGL_ERROR, "Failed to connect to the BTS (%s). "
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100224 "Retrying...\n", the_pcu->pcu_sock_path);
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700225 osmo_timer_setup(&pcu_sock_state.timer, pcu_sock_timeout, NULL);
226 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400227 return 0;
228 }
229
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700230 pcu_sock_state.conn_bfd.cb = pcu_sock_cb;
231 pcu_sock_state.conn_bfd.data = NULL;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400232
Maxb3df5862017-01-06 17:20:57 +0100233 LOGP(DL1IF, LOGL_NOTICE, "osmo-bts PCU socket %s has been connected\n",
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100234 the_pcu->pcu_sock_path);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400235
Max0a8fae82017-03-08 18:53:30 +0100236 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
237
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100238 /* Schedule a timer so we keep trying until the BTS becomes active. */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700239 osmo_timer_setup(&pcu_sock_state.timer, pcu_tx_txt_retry, NULL);
240 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100241
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400242 return 0;
243}
244
245void pcu_l1if_close(void)
246{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400247 struct osmo_fd *bfd;
248
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700249 osmo_timer_del(&pcu_sock_state.timer);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400250
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700251 bfd = &pcu_sock_state.conn_bfd;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400252 if (bfd->fd > 0)
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700253 pcu_sock_close(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400254}