blob: 1cbd1a0fe47ed73718efcb724cf969f4afe825a6 [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.
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040014 */
15
16#include <stdio.h>
17#include <unistd.h>
18#include <stdlib.h>
19#include <string.h>
20#include <errno.h>
21#include <assert.h>
22#include <sys/socket.h>
23#include <sys/un.h>
Pau Espin Pedrole91c4c72021-01-18 17:54:30 +010024
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040025#include <osmocom/core/select.h>
26#include <osmocom/core/msgb.h>
Max1187a772018-01-26 13:31:42 +010027#include <osmocom/core/linuxlist.h>
28#include <osmocom/core/logging.h>
29#include <osmocom/core/timer.h>
Pau Espin Pedrole91c4c72021-01-18 17:54:30 +010030
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040031
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040032#include <pcu_l1_if.h>
33#include <gprs_debug.h>
34#include <gprs_bssgp_pcu.h>
Harald Welte68fc1272016-11-16 22:48:33 +010035#include <osmocom/pcu/pcuif_proto.h>
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020036#include <bts.h>
Holger Hans Peter Freyther9e21d842013-10-16 17:48:12 +020037#include <tbf.h>
Max6dc90b82018-02-19 17:17:28 +010038#include <pdch.h>
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040039
Andreas Eversberg0f4541b2013-01-16 09:17:24 +010040int l1if_close_pdch(void *obj);
Andreas Eversberg0f4541b2013-01-16 09:17:24 +010041
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040042/*
Harald Welted32cbbb2015-11-11 21:23:23 +010043 * osmo-bts PCU socket functions
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040044 */
45
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070046static struct {
Vadim Yanitskiy3ff1a3c2020-02-06 17:20:55 +070047 struct osmo_fd conn_bfd; /* fd for connection to the BTS */
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040048 struct osmo_timer_list timer; /* socket connect retry timer */
49 struct llist_head upqueue; /* queue for sending messages */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070050} pcu_sock_state;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040051
Stefan Sperling5b22fb72018-02-14 19:46:33 +010052static void pcu_sock_timeout(void *_priv)
53{
54 pcu_l1if_open();
55}
56
57static void pcu_tx_txt_retry(void *_priv)
58{
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010059 struct gprs_rlcmac_bts *bts;
60 bool retry = llist_empty(&the_pcu->bts_list);
Stefan Sperling5b22fb72018-02-14 19:46:33 +010061
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010062 llist_for_each_entry(bts, &the_pcu->bts_list, list) {
63 if (bts->active)
64 continue;
65 retry = true;
66 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
67 break;
68 }
Stefan Sperling5b22fb72018-02-14 19:46:33 +010069
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010070 /* If no BTS (or not all) yet active, retry */
71 if (retry)
72 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Stefan Sperling5b22fb72018-02-14 19:46:33 +010073}
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040074
75int pcu_sock_send(struct msgb *msg)
76{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040077 struct osmo_fd *conn_bfd;
78
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070079 conn_bfd = &pcu_sock_state.conn_bfd;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040080 if (conn_bfd->fd <= 0) {
81 LOGP(DL1IF, LOGL_NOTICE, "PCU socket not connected, dropping "
82 "message\n");
83 return -EIO;
84 }
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070085 msgb_enqueue(&pcu_sock_state.upqueue, msg);
Harald Welte2bbdf2e2020-10-19 12:59:13 +020086 osmo_fd_write_enable(conn_bfd);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040087
88 return 0;
89}
90
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070091static void pcu_sock_close(int lost)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040092{
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070093 struct osmo_fd *bfd = &pcu_sock_state.conn_bfd;
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010094 struct gprs_rlcmac_bts *bts;
Holger Hans Peter Freyther964ddb62013-10-16 17:53:23 +020095 uint8_t trx, ts;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040096
Andreas Eversberga3c12fb2012-09-28 22:46:33 +020097 LOGP(DL1IF, LOGL_NOTICE, "PCU socket has %s connection\n",
98 (lost) ? "LOST" : "closed");
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040099
100 close(bfd->fd);
101 bfd->fd = -1;
102 osmo_fd_unregister(bfd);
103
104 /* flush the queue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700105 while (!llist_empty(&pcu_sock_state.upqueue)) {
106 struct msgb *msg = msgb_dequeue(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400107 msgb_free(msg);
108 }
109
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100110 llist_for_each_entry(bts, &the_pcu->bts_list, list) {
111 /* disable all slots, kick all TBFs */
112 for (trx = 0; trx < 8; trx++) {
Maxcad867e2016-04-21 14:35:55 +0200113#ifdef ENABLE_DIRECT_PHY
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100114 if (bts->trx[trx].fl1h) {
115 l1if_close_pdch(bts->trx[trx].fl1h);
116 bts->trx[trx].fl1h = NULL;
117 }
Andreas Eversberg3afe56d2013-01-25 07:22:59 +0100118#endif
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100119 for (ts = 0; ts < 8; ts++)
Pau Espin Pedrol4f67a9b2021-06-30 16:03:06 +0200120 if (pdch_is_enabled(&bts->trx[trx].pdch[ts]))
121 pdch_disable(&bts->trx[trx].pdch[ts]);
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100122 /* FIXME: NOT ALL RESOURCES are freed in this case... inconsistent with the other code. Share the code with pcu_l1if.c
123 for the reset. */
124 bts_trx_free_all_tbf(&bts->trx[trx]);
125 }
126 gprs_bssgp_destroy(bts);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400127 }
Daniel Willmann6d8884d2014-06-04 18:30:59 +0200128 exit(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400129}
130
131static int pcu_sock_read(struct osmo_fd *bfd)
132{
Pau Espin Pedrol1989a192021-06-23 19:46:07 +0200133 const size_t max_len = sizeof(struct gsm_pcu_if) + 1000;
134 uint8_t *buf = alloca(max_len);
135 struct gsm_pcu_if *pcu_prim = (struct gsm_pcu_if *)buf;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400136 int rc;
137
Pau Espin Pedrol1989a192021-06-23 19:46:07 +0200138 rc = recv(bfd->fd, buf, max_len, 0);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200139 if (rc < 0 && errno == EAGAIN)
140 return 0; /* Try again later */
141 if (rc <= 0) {
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700142 pcu_sock_close(1);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200143 return -EIO;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400144 }
145
Pau Espin Pedrol1989a192021-06-23 19:46:07 +0200146 if (rc < PCUIF_HDR_SIZE) {
147 LOGP(DL1IF, LOGL_ERROR, "Received %d bytes on PCU Socket, but primitive "
148 "hdr size is %zu, discarding\n", rc, PCUIF_HDR_SIZE);
149 return -EINVAL;
150 }
151
152 return pcu_rx(pcu_prim, rc);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400153}
154
155static int pcu_sock_write(struct osmo_fd *bfd)
156{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400157 int rc;
158
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700159 while (!llist_empty(&pcu_sock_state.upqueue)) {
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400160 struct msgb *msg, *msg2;
161 struct gsm_pcu_if *pcu_prim;
162
163 /* peek at the beginning of the queue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700164 msg = llist_entry(pcu_sock_state.upqueue.next, struct msgb, list);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400165 pcu_prim = (struct gsm_pcu_if *)msg->data;
166
Harald Welte2bbdf2e2020-10-19 12:59:13 +0200167 osmo_fd_write_disable(bfd);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400168
169 /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
170 if (!msgb_length(msg)) {
171 LOGP(DL1IF, LOGL_ERROR, "message type (%d) with ZERO "
172 "bytes!\n", pcu_prim->msg_type);
173 goto dontsend;
174 }
175
176 /* try to send it over the socket */
177 rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
178 if (rc == 0)
179 goto close;
180 if (rc < 0) {
181 if (errno == EAGAIN) {
Harald Welte2bbdf2e2020-10-19 12:59:13 +0200182 osmo_fd_write_enable(bfd);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400183 break;
184 }
185 goto close;
186 }
187
188dontsend:
189 /* _after_ we send it, we can deueue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700190 msg2 = msgb_dequeue(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400191 assert(msg == msg2);
192 msgb_free(msg);
193 }
194 return 0;
195
196close:
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700197 pcu_sock_close(1);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400198
199 return -1;
200}
201
202static int pcu_sock_cb(struct osmo_fd *bfd, unsigned int flags)
203{
204 int rc = 0;
205
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200206 if (flags & OSMO_FD_READ)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400207 rc = pcu_sock_read(bfd);
208 if (rc < 0)
209 return rc;
210
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200211 if (flags & OSMO_FD_WRITE)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400212 rc = pcu_sock_write(bfd);
213
214 return rc;
215}
216
217int pcu_l1if_open(void)
218{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400219 int rc;
Harald Welte21848272015-11-12 01:07:41 +0100220 LOGP(DL1IF, LOGL_INFO, "Opening OsmoPCU L1 interface to OsmoBTS\n");
221
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700222 memset(&pcu_sock_state, 0x00, sizeof(pcu_sock_state));
223 INIT_LLIST_HEAD(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400224
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700225 rc = osmo_sock_unix_init_ofd(&pcu_sock_state.conn_bfd, SOCK_SEQPACKET, 0,
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100226 the_pcu->pcu_sock_path, OSMO_SOCK_F_CONNECT);
Vadim Yanitskiyaef6bf42019-08-23 16:50:01 +0200227 if (rc < 0) {
228 LOGP(DL1IF, LOGL_ERROR, "Failed to connect to the BTS (%s). "
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100229 "Retrying...\n", the_pcu->pcu_sock_path);
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700230 osmo_timer_setup(&pcu_sock_state.timer, pcu_sock_timeout, NULL);
231 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400232 return 0;
233 }
234
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700235 pcu_sock_state.conn_bfd.cb = pcu_sock_cb;
236 pcu_sock_state.conn_bfd.data = NULL;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400237
Maxb3df5862017-01-06 17:20:57 +0100238 LOGP(DL1IF, LOGL_NOTICE, "osmo-bts PCU socket %s has been connected\n",
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100239 the_pcu->pcu_sock_path);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400240
Max0a8fae82017-03-08 18:53:30 +0100241 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
242
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100243 /* Schedule a timer so we keep trying until the BTS becomes active. */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700244 osmo_timer_setup(&pcu_sock_state.timer, pcu_tx_txt_retry, NULL);
245 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100246
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400247 return 0;
248}
249
250void pcu_l1if_close(void)
251{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400252 struct osmo_fd *bfd;
253
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700254 osmo_timer_del(&pcu_sock_state.timer);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400255
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700256 bfd = &pcu_sock_state.conn_bfd;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400257 if (bfd->fd > 0)
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700258 pcu_sock_close(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400259}