blob: 8281b4f84aa8509ed6cc764f993a918f21d9e312 [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>
15#include <osmocom/gsm/tlv.h>
16#include <osmocom/core/msgb.h>
17#include <osmocom/core/logging.h>
Harald Welte71d87b22011-07-18 14:49:56 +020018#include <osmocom/core/talloc.h>
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020019#include <osmocom/abis/e1_input.h>
20#include <osmocom/abis/ipaccess.h>
21#include <osmocom/core/socket.h>
Pablo Neira Ayusoef132692013-07-08 01:17:27 +020022#include <osmocom/core/backtrace.h>
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020023
24#include <osmocom/abis/ipa.h>
25
Maxf4463672018-02-13 15:17:27 +010026#define LOGIPA(link, level, fmt, args...) LOGP(DLINP, level, "%s:%u " fmt, link->addr, link->port, ## args)
27
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +020028void ipa_msg_push_header(struct msgb *msg, uint8_t proto)
29{
30 struct ipaccess_head *hh;
31
32 msg->l2h = msg->data;
33 hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
34 hh->proto = proto;
35 hh->len = htons(msgb_l2len(msg));
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020036}
37
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020038void ipa_client_conn_close(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020039{
Harald Weltee68055b2013-06-30 14:21:54 +020040 /* be safe against multiple calls */
41 if (link->ofd->fd != -1) {
42 osmo_fd_unregister(link->ofd);
43 close(link->ofd->fd);
44 link->ofd->fd = -1;
45 }
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020046 msgb_free(link->pending_msg);
47 link->pending_msg = NULL;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020048}
49
Pau Espin Pedrol27757982018-08-28 17:32:29 +020050static int ipa_client_read(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020051{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020052 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020053 struct msgb *msg;
54 int ret;
55
Maxf4463672018-02-13 15:17:27 +010056 LOGIPA(link, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020057
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020058 ret = ipa_msg_recv_buffered(ofd->fd, &msg, &link->pending_msg);
Pau Espin Pedrol493c8e62018-08-28 16:46:39 +020059 if (ret <= 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020060 if (ret == -EAGAIN)
Pau Espin Pedrol27757982018-08-28 17:32:29 +020061 return 0;
Pau Espin Pedrol493c8e62018-08-28 16:46:39 +020062 else if (ret == -EPIPE || ret == -ECONNRESET)
Maxf4463672018-02-13 15:17:27 +010063 LOGIPA(link, LOGL_ERROR, "lost connection with server\n");
Pau Espin Pedrol493c8e62018-08-28 16:46:39 +020064 else if (ret == 0)
65 LOGIPA(link, LOGL_ERROR, "connection closed with server\n");
Harald Welte51de9ca2013-06-30 20:13:16 +020066 ipa_client_conn_close(link);
67 if (link->updown_cb)
68 link->updown_cb(link, 0);
Pau Espin Pedrol27757982018-08-28 17:32:29 +020069 return -EBADF;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020070 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020071 if (link->read_cb)
Pau Espin Pedrol27757982018-08-28 17:32:29 +020072 return link->read_cb(link, msg);
73 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020074}
75
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020076static void ipa_client_write(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020077{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020078 if (link->write_cb)
79 link->write_cb(link);
80}
81
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +020082static int ipa_client_write_default_cb(struct ipa_client_conn *link)
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020083{
84 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020085 struct msgb *msg;
86 struct llist_head *lh;
87 int ret;
88
Maxf4463672018-02-13 15:17:27 +010089 LOGIPA(link, LOGL_DEBUG, "sending data\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020090
91 if (llist_empty(&link->tx_queue)) {
Harald Weltede3959e2020-10-18 22:28:50 +020092 ofd->when &= ~OSMO_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020093 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020094 }
95 lh = link->tx_queue.next;
96 llist_del(lh);
97 msg = llist_entry(lh, struct msgb, list);
98
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020099 ret = send(link->ofd->fd, msg->data, msg->len, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200100 if (ret < 0) {
101 if (errno == EPIPE || errno == ENOTCONN) {
Harald Welte51de9ca2013-06-30 20:13:16 +0200102 ipa_client_conn_close(link);
103 if (link->updown_cb)
104 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200105 }
Maxf4463672018-02-13 15:17:27 +0100106 LOGIPA(link, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200107 }
108 msgb_free(msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200109 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200110}
111
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200112static int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200113{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200114 struct ipa_client_conn *link = ofd->data;
Pau Espin Pedrol27757982018-08-28 17:32:29 +0200115 int error, ret = 0;
Harald Welte4301c372011-08-19 13:33:16 +0200116 socklen_t len = sizeof(error);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200117
118 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200119 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200120 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
121 if (ret >= 0 && error > 0) {
Harald Welte51de9ca2013-06-30 20:13:16 +0200122 ipa_client_conn_close(link);
123 if (link->updown_cb)
124 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200125 return 0;
126 }
Harald Weltede3959e2020-10-18 22:28:50 +0200127 ofd->when &= ~OSMO_FD_WRITE;
Maxf4463672018-02-13 15:17:27 +0100128 LOGIPA(link, LOGL_NOTICE, "connection done\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200129 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Harald Welte51de9ca2013-06-30 20:13:16 +0200130 if (link->updown_cb)
131 link->updown_cb(link, 1);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200132 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200133 case IPA_CLIENT_LINK_STATE_CONNECTED:
Harald Weltede3959e2020-10-18 22:28:50 +0200134 if (what & OSMO_FD_READ) {
Maxf4463672018-02-13 15:17:27 +0100135 LOGIPA(link, LOGL_DEBUG, "connected read\n");
Pau Espin Pedrol27757982018-08-28 17:32:29 +0200136 ret = ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200137 }
Harald Weltede3959e2020-10-18 22:28:50 +0200138 if (ret != -EBADF && (what & OSMO_FD_WRITE)) {
Maxf4463672018-02-13 15:17:27 +0100139 LOGIPA(link, LOGL_DEBUG, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200140 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200141 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200142 break;
143 default:
144 break;
145 }
146 return 0;
147}
148
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200149struct ipa_client_conn *
150ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200151 int priv_nr, const char *addr, uint16_t port,
Harald Welte51de9ca2013-06-30 20:13:16 +0200152 void (*updown_cb)(struct ipa_client_conn *link, int up),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200153 int (*read_cb)(struct ipa_client_conn *link,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200154 struct msgb *msgb),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200155 int (*write_cb)(struct ipa_client_conn *link),
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200156 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200157{
Pau Espin Pedrolb6e28bf2019-11-08 17:30:28 +0100158 return ipa_client_conn_create2(ctx, ts, priv_nr, NULL, 0, addr, port,
159 updown_cb, read_cb, write_cb, data);
160}
161
162struct ipa_client_conn *
163ipa_client_conn_create2(void *ctx, struct e1inp_ts *ts,
164 int priv_nr, const char *loc_addr, uint16_t loc_port,
165 const char *rem_addr, uint16_t rem_port,
166 void (*updown_cb)(struct ipa_client_conn *link, int up),
167 int (*read_cb)(struct ipa_client_conn *link,
168 struct msgb *msgb),
169 int (*write_cb)(struct ipa_client_conn *link),
170 void *data)
171{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200172 struct ipa_client_conn *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200173
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200174 ipa_link = talloc_zero(ctx, struct ipa_client_conn);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200175 if (!ipa_link)
176 return NULL;
177
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200178 if (ts) {
Pablo Neira Ayuso00af7722011-09-08 12:47:06 +0200179 if (ts->line->driver == NULL) {
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200180 talloc_free(ipa_link);
181 return NULL;
182 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200183 ipa_link->ofd = &ts->driver.ipaccess.fd;
184 } else {
185 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
186 if (ipa_link->ofd == NULL) {
187 talloc_free(ipa_link);
188 return NULL;
189 }
190 }
191
Harald Welte6e831b72020-10-18 22:59:58 +0200192 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 +0200193 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pau Espin Pedrolb6e28bf2019-11-08 17:30:28 +0100194 ipa_link->local_addr = talloc_strdup(ipa_link, loc_addr);
195 ipa_link->local_port = loc_port;
196 ipa_link->addr = talloc_strdup(ipa_link, rem_addr);
197 ipa_link->port = rem_port;
Harald Welte51de9ca2013-06-30 20:13:16 +0200198 ipa_link->updown_cb = updown_cb;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200199 ipa_link->read_cb = read_cb;
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200200 /* default to generic write callback if not set. */
201 if (write_cb == NULL)
202 ipa_link->write_cb = ipa_client_write_default_cb;
Pablo Neira Ayuso81ed7592012-08-22 16:35:17 +0200203 else
204 ipa_link->write_cb = write_cb;
205
Pablo Neira Ayuso2220a052011-09-08 18:43:31 +0200206 if (ts)
207 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200208 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200209 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200210
211 return ipa_link;
212}
213
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200214void ipa_client_conn_destroy(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200215{
216 talloc_free(link);
217}
218
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200219int ipa_client_conn_open(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200220{
221 int ret;
222
Harald Weltee7e1b752014-08-17 21:41:34 +0200223 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pau Espin Pedrolb6e28bf2019-11-08 17:30:28 +0100224 ret = osmo_sock_init2(AF_INET, SOCK_STREAM, IPPROTO_TCP,
225 link->local_addr, link->local_port,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200226 link->addr, link->port,
Pau Espin Pedrolb6e28bf2019-11-08 17:30:28 +0100227 OSMO_SOCK_F_BIND|OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
Harald Welte14dd30a2016-11-26 09:37:09 +0100228 if (ret < 0)
229 return ret;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200230 link->ofd->fd = ret;
Harald Weltede3959e2020-10-18 22:28:50 +0200231 link->ofd->when |= OSMO_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200232 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200233 close(ret);
Harald Welte51de9ca2013-06-30 20:13:16 +0200234 link->ofd->fd = -1;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200235 return -EIO;
236 }
Harald Welte51de9ca2013-06-30 20:13:16 +0200237
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200238 return 0;
239}
240
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200241void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200242{
243 msgb_enqueue(&link->tx_queue, msg);
Harald Weltede3959e2020-10-18 22:28:50 +0200244 link->ofd->when |= OSMO_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200245}
246
Holger Hans Peter Freyther90878592015-01-18 17:50:05 +0100247size_t ipa_client_conn_clear_queue(struct ipa_client_conn *link)
248{
249 size_t deleted = 0;
250
251 while (!llist_empty(&link->tx_queue)) {
252 struct msgb *msg = msgb_dequeue(&link->tx_queue);
253 msgb_free(msg);
254 deleted += 1;
255 }
256
Harald Weltede3959e2020-10-18 22:28:50 +0200257 link->ofd->when &= ~OSMO_FD_WRITE;
Holger Hans Peter Freyther90878592015-01-18 17:50:05 +0100258 return deleted;
259}
260
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200261static int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200262{
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200263 int fd, ret;
Max480073a2019-01-20 12:43:45 +0100264 char ipbuf[INET6_ADDRSTRLEN + 1];
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200265 struct sockaddr_in sa;
266 socklen_t sa_len = sizeof(sa);
267 struct ipa_server_link *link = ofd->data;
268
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200269 fd = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
270 if (fd < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200271 LOGP(DLINP, LOGL_ERROR, "failed to accept from origin "
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200272 "peer, reason=`%s'\n", strerror(errno));
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200273 return fd;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200274 }
Max480073a2019-01-20 12:43:45 +0100275
276 if (!link->addr) {
277 ret = osmo_sock_get_local_ip(fd, ipbuf, INET6_ADDRSTRLEN + 1);
278 if (ret == 0)
279 link->addr = talloc_strdup(link, ipbuf);
280 }
281
Max3a2aa092019-01-20 12:48:47 +0100282 LOGIPA(link, LOGL_NOTICE, "accept()ed new link from %s:%u\n",
283 inet_ntoa(sa.sin_addr), ntohs(sa.sin_port));
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200284
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200285 ret = link->accept_cb(link, fd);
286 if (ret < 0) {
287 LOGP(DLINP, LOGL_ERROR,
Debian Mobcom Maintainers418775c2018-08-09 21:32:08 +0200288 "failed to process accept()ed new link, "
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200289 "reason=`%s'\n", strerror(-ret));
290 close(fd);
291 return ret;
292 }
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200293
294 return 0;
295}
296
297struct ipa_server_link *
298ipa_server_link_create(void *ctx, struct e1inp_line *line,
299 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200300 int (*accept_cb)(struct ipa_server_link *link, int fd),
301 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200302{
303 struct ipa_server_link *ipa_link;
304
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200305 OSMO_ASSERT(accept_cb != NULL);
306
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200307 ipa_link = talloc_zero(ctx, struct ipa_server_link);
308 if (!ipa_link)
309 return NULL;
310
Harald Welte6e831b72020-10-18 22:59:58 +0200311 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 +0100312 if (addr)
313 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200314 ipa_link->port = port;
315 ipa_link->accept_cb = accept_cb;
316 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200317 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200318
319 return ipa_link;
320
321}
322
323void ipa_server_link_destroy(struct ipa_server_link *link)
324{
325 talloc_free(link);
326}
327
328int ipa_server_link_open(struct ipa_server_link *link)
329{
330 int ret;
331
332 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
333 link->addr, link->port, OSMO_SOCK_F_BIND);
334 if (ret < 0)
335 return ret;
336
337 link->ofd.fd = ret;
338 if (osmo_fd_register(&link->ofd) < 0) {
339 close(ret);
Alexander Couzense11afda2019-08-28 02:35:10 +0200340 link->ofd.fd = -1;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200341 return -EIO;
342 }
343 return 0;
344}
345
346void ipa_server_link_close(struct ipa_server_link *link)
347{
Alexander Couzense11afda2019-08-28 02:35:10 +0200348 if (link->ofd.fd == -1)
349 return;
350
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200351 osmo_fd_unregister(&link->ofd);
352 close(link->ofd.fd);
Alexander Couzense11afda2019-08-28 02:35:10 +0200353 link->ofd.fd = -1;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200354}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200355
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200356static int ipa_server_conn_read(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200357{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200358 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200359 struct msgb *msg;
360 int ret;
361
Maxf4463672018-02-13 15:17:27 +0100362 LOGIPA(conn, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200363
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200364 ret = ipa_msg_recv_buffered(ofd->fd, &msg, &conn->pending_msg);
Pau Espin Pedrol3750dea2018-08-28 17:49:29 +0200365 if (ret <= 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200366 if (ret == -EAGAIN)
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200367 return 0;
Pau Espin Pedrol3750dea2018-08-28 17:49:29 +0200368 else if (ret == -EPIPE || ret == -ECONNRESET)
Maxf4463672018-02-13 15:17:27 +0100369 LOGIPA(conn, LOGL_ERROR, "lost connection with server\n");
Pau Espin Pedrol3750dea2018-08-28 17:49:29 +0200370 else if (ret == 0)
371 LOGIPA(conn, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200372 ipa_server_conn_destroy(conn);
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200373 return -EBADF;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200374 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200375 if (conn->cb)
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200376 return conn->cb(conn, msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200377
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200378 return 0;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200379}
380
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200381static void ipa_server_conn_write(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200382{
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200383 struct msgb *msg;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200384 int ret;
385
Maxf4463672018-02-13 15:17:27 +0100386 LOGIPA(conn, LOGL_DEBUG, "sending data\n");
Neels Hofmeyr01543a12017-09-14 04:32:19 +0200387 msg = msgb_dequeue(&conn->tx_queue);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200388
Neels Hofmeyr01543a12017-09-14 04:32:19 +0200389 if (!msg) {
Harald Weltede3959e2020-10-18 22:28:50 +0200390 conn->ofd.when &= ~OSMO_FD_WRITE;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200391 return;
392 }
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200393
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200394 ret = send(conn->ofd.fd, msg->data, msg->len, 0);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200395 if (ret < 0) {
Maxf4463672018-02-13 15:17:27 +0100396 LOGIPA(conn, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200397 }
398 msgb_free(msg);
399}
400
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200401static int ipa_server_conn_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200402{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200403 struct ipa_server_conn *conn = ofd->data;
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200404 int rc = 0;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200405
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200406 LOGP(DLINP, LOGL_DEBUG, "connected read/write\n");
Harald Weltede3959e2020-10-18 22:28:50 +0200407 if (what & OSMO_FD_READ)
Pau Espin Pedrol082876b2018-08-28 17:53:38 +0200408 rc = ipa_server_conn_read(conn);
Harald Weltede3959e2020-10-18 22:28:50 +0200409 if (rc != -EBADF && (what & OSMO_FD_WRITE))
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200410 ipa_server_conn_write(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200411
412 return 0;
413}
414
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200415struct ipa_server_conn *
416ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd,
417 int (*cb)(struct ipa_server_conn *conn, struct msgb *msg),
Daniel Willmanna0d93312011-09-15 12:56:58 +0200418 int (*closed_cb)(struct ipa_server_conn *conn), void *data)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200419{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200420 struct ipa_server_conn *conn;
Harald Welteb2d727a2016-04-28 07:53:49 +0200421 struct sockaddr_in sa;
422 socklen_t sa_len = sizeof(sa);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200423
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200424 conn = talloc_zero(ctx, struct ipa_server_conn);
425 if (conn == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200426 LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in server, "
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200427 "reason=`%s'\n", strerror(errno));
428 return NULL;
429 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200430 conn->server = link;
Harald Welte6e831b72020-10-18 22:59:58 +0200431 osmo_fd_setup(&conn->ofd, fd, OSMO_FD_READ, ipa_server_conn_cb, conn, 0);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200432 conn->cb = cb;
Daniel Willmanna0d93312011-09-15 12:56:58 +0200433 conn->closed_cb = closed_cb;
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200434 conn->data = data;
435 INIT_LLIST_HEAD(&conn->tx_queue);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200436
Harald Welteb2d727a2016-04-28 07:53:49 +0200437 if (!getpeername(fd, (struct sockaddr *)&sa, &sa_len)) {
438 char *str = inet_ntoa(sa.sin_addr);
439 conn->addr = talloc_strdup(conn, str);
440 conn->port = ntohs(sa.sin_port);
441 }
442
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200443 if (osmo_fd_register(&conn->ofd) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200444 LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200445 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200446 return NULL;
447 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200448 return conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200449}
450
Harald Welte12814b92016-04-28 07:54:31 +0200451int ipa_server_conn_ccm(struct ipa_server_conn *conn, struct msgb *msg)
452{
453 struct tlv_parsed tlvp;
454 uint8_t msg_type = *(msg->l2h);
455 struct ipaccess_unit unit_data = {};
456 char *unitid;
457 int len, rc;
458
459 /* shared CCM handling on both server and client */
460 rc = ipa_ccm_rcvmsg_base(msg, &conn->ofd);
461 switch (rc) {
462 case -1:
463 /* error in IPA CCM processing */
464 goto err;
465 case 1:
466 /* IPA CCM message that was handled in _base */
467 return 0;
468 case 0:
469 /* IPA CCM message that we need to handle */
470 break;
471 default:
472 /* Error */
Maxf4463672018-02-13 15:17:27 +0100473 LOGIPA(conn, LOGL_ERROR, "Unexpected return from "
Harald Welte12814b92016-04-28 07:54:31 +0200474 "ipa_ccm_rcvmsg_base: %d\n", rc);
475 goto err;
476 }
477
478 switch (msg_type) {
479 case IPAC_MSGT_ID_RESP:
Harald Welte82eb55e2018-08-01 13:22:55 +0200480 rc = ipa_ccm_id_resp_parse(&tlvp, (const uint8_t *)msg->l2h+1, msgb_l2len(msg)-1);
Harald Welte12814b92016-04-28 07:54:31 +0200481 if (rc < 0) {
Maxf4463672018-02-13 15:17:27 +0100482 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESPonse with "
Harald Welte12814b92016-04-28 07:54:31 +0200483 "malformed TLVs\n");
484 goto err;
485 }
486 if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
Maxf4463672018-02-13 15:17:27 +0100487 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP without "
Harald Welte12814b92016-04-28 07:54:31 +0200488 "unit ID\n");
489 goto err;
490 }
491 len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT);
492 if (len < 1) {
Maxf4463672018-02-13 15:17:27 +0100493 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP with short"
Harald Welte12814b92016-04-28 07:54:31 +0200494 "unit ID\n");
495 goto err;
496 }
497 unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT);
498 unitid[len-1] = '\0';
499 ipa_parse_unitid(unitid, &unit_data);
500
501 /* FIXME */
502 rc = conn->ccm_cb(conn, msg, &tlvp, &unit_data);
503 if (rc < 0)
504 goto err;
505 break;
506 default:
Maxf4463672018-02-13 15:17:27 +0100507 LOGIPA(conn, LOGL_ERROR, "Unknown IPA message type\n");
Harald Welte12814b92016-04-28 07:54:31 +0200508 break;
509 }
510 return 0;
511err:
512 /* in case of any error, we close the connection */
513 ipa_server_conn_destroy(conn);
514 return -1;
515}
516
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200517void ipa_server_conn_destroy(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200518{
Harald Weltec0a0ec42019-03-04 22:32:52 +0100519 /* make the function re-entrant in case closed_cb() below somehow
520 * calls again into this destructor */
521 if (conn->ofd.fd == -1)
522 return;
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200523 close(conn->ofd.fd);
Harald Weltec0a0ec42019-03-04 22:32:52 +0100524 conn->ofd.fd = -1;
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200525 msgb_free(conn->pending_msg);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200526 osmo_fd_unregister(&conn->ofd);
Daniel Willmanna0d93312011-09-15 12:56:58 +0200527 if (conn->closed_cb)
528 conn->closed_cb(conn);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200529 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200530}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200531
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200532void ipa_server_conn_send(struct ipa_server_conn *conn, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200533{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200534 msgb_enqueue(&conn->tx_queue, msg);
Harald Weltede3959e2020-10-18 22:28:50 +0200535 conn->ofd.when |= OSMO_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200536}