blob: 91b62a006b00f9992f428faf7cd2bd59668688eb [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++)
Pau Espin Pedrol4f67a9b2021-06-30 16:03:06 +0200124 if (pdch_is_enabled(&bts->trx[trx].pdch[ts]))
125 pdch_disable(&bts->trx[trx].pdch[ts]);
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100126 /* FIXME: NOT ALL RESOURCES are freed in this case... inconsistent with the other code. Share the code with pcu_l1if.c
127 for the reset. */
128 bts_trx_free_all_tbf(&bts->trx[trx]);
129 }
130 gprs_bssgp_destroy(bts);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400131 }
Daniel Willmann6d8884d2014-06-04 18:30:59 +0200132 exit(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400133}
134
135static int pcu_sock_read(struct osmo_fd *bfd)
136{
Pau Espin Pedrol1989a192021-06-23 19:46:07 +0200137 const size_t max_len = sizeof(struct gsm_pcu_if) + 1000;
138 uint8_t *buf = alloca(max_len);
139 struct gsm_pcu_if *pcu_prim = (struct gsm_pcu_if *)buf;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400140 int rc;
141
Pau Espin Pedrol1989a192021-06-23 19:46:07 +0200142 rc = recv(bfd->fd, buf, max_len, 0);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200143 if (rc < 0 && errno == EAGAIN)
144 return 0; /* Try again later */
145 if (rc <= 0) {
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700146 pcu_sock_close(1);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200147 return -EIO;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400148 }
149
Pau Espin Pedrol1989a192021-06-23 19:46:07 +0200150 if (rc < PCUIF_HDR_SIZE) {
151 LOGP(DL1IF, LOGL_ERROR, "Received %d bytes on PCU Socket, but primitive "
152 "hdr size is %zu, discarding\n", rc, PCUIF_HDR_SIZE);
153 return -EINVAL;
154 }
155
156 return pcu_rx(pcu_prim, rc);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400157}
158
159static int pcu_sock_write(struct osmo_fd *bfd)
160{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400161 int rc;
162
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700163 while (!llist_empty(&pcu_sock_state.upqueue)) {
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400164 struct msgb *msg, *msg2;
165 struct gsm_pcu_if *pcu_prim;
166
167 /* peek at the beginning of the queue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700168 msg = llist_entry(pcu_sock_state.upqueue.next, struct msgb, list);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400169 pcu_prim = (struct gsm_pcu_if *)msg->data;
170
Harald Welte2bbdf2e2020-10-19 12:59:13 +0200171 osmo_fd_write_disable(bfd);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400172
173 /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
174 if (!msgb_length(msg)) {
175 LOGP(DL1IF, LOGL_ERROR, "message type (%d) with ZERO "
176 "bytes!\n", pcu_prim->msg_type);
177 goto dontsend;
178 }
179
180 /* try to send it over the socket */
181 rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
182 if (rc == 0)
183 goto close;
184 if (rc < 0) {
185 if (errno == EAGAIN) {
Harald Welte2bbdf2e2020-10-19 12:59:13 +0200186 osmo_fd_write_enable(bfd);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400187 break;
188 }
189 goto close;
190 }
191
192dontsend:
193 /* _after_ we send it, we can deueue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700194 msg2 = msgb_dequeue(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400195 assert(msg == msg2);
196 msgb_free(msg);
197 }
198 return 0;
199
200close:
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700201 pcu_sock_close(1);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400202
203 return -1;
204}
205
206static int pcu_sock_cb(struct osmo_fd *bfd, unsigned int flags)
207{
208 int rc = 0;
209
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200210 if (flags & OSMO_FD_READ)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400211 rc = pcu_sock_read(bfd);
212 if (rc < 0)
213 return rc;
214
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200215 if (flags & OSMO_FD_WRITE)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400216 rc = pcu_sock_write(bfd);
217
218 return rc;
219}
220
221int pcu_l1if_open(void)
222{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400223 int rc;
Harald Welte21848272015-11-12 01:07:41 +0100224 LOGP(DL1IF, LOGL_INFO, "Opening OsmoPCU L1 interface to OsmoBTS\n");
225
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700226 memset(&pcu_sock_state, 0x00, sizeof(pcu_sock_state));
227 INIT_LLIST_HEAD(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400228
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700229 rc = osmo_sock_unix_init_ofd(&pcu_sock_state.conn_bfd, SOCK_SEQPACKET, 0,
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100230 the_pcu->pcu_sock_path, OSMO_SOCK_F_CONNECT);
Vadim Yanitskiyaef6bf42019-08-23 16:50:01 +0200231 if (rc < 0) {
232 LOGP(DL1IF, LOGL_ERROR, "Failed to connect to the BTS (%s). "
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100233 "Retrying...\n", the_pcu->pcu_sock_path);
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700234 osmo_timer_setup(&pcu_sock_state.timer, pcu_sock_timeout, NULL);
235 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400236 return 0;
237 }
238
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700239 pcu_sock_state.conn_bfd.cb = pcu_sock_cb;
240 pcu_sock_state.conn_bfd.data = NULL;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400241
Maxb3df5862017-01-06 17:20:57 +0100242 LOGP(DL1IF, LOGL_NOTICE, "osmo-bts PCU socket %s has been connected\n",
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100243 the_pcu->pcu_sock_path);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400244
Max0a8fae82017-03-08 18:53:30 +0100245 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
246
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100247 /* Schedule a timer so we keep trying until the BTS becomes active. */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700248 osmo_timer_setup(&pcu_sock_state.timer, pcu_tx_txt_retry, NULL);
249 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100250
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400251 return 0;
252}
253
254void pcu_l1if_close(void)
255{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400256 struct osmo_fd *bfd;
257
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700258 osmo_timer_del(&pcu_sock_state.timer);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400259
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700260 bfd = &pcu_sock_state.conn_bfd;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400261 if (bfd->fd > 0)
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700262 pcu_sock_close(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400263}