VIRT-PHY: Properly destroy l1_model_ms after disconnect
[osmocom-bb.git] / src / host / virt_phy / src / l1ctl_sock.c
blobbf28895fdae85033793c99886fb4e7f28eec17cb
1 /* Socket based Layer1 <-> Layer23 communication over L1CTL primitives. */
3 /* (C) 2016 by Sebastian Stumpf <sebastian.stumpf87@googlemail.com>
4 * (C) 2017 by Harald Welte <laforge@gnumonks.org>
6 * All Rights Reserved
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <stdint.h>
29 #include <fcntl.h>
30 #include <errno.h>
31 #include <termios.h>
32 #include <sys/ioctl.h>
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <sys/stat.h>
36 #include <arpa/inet.h>
38 #include <osmocom/core/linuxlist.h>
39 #include <osmocom/core/select.h>
40 #include <osmocom/core/talloc.h>
41 #include <osmocom/core/socket.h>
43 #include <virtphy/l1ctl_sock.h>
44 #include <virtphy/logging.h>
46 #define L1CTL_SOCK_MSGB_SIZE 256
48 static void l1ctl_client_destroy(struct l1ctl_sock_client *lsc)
50 struct l1ctl_sock_inst *lsi = lsc->l1ctl_sock;
51 if (lsi->close_cb)
52 lsi->close_cb(lsc);
53 osmo_fd_close(&lsc->ofd);
54 llist_del(&lsc->list);
55 talloc_free(lsc);
58 /**
59 * @brief L1CTL socket file descriptor callback function.
61 * @param ofd The osmocom file descriptor.
62 * @param what Indicates if the fd has a read, write or exception request. See select.h.
64 * Will be called by osmo_select_main() if data on fd is pending.
66 static int l1ctl_sock_data_cb(struct osmo_fd *ofd, unsigned int what)
68 struct l1ctl_sock_client *lsc = ofd->data;
69 struct l1ctl_hdr *l1h;
70 struct msgb *msg;
71 uint16_t len;
72 int rc;
74 /* Check if request is really read request */
75 if (!(what & BSC_FD_READ))
76 return 0;
78 msg = msgb_alloc(L1CTL_SOCK_MSGB_SIZE, "L1CTL sock rx");
80 /* read length of the message first and convert to host byte order */
81 rc = read(ofd->fd, &len, sizeof(len));
82 if (rc < sizeof(len))
83 goto err_close;
85 /* convert to host byte order */
86 len = ntohs(len);
87 if (len <= 0 || len > L1CTL_SOCK_MSGB_SIZE)
88 goto err_close;
90 rc = read(ofd->fd, msgb_data(msg), len);
91 if (rc == len) {
92 msgb_put(msg, rc);
93 l1h = (void *) msgb_data(msg);
94 msg->l1h = (void *) l1h;
95 lsc->l1ctl_sock->recv_cb(lsc, msg);
96 return 0;
98 err_close:
99 LOGP(DL1C, LOGL_ERROR, "Failed to receive msg from l2. Connection will be closed.\n");
100 l1ctl_client_destroy(lsc);
102 return 0;
106 /* called for the master (listening) socket of the instance, allocates a new client */
107 static int l1ctl_sock_accept_cb(struct osmo_fd *ofd, unsigned int what)
110 struct l1ctl_sock_inst *lsi = ofd->data;
111 struct l1ctl_sock_client *lsc;
112 int fd, rc;
114 fd = accept(ofd->fd, NULL, NULL);
115 if (fd < 0) {
116 LOGP(DL1C, LOGL_ERROR, "Failed to accept connection to l2.\n");
117 return -1;
120 lsc = talloc_zero(lsi, struct l1ctl_sock_client);
121 if (!lsc) {
122 close(fd);
123 LOGP(DL1C, LOGL_ERROR, "Failed to allocate L1CTL client\n");
124 return -1;
127 lsc->l1ctl_sock = lsi;
128 lsc->ofd.fd = fd;
129 lsc->ofd.when = BSC_FD_READ;
130 lsc->ofd.cb = l1ctl_sock_data_cb;
131 lsc->ofd.data = lsc;
132 if (lsi->accept_cb) {
133 rc = lsi->accept_cb(lsc);
134 if (rc < 0) {
135 talloc_free(lsc);
136 close(fd);
137 return rc;
141 LOGP(DL1C, LOGL_INFO, "Accepted client (fd=%u) from server (fd=%u)\n", fd, ofd->fd);
142 if (osmo_fd_register(&lsc->ofd) != 0) {
143 LOGP(DL1C, LOGL_ERROR, "Failed to register the l2 connection fd.\n");
144 talloc_free(lsc);
145 return -1;
147 llist_add_tail(&lsc->list, &lsi->clients);
148 return 0;
151 struct l1ctl_sock_inst *l1ctl_sock_init(
152 void *ctx,
153 void (*recv_cb)(struct l1ctl_sock_client *lsc, struct msgb *msg),
154 int (*accept_cb)(struct l1ctl_sock_client *lsc),
155 void (*close_cb)(struct l1ctl_sock_client *lsc),
156 char *path)
158 struct l1ctl_sock_inst *lsi;
159 int rc;
161 if (!path)
162 path = L1CTL_SOCK_PATH;
164 lsi = talloc_zero(ctx, struct l1ctl_sock_inst);
165 lsi->priv = NULL;
166 lsi->ofd.data = lsi;
167 lsi->ofd.when = BSC_FD_READ;
168 lsi->ofd.cb = l1ctl_sock_accept_cb;
170 rc = osmo_sock_unix_init_ofd(&lsi->ofd, SOCK_STREAM, 0, path, OSMO_SOCK_F_BIND);
171 if (rc < 0) {
172 LOGP(DL1C, LOGL_ERROR, "Error creating L1CTL listening socket\n");
173 talloc_free(lsi);
174 return NULL;
177 lsi->recv_cb = recv_cb;
178 lsi->accept_cb = accept_cb;
179 lsi->close_cb = close_cb;
180 lsi->l1ctl_sock_path = path;
181 INIT_LLIST_HEAD(&lsi->clients);
183 return lsi;
186 void l1ctl_sock_destroy(struct l1ctl_sock_inst *lsi)
188 struct l1ctl_sock_client *lsc, *lsc2;
190 llist_for_each_entry_safe(lsc, lsc2, &lsi->clients, list)
191 l1ctl_client_destroy(lsc);
193 osmo_fd_close(&lsi->ofd);
194 talloc_free(lsi);
197 int l1ctl_sock_write_msg(struct l1ctl_sock_client *lsc, struct msgb *msg)
199 int rc;
200 rc = write(lsc->ofd.fd, msgb_data(msg), msgb_length(msg));
201 msgb_free(msg);
202 return rc;