blob: 282e33f042dfc5d1028a7ceb2246d7f0c91109d8 [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>
Philipp Maiereaf5da32023-02-13 13:37:22 +010033#include <pcu_l1_if_phy.h>
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040034#include <gprs_debug.h>
35#include <gprs_bssgp_pcu.h>
Harald Welte68fc1272016-11-16 22:48:33 +010036#include <osmocom/pcu/pcuif_proto.h>
Holger Hans Peter Freyther34bd8bd2013-10-19 21:10:38 +020037#include <bts.h>
Holger Hans Peter Freyther9e21d842013-10-16 17:48:12 +020038#include <tbf.h>
Max6dc90b82018-02-19 17:17:28 +010039#include <pdch.h>
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040040
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040041/*
Harald Welted32cbbb2015-11-11 21:23:23 +010042 * osmo-bts PCU socket functions
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040043 */
44
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070045static struct {
Vadim Yanitskiy3ff1a3c2020-02-06 17:20:55 +070046 struct osmo_fd conn_bfd; /* fd for connection to the BTS */
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040047 struct osmo_timer_list timer; /* socket connect retry timer */
48 struct llist_head upqueue; /* queue for sending messages */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +070049} pcu_sock_state;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +040050
Stefan Sperling5b22fb72018-02-14 19:46:33 +010051static void pcu_sock_timeout(void *_priv)
52{
53 pcu_l1if_open();
54}
55
56static void pcu_tx_txt_retry(void *_priv)
57{
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010058 struct gprs_rlcmac_bts *bts;
59 bool retry = llist_empty(&the_pcu->bts_list);
Stefan Sperling5b22fb72018-02-14 19:46:33 +010060
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010061 llist_for_each_entry(bts, &the_pcu->bts_list, list) {
62 if (bts->active)
63 continue;
64 retry = true;
65 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
66 break;
67 }
Stefan Sperling5b22fb72018-02-14 19:46:33 +010068
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010069 /* If no BTS (or not all) yet active, retry */
70 if (retry)
71 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);
Harald Welte2bbdf2e2020-10-19 12:59:13 +020085 osmo_fd_write_enable(conn_bfd);
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;
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +010093 struct gprs_rlcmac_bts *bts;
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
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100109 llist_for_each_entry(bts, &the_pcu->bts_list, list) {
110 /* disable all slots, kick all TBFs */
111 for (trx = 0; trx < 8; trx++) {
Maxcad867e2016-04-21 14:35:55 +0200112#ifdef ENABLE_DIRECT_PHY
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100113 if (bts->trx[trx].fl1h) {
114 l1if_close_pdch(bts->trx[trx].fl1h);
115 bts->trx[trx].fl1h = NULL;
116 }
Andreas Eversberg3afe56d2013-01-25 07:22:59 +0100117#endif
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100118 for (ts = 0; ts < 8; ts++)
Pau Espin Pedrol4f67a9b2021-06-30 16:03:06 +0200119 if (pdch_is_enabled(&bts->trx[trx].pdch[ts]))
120 pdch_disable(&bts->trx[trx].pdch[ts]);
Pau Espin Pedrold1049dc2021-01-18 17:14:14 +0100121 /* FIXME: NOT ALL RESOURCES are freed in this case... inconsistent with the other code. Share the code with pcu_l1if.c
122 for the reset. */
123 bts_trx_free_all_tbf(&bts->trx[trx]);
124 }
125 gprs_bssgp_destroy(bts);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400126 }
Daniel Willmann6d8884d2014-06-04 18:30:59 +0200127 exit(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400128}
129
130static int pcu_sock_read(struct osmo_fd *bfd)
131{
Pau Espin Pedrol1989a192021-06-23 19:46:07 +0200132 const size_t max_len = sizeof(struct gsm_pcu_if) + 1000;
133 uint8_t *buf = alloca(max_len);
134 struct gsm_pcu_if *pcu_prim = (struct gsm_pcu_if *)buf;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400135 int rc;
136
Pau Espin Pedrol1989a192021-06-23 19:46:07 +0200137 rc = recv(bfd->fd, buf, max_len, 0);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200138 if (rc < 0 && errno == EAGAIN)
139 return 0; /* Try again later */
140 if (rc <= 0) {
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700141 pcu_sock_close(1);
Vadim Yanitskiy9e5ef542019-08-23 18:03:14 +0200142 return -EIO;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400143 }
144
Pau Espin Pedrol1989a192021-06-23 19:46:07 +0200145 if (rc < PCUIF_HDR_SIZE) {
146 LOGP(DL1IF, LOGL_ERROR, "Received %d bytes on PCU Socket, but primitive "
147 "hdr size is %zu, discarding\n", rc, PCUIF_HDR_SIZE);
148 return -EINVAL;
149 }
150
151 return pcu_rx(pcu_prim, rc);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400152}
153
154static int pcu_sock_write(struct osmo_fd *bfd)
155{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400156 int rc;
157
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700158 while (!llist_empty(&pcu_sock_state.upqueue)) {
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400159 struct msgb *msg, *msg2;
160 struct gsm_pcu_if *pcu_prim;
161
162 /* peek at the beginning of the queue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700163 msg = llist_entry(pcu_sock_state.upqueue.next, struct msgb, list);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400164 pcu_prim = (struct gsm_pcu_if *)msg->data;
165
Harald Welte2bbdf2e2020-10-19 12:59:13 +0200166 osmo_fd_write_disable(bfd);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400167
168 /* bug hunter 8-): maybe someone forgot msgb_put(...) ? */
169 if (!msgb_length(msg)) {
170 LOGP(DL1IF, LOGL_ERROR, "message type (%d) with ZERO "
171 "bytes!\n", pcu_prim->msg_type);
172 goto dontsend;
173 }
174
175 /* try to send it over the socket */
176 rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
177 if (rc == 0)
178 goto close;
179 if (rc < 0) {
180 if (errno == EAGAIN) {
Harald Welte2bbdf2e2020-10-19 12:59:13 +0200181 osmo_fd_write_enable(bfd);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400182 break;
183 }
184 goto close;
185 }
186
187dontsend:
188 /* _after_ we send it, we can deueue */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700189 msg2 = msgb_dequeue(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400190 assert(msg == msg2);
191 msgb_free(msg);
192 }
193 return 0;
194
195close:
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700196 pcu_sock_close(1);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400197
198 return -1;
199}
200
201static int pcu_sock_cb(struct osmo_fd *bfd, unsigned int flags)
202{
203 int rc = 0;
204
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200205 if (flags & OSMO_FD_READ)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400206 rc = pcu_sock_read(bfd);
207 if (rc < 0)
208 return rc;
209
Pau Espin Pedroldb9ea552020-05-09 19:18:06 +0200210 if (flags & OSMO_FD_WRITE)
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400211 rc = pcu_sock_write(bfd);
212
213 return rc;
214}
215
216int pcu_l1if_open(void)
217{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400218 int rc;
Harald Welte21848272015-11-12 01:07:41 +0100219 LOGP(DL1IF, LOGL_INFO, "Opening OsmoPCU L1 interface to OsmoBTS\n");
220
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700221 memset(&pcu_sock_state, 0x00, sizeof(pcu_sock_state));
222 INIT_LLIST_HEAD(&pcu_sock_state.upqueue);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400223
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700224 rc = osmo_sock_unix_init_ofd(&pcu_sock_state.conn_bfd, SOCK_SEQPACKET, 0,
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100225 the_pcu->pcu_sock_path, OSMO_SOCK_F_CONNECT);
Vadim Yanitskiyaef6bf42019-08-23 16:50:01 +0200226 if (rc < 0) {
227 LOGP(DL1IF, LOGL_ERROR, "Failed to connect to the BTS (%s). "
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100228 "Retrying...\n", the_pcu->pcu_sock_path);
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700229 osmo_timer_setup(&pcu_sock_state.timer, pcu_sock_timeout, NULL);
230 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400231 return 0;
232 }
233
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700234 pcu_sock_state.conn_bfd.cb = pcu_sock_cb;
235 pcu_sock_state.conn_bfd.data = NULL;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400236
Maxb3df5862017-01-06 17:20:57 +0100237 LOGP(DL1IF, LOGL_NOTICE, "osmo-bts PCU socket %s has been connected\n",
Pau Espin Pedrolac3fd122021-01-13 18:54:38 +0100238 the_pcu->pcu_sock_path);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400239
Max0a8fae82017-03-08 18:53:30 +0100240 pcu_tx_txt_ind(PCU_VERSION, "%s", PACKAGE_VERSION);
241
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100242 /* Schedule a timer so we keep trying until the BTS becomes active. */
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700243 osmo_timer_setup(&pcu_sock_state.timer, pcu_tx_txt_retry, NULL);
244 osmo_timer_schedule(&pcu_sock_state.timer, 5, 0);
Stefan Sperling5b22fb72018-02-14 19:46:33 +0100245
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400246 return 0;
247}
248
249void pcu_l1if_close(void)
250{
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400251 struct osmo_fd *bfd;
252
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700253 osmo_timer_del(&pcu_sock_state.timer);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400254
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700255 bfd = &pcu_sock_state.conn_bfd;
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400256 if (bfd->fd > 0)
Vadim Yanitskiy8832c2e2020-02-06 17:15:11 +0700257 pcu_sock_close(0);
Ivan Kluchnikovef7f28c2012-07-12 14:49:15 +0400258}