blob: 94e7e5a68729130f9da2ee88e9deba5b70f1cc1c [file] [log] [blame]
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +02001#include "internal.h"
2
3#include <stdio.h>
4#include <unistd.h>
5#include <stdlib.h>
6#include <errno.h>
7#include <string.h>
8#include <time.h>
9#include <sys/fcntl.h>
10#include <sys/socket.h>
11#include <sys/ioctl.h>
12#include <arpa/inet.h>
13
14#include <osmocom/core/select.h>
Daniel Willmann61135252022-12-15 04:48:51 +010015#include <osmocom/core/timer.h>
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020016#include <osmocom/gsm/tlv.h>
17#include <osmocom/core/msgb.h>
18#include <osmocom/core/logging.h>
Harald Welte71d87b22011-07-18 14:49:56 +020019#include <osmocom/core/talloc.h>
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020020#include <osmocom/abis/e1_input.h>
21#include <osmocom/abis/ipaccess.h>
22#include <osmocom/core/socket.h>
Pablo Neira Ayusoef132692013-07-08 01:17:27 +020023#include <osmocom/core/backtrace.h>
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020024
25#include <osmocom/abis/ipa.h>
26
Maxf4463672018-02-13 15:17:27 +010027#define LOGIPA(link, level, fmt, args...) LOGP(DLINP, level, "%s:%u " fmt, link->addr, link->port, ## args)
28
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +020029void ipa_msg_push_header(struct msgb *msg, uint8_t proto)
30{
31 struct ipaccess_head *hh;
32
33 msg->l2h = msg->data;
34 hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
35 hh->proto = proto;
36 hh->len = htons(msgb_l2len(msg));
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020037}
38
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020039void ipa_client_conn_close(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020040{
Daniel Willmann61135252022-12-15 04:48:51 +010041 osmo_timer_del(&link->timer);
42
Harald Weltee68055b2013-06-30 14:21:54 +020043 /* be safe against multiple calls */
44 if (link->ofd->fd != -1) {
45 osmo_fd_unregister(link->ofd);
46 close(link->ofd->fd);
47 link->ofd->fd = -1;
48 }
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020049 msgb_free(link->pending_msg);
50 link->pending_msg = NULL;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020051}
52
Pau Espin Pedrol27757982018-08-28 17:32:29 +020053static int ipa_client_read(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020054{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020055 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020056 struct msgb *msg;
57 int ret;
58
Maxf4463672018-02-13 15:17:27 +010059 LOGIPA(link, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020060
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020061 ret = ipa_msg_recv_buffered(ofd->fd, &msg, &link->pending_msg);
Pau Espin Pedrol493c8e62018-08-28 16:46:39 +020062 if (ret <= 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020063 if (ret == -EAGAIN)
Pau Espin Pedrol27757982018-08-28 17:32:29 +020064 return 0;
Pau Espin Pedrol493c8e62018-08-28 16:46:39 +020065 else if (ret == -EPIPE || ret == -ECONNRESET)
Maxf4463672018-02-13 15:17:27 +010066 LOGIPA(link, LOGL_ERROR, "lost connection with server\n");
Pau Espin Pedrol493c8e62018-08-28 16:46:39 +020067 else if (ret == 0)
68 LOGIPA(link, LOGL_ERROR, "connection closed with server\n");
Harald Welte51de9ca2013-06-30 20:13:16 +020069 ipa_client_conn_close(link);
70 if (link->updown_cb)
71 link->updown_cb(link, 0);
Pau Espin Pedrol27757982018-08-28 17:32:29 +020072 return -EBADF;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020073 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020074 if (link->read_cb)
Pau Espin Pedrol27757982018-08-28 17:32:29 +020075 return link->read_cb(link, msg);
76 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020077}
78
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020079static void ipa_client_write(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020080{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020081 if (link->write_cb)
82 link->write_cb(link);
83}
84
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +020085static int ipa_client_write_default_cb(struct ipa_client_conn *link)
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020086{
87 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020088 struct msgb *msg;
89 struct llist_head *lh;
90 int ret;
91
Maxf4463672018-02-13 15:17:27 +010092 LOGIPA(link, LOGL_DEBUG, "sending data\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020093
94 if (llist_empty(&link->tx_queue)) {
Harald Welte949b8a22020-10-18 23:01:53 +020095 osmo_fd_write_disable(ofd);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020096 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020097 }
98 lh = link->tx_queue.next;
99 llist_del(lh);
100 msg = llist_entry(lh, struct msgb, list);
101
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200102 ret = send(link->ofd->fd, msg->data, msg->len, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200103 if (ret < 0) {
104 if (errno == EPIPE || errno == ENOTCONN) {
Harald Welte51de9ca2013-06-30 20:13:16 +0200105 ipa_client_conn_close(link);
106 if (link->updown_cb)
107 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200108 }
Maxf4463672018-02-13 15:17:27 +0100109 LOGIPA(link, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200110 }
111 msgb_free(msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200112 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200113}
114
Daniel Willmann61135252022-12-15 04:48:51 +0100115static void ipa_connect_failure(struct ipa_client_conn *link)
116{
117 ipa_client_conn_close(link);
118 if (link->updown_cb)
119 link->updown_cb(link, 0);
120}
121
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200122static int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200123{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200124 struct ipa_client_conn *link = ofd->data;
Pau Espin Pedrol27757982018-08-28 17:32:29 +0200125 int error, ret = 0;
Harald Welte4301c372011-08-19 13:33:16 +0200126 socklen_t len = sizeof(error);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200127
128 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200129 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200130 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
131 if (ret >= 0 && error > 0) {
Daniel Willmann61135252022-12-15 04:48:51 +0100132 ipa_connect_failure(link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200133 return 0;
134 }
Daniel Willmann61135252022-12-15 04:48:51 +0100135
136 /* Stop the timer when connection succeeds, on failure it's deleted in
137 ipa_client_conn_close() called by ipa_connect_failure() above */
138 osmo_timer_del(&link->timer);
139
Harald Welte949b8a22020-10-18 23:01:53 +0200140 osmo_fd_write_disable(ofd);
Maxf4463672018-02-13 15:17:27 +0100141 LOGIPA(link, LOGL_NOTICE, "connection done\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200142 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Harald Welte51de9ca2013-06-30 20:13:16 +0200143 if (link->updown_cb)
144 link->updown_cb(link, 1);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200145 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200146 case IPA_CLIENT_LINK_STATE_CONNECTED:
Harald Weltede3959e2020-10-18 22:28:50 +0200147 if (what & OSMO_FD_READ) {
Maxf4463672018-02-13 15:17:27 +0100148 LOGIPA(link, LOGL_DEBUG, "connected read\n");
Pau Espin Pedrol27757982018-08-28 17:32:29 +0200149 ret = ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200150 }
Harald Weltede3959e2020-10-18 22:28:50 +0200151 if (ret != -EBADF && (what & OSMO_FD_WRITE)) {
Maxf4463672018-02-13 15:17:27 +0100152 LOGIPA(link, LOGL_DEBUG, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200153 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200154 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200155 break;
156 default:
157 break;
158 }
Daniel Willmann61135252022-12-15 04:48:51 +0100159 return 0;
160}
161
162/* Treat the connect timeout exactly like a connect failure */
163static void ipa_connect_timeout_cb(void *data)
164{
165 struct ipa_client_conn *link = (struct ipa_client_conn *)data;
166
167 LOGIPA(link, LOGL_NOTICE, "Connect timeout reached\n");
168 ipa_connect_failure(link);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200169}
170
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200171struct ipa_client_conn *
172ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200173 int priv_nr, const char *addr, uint16_t port,
Harald Welte51de9ca2013-06-30 20:13:16 +0200174 void (*updown_cb)(struct ipa_client_conn *link, int up),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200175 int (*read_cb)(struct ipa_client_conn *link,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200176 struct msgb *msgb),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200177 int (*write_cb)(struct ipa_client_conn *link),
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200178 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200179{
Pau Espin Pedrolb6e28bf2019-11-08 17:30:28 +0100180 return ipa_client_conn_create2(ctx, ts, priv_nr, NULL, 0, addr, port,
181 updown_cb, read_cb, write_cb, data);
182}
183
184struct ipa_client_conn *
185ipa_client_conn_create2(void *ctx, struct e1inp_ts *ts,
186 int priv_nr, const char *loc_addr, uint16_t loc_port,
187 const char *rem_addr, uint16_t rem_port,
188 void (*updown_cb)(struct ipa_client_conn *link, int up),
189 int (*read_cb)(struct ipa_client_conn *link,
190 struct msgb *msgb),
191 int (*write_cb)(struct ipa_client_conn *link),
192 void *data)
193{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200194 struct ipa_client_conn *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200195
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200196 ipa_link = talloc_zero(ctx, struct ipa_client_conn);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200197 if (!ipa_link)
198 return NULL;
199
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200200 if (ts) {
Pablo Neira Ayuso00af7722011-09-08 12:47:06 +0200201 if (ts->line->driver == NULL) {
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200202 talloc_free(ipa_link);
203 return NULL;
204 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200205 ipa_link->ofd = &ts->driver.ipaccess.fd;
206 } else {
207 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
208 if (ipa_link->ofd == NULL) {
209 talloc_free(ipa_link);
210 return NULL;
211 }
212 }
213
Harald Welte6e831b72020-10-18 22:59:58 +0200214 osmo_fd_setup(ipa_link->ofd, -1, OSMO_FD_READ|OSMO_FD_WRITE, ipa_client_fd_cb, ipa_link, priv_nr);
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200215 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pau Espin Pedrolb6e28bf2019-11-08 17:30:28 +0100216 ipa_link->local_addr = talloc_strdup(ipa_link, loc_addr);
217 ipa_link->local_port = loc_port;
218 ipa_link->addr = talloc_strdup(ipa_link, rem_addr);
219 ipa_link->port = rem_port;
Harald Welte51de9ca2013-06-30 20:13:16 +0200220 ipa_link->updown_cb = updown_cb;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200221 ipa_link->read_cb = read_cb;
Daniel Willmann61135252022-12-15 04:48:51 +0100222 osmo_timer_setup(&ipa_link->timer, ipa_connect_timeout_cb, ipa_link);
223
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200224 /* default to generic write callback if not set. */
225 if (write_cb == NULL)
226 ipa_link->write_cb = ipa_client_write_default_cb;
Pablo Neira Ayuso81ed7592012-08-22 16:35:17 +0200227 else
228 ipa_link->write_cb = write_cb;
229
Pablo Neira Ayuso2220a052011-09-08 18:43:31 +0200230 if (ts)
231 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200232 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200233 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200234
235 return ipa_link;
236}
237
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200238void ipa_client_conn_destroy(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200239{
240 talloc_free(link);
241}
242
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200243int ipa_client_conn_open(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200244{
Daniel Willmann61135252022-12-15 04:48:51 +0100245 return ipa_client_conn_open2(link, 30);
246}
247
248int ipa_client_conn_open2(struct ipa_client_conn *link, unsigned int connect_timeout)
249{
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200250 int ret;
251
Daniel Willmannf2c76032022-12-15 16:05:29 +0100252 if (link->ofd->fd != -1)
253 return -EINVAL;
254
Harald Weltee7e1b752014-08-17 21:41:34 +0200255 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pau Espin Pedrolb6e28bf2019-11-08 17:30:28 +0100256 ret = osmo_sock_init2(AF_INET, SOCK_STREAM, IPPROTO_TCP,
257 link->local_addr, link->local_port,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200258 link->addr, link->port,
Harald Welte6bcc32b2021-04-28 14:40:59 +0200259 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK|
260 OSMO_SOCK_F_DSCP(link->dscp) | OSMO_SOCK_F_PRIO(link->priority));
Harald Welte14dd30a2016-11-26 09:37:09 +0100261 if (ret < 0)
262 return ret;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200263 link->ofd->fd = ret;
Harald Welte949b8a22020-10-18 23:01:53 +0200264 osmo_fd_write_enable(link->ofd);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200265 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200266 close(ret);
Harald Welte51de9ca2013-06-30 20:13:16 +0200267 link->ofd->fd = -1;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200268 return -EIO;
269 }
Harald Welte51de9ca2013-06-30 20:13:16 +0200270
Daniel Willmann61135252022-12-15 04:48:51 +0100271 if (connect_timeout > 0)
272 osmo_timer_schedule(&link->timer, connect_timeout, 0);
273
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200274 return 0;
275}
276
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200277void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200278{
279 msgb_enqueue(&link->tx_queue, msg);
Harald Welte949b8a22020-10-18 23:01:53 +0200280 osmo_fd_write_enable(link->ofd);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200281}
282
Holger Hans Peter Freyther90878592015-01-18 17:50:05 +0100283size_t ipa_client_conn_clear_queue(struct ipa_client_conn *link)
284{
285 size_t deleted = 0;
286
287 while (!llist_empty(&link->tx_queue)) {
288 struct msgb *msg = msgb_dequeue(&link->tx_queue);
289 msgb_free(msg);
290 deleted += 1;
291 }
292
Harald Welte949b8a22020-10-18 23:01:53 +0200293 osmo_fd_write_disable(link->ofd);
Holger Hans Peter Freyther90878592015-01-18 17:50:05 +0100294 return deleted;
295}
296
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200297static int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200298{
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200299 int fd, ret;
Max480073a2019-01-20 12:43:45 +0100300 char ipbuf[INET6_ADDRSTRLEN + 1];
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200301 struct sockaddr_in sa;
302 socklen_t sa_len = sizeof(sa);
303 struct ipa_server_link *link = ofd->data;
304
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200305 fd = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
306 if (fd < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200307 LOGP(DLINP, LOGL_ERROR, "failed to accept from origin "
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200308 "peer, reason=`%s'\n", strerror(errno));
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200309 return fd;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200310 }
Max480073a2019-01-20 12:43:45 +0100311
312 if (!link->addr) {
313 ret = osmo_sock_get_local_ip(fd, ipbuf, INET6_ADDRSTRLEN + 1);
314 if (ret == 0)
315 link->addr = talloc_strdup(link, ipbuf);
316 }
317
Max3a2aa092019-01-20 12:48:47 +0100318 LOGIPA(link, LOGL_NOTICE, "accept()ed new link from %s:%u\n",
319 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200320
Harald Welte6bcc32b2021-04-28 14:40:59 +0200321 /* make new fd inherit DSCP + priority of listen-socket */
322 osmo_sock_set_dscp(fd, link->dscp);
323 osmo_sock_set_priority(fd, link->priority);
324
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200325 ret = link->accept_cb(link, fd);
326 if (ret < 0) {
327 LOGP(DLINP, LOGL_ERROR,
Debian Mobcom Maintainers418775c2018-08-09 21:32:08 +0200328 "failed to process accept()ed new link, "
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200329 "reason=`%s'\n", strerror(-ret));
330 close(fd);
331 return ret;
332 }
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200333
334 return 0;
335}
336
337struct ipa_server_link *
338ipa_server_link_create(void *ctx, struct e1inp_line *line,
339 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200340 int (*accept_cb)(struct ipa_server_link *link, int fd),
341 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200342{
343 struct ipa_server_link *ipa_link;
344
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200345 OSMO_ASSERT(accept_cb != NULL);
346
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200347 ipa_link = talloc_zero(ctx, struct ipa_server_link);
348 if (!ipa_link)
349 return NULL;
350
Harald Welte6e831b72020-10-18 22:59:58 +0200351 osmo_fd_setup(&ipa_link->ofd, -1, OSMO_FD_READ|OSMO_FD_WRITE, ipa_server_fd_cb, ipa_link, 0);
Max480073a2019-01-20 12:43:45 +0100352 if (addr)
353 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200354 ipa_link->port = port;
355 ipa_link->accept_cb = accept_cb;
356 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200357 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200358
359 return ipa_link;
360
361}
362
363void ipa_server_link_destroy(struct ipa_server_link *link)
364{
365 talloc_free(link);
366}
367
368int ipa_server_link_open(struct ipa_server_link *link)
369{
370 int ret;
371
372 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Harald Welte6bcc32b2021-04-28 14:40:59 +0200373 link->addr, link->port, OSMO_SOCK_F_BIND|
374 OSMO_SOCK_F_DSCP(link->dscp) | OSMO_SOCK_F_PRIO(link->priority));
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200375 if (ret < 0)
376 return ret;
377
378 link->ofd.fd = ret;
379 if (osmo_fd_register(&link->ofd) < 0) {
380 close(ret);
Alexander Couzense11afda2019-08-28 02:35:10 +0200381 link->ofd.fd = -1;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200382 return -EIO;
383 }
384 return 0;
385}
386
387void ipa_server_link_close(struct ipa_server_link *link)
388{
Alexander Couzense11afda2019-08-28 02:35:10 +0200389 if (link->ofd.fd == -1)
390 return;
391
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200392 osmo_fd_unregister(&link->ofd);
393 close(link->ofd.fd);
Alexander Couzense11afda2019-08-28 02:35:10 +0200394 link->ofd.fd = -1;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200395}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200396
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200397static int ipa_server_conn_read(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200398{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200399 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200400 struct msgb *msg;
401 int ret;
402
Maxf4463672018-02-13 15:17:27 +0100403 LOGIPA(conn, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200404
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200405 ret = ipa_msg_recv_buffered(ofd->fd, &msg, &conn->pending_msg);
Pau Espin Pedrol3750dea2018-08-28 17:49:29 +0200406 if (ret <= 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200407 if (ret == -EAGAIN)
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200408 return 0;
Pau Espin Pedrol3750dea2018-08-28 17:49:29 +0200409 else if (ret == -EPIPE || ret == -ECONNRESET)
Maxf4463672018-02-13 15:17:27 +0100410 LOGIPA(conn, LOGL_ERROR, "lost connection with server\n");
Pau Espin Pedrol3750dea2018-08-28 17:49:29 +0200411 else if (ret == 0)
412 LOGIPA(conn, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200413 ipa_server_conn_destroy(conn);
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200414 return -EBADF;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200415 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200416 if (conn->cb)
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200417 return conn->cb(conn, msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200418
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200419 return 0;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200420}
421
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200422static void ipa_server_conn_write(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200423{
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200424 struct msgb *msg;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200425 int ret;
426
Maxf4463672018-02-13 15:17:27 +0100427 LOGIPA(conn, LOGL_DEBUG, "sending data\n");
Neels Hofmeyr01543a12017-09-14 04:32:19 +0200428 msg = msgb_dequeue(&conn->tx_queue);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200429
Neels Hofmeyr01543a12017-09-14 04:32:19 +0200430 if (!msg) {
Harald Welte949b8a22020-10-18 23:01:53 +0200431 osmo_fd_write_disable(&conn->ofd);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200432 return;
433 }
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200434
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200435 ret = send(conn->ofd.fd, msg->data, msg->len, 0);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200436 if (ret < 0) {
Maxf4463672018-02-13 15:17:27 +0100437 LOGIPA(conn, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200438 }
439 msgb_free(msg);
440}
441
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200442static int ipa_server_conn_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200443{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200444 struct ipa_server_conn *conn = ofd->data;
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200445 int rc = 0;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200446
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200447 LOGP(DLINP, LOGL_DEBUG, "connected read/write\n");
Harald Weltede3959e2020-10-18 22:28:50 +0200448 if (what & OSMO_FD_READ)
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200449 rc = ipa_server_conn_read(conn);
Harald Weltede3959e2020-10-18 22:28:50 +0200450 if (rc != -EBADF && (what & OSMO_FD_WRITE))
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200451 ipa_server_conn_write(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200452
453 return 0;
454}
455
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200456struct ipa_server_conn *
457ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd,
458 int (*cb)(struct ipa_server_conn *conn, struct msgb *msg),
Daniel Willmanna0d93312011-09-15 12:56:58 +0200459 int (*closed_cb)(struct ipa_server_conn *conn), void *data)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200460{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200461 struct ipa_server_conn *conn;
Harald Welteb2d727a2016-04-28 07:53:49 +0200462 struct sockaddr_in sa;
463 socklen_t sa_len = sizeof(sa);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200464
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200465 conn = talloc_zero(ctx, struct ipa_server_conn);
466 if (conn == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200467 LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in server, "
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200468 "reason=`%s'\n", strerror(errno));
469 return NULL;
470 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200471 conn->server = link;
Harald Welte6e831b72020-10-18 22:59:58 +0200472 osmo_fd_setup(&conn->ofd, fd, OSMO_FD_READ, ipa_server_conn_cb, conn, 0);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200473 conn->cb = cb;
Daniel Willmanna0d93312011-09-15 12:56:58 +0200474 conn->closed_cb = closed_cb;
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200475 conn->data = data;
476 INIT_LLIST_HEAD(&conn->tx_queue);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200477
Harald Welteb2d727a2016-04-28 07:53:49 +0200478 if (!getpeername(fd, (struct sockaddr *)&sa, &sa_len)) {
479 char *str = inet_ntoa(sa.sin_addr);
480 conn->addr = talloc_strdup(conn, str);
481 conn->port = ntohs(sa.sin_port);
482 }
483
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200484 if (osmo_fd_register(&conn->ofd) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200485 LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200486 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200487 return NULL;
488 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200489 return conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200490}
491
Harald Welte12814b92016-04-28 07:54:31 +0200492int ipa_server_conn_ccm(struct ipa_server_conn *conn, struct msgb *msg)
493{
494 struct tlv_parsed tlvp;
495 uint8_t msg_type = *(msg->l2h);
496 struct ipaccess_unit unit_data = {};
497 char *unitid;
498 int len, rc;
499
500 /* shared CCM handling on both server and client */
501 rc = ipa_ccm_rcvmsg_base(msg, &conn->ofd);
502 switch (rc) {
503 case -1:
504 /* error in IPA CCM processing */
505 goto err;
506 case 1:
507 /* IPA CCM message that was handled in _base */
508 return 0;
509 case 0:
510 /* IPA CCM message that we need to handle */
511 break;
512 default:
513 /* Error */
Maxf4463672018-02-13 15:17:27 +0100514 LOGIPA(conn, LOGL_ERROR, "Unexpected return from "
Harald Welte12814b92016-04-28 07:54:31 +0200515 "ipa_ccm_rcvmsg_base: %d\n", rc);
516 goto err;
517 }
518
519 switch (msg_type) {
520 case IPAC_MSGT_ID_RESP:
Harald Welte82eb55e2018-08-01 13:22:55 +0200521 rc = ipa_ccm_id_resp_parse(&tlvp, (const uint8_t *)msg->l2h+1, msgb_l2len(msg)-1);
Harald Welte12814b92016-04-28 07:54:31 +0200522 if (rc < 0) {
Maxf4463672018-02-13 15:17:27 +0100523 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESPonse with "
Harald Welte12814b92016-04-28 07:54:31 +0200524 "malformed TLVs\n");
525 goto err;
526 }
527 if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
Maxf4463672018-02-13 15:17:27 +0100528 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP without "
Harald Welte12814b92016-04-28 07:54:31 +0200529 "unit ID\n");
530 goto err;
531 }
532 len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT);
533 if (len < 1) {
Maxf4463672018-02-13 15:17:27 +0100534 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP with short"
Harald Welte12814b92016-04-28 07:54:31 +0200535 "unit ID\n");
536 goto err;
537 }
538 unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT);
539 unitid[len-1] = '\0';
540 ipa_parse_unitid(unitid, &unit_data);
541
542 /* FIXME */
543 rc = conn->ccm_cb(conn, msg, &tlvp, &unit_data);
544 if (rc < 0)
545 goto err;
546 break;
547 default:
Maxf4463672018-02-13 15:17:27 +0100548 LOGIPA(conn, LOGL_ERROR, "Unknown IPA message type\n");
Harald Welte12814b92016-04-28 07:54:31 +0200549 break;
550 }
551 return 0;
552err:
553 /* in case of any error, we close the connection */
554 ipa_server_conn_destroy(conn);
555 return -1;
556}
557
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200558void ipa_server_conn_destroy(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200559{
Harald Weltec0a0ec42019-03-04 22:32:52 +0100560 /* make the function re-entrant in case closed_cb() below somehow
561 * calls again into this destructor */
562 if (conn->ofd.fd == -1)
563 return;
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200564 close(conn->ofd.fd);
Harald Weltec0a0ec42019-03-04 22:32:52 +0100565 conn->ofd.fd = -1;
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200566 msgb_free(conn->pending_msg);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200567 osmo_fd_unregister(&conn->ofd);
Daniel Willmanna0d93312011-09-15 12:56:58 +0200568 if (conn->closed_cb)
569 conn->closed_cb(conn);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200570 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200571}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200572
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200573void ipa_server_conn_send(struct ipa_server_conn *conn, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200574{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200575 msgb_enqueue(&conn->tx_queue, msg);
Harald Welte949b8a22020-10-18 23:01:53 +0200576 osmo_fd_write_enable(&conn->ofd);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200577}