blob: 995d2c38ad40c8b979ce85a2713f057cae749eb1 [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
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020050static void 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);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020059 if (ret < 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020060 if (ret == -EAGAIN)
61 return;
62 if (ret == -EPIPE || ret == -ECONNRESET)
Maxf4463672018-02-13 15:17:27 +010063 LOGIPA(link, LOGL_ERROR, "lost connection with server\n");
Harald Welte51de9ca2013-06-30 20:13:16 +020064 ipa_client_conn_close(link);
65 if (link->updown_cb)
66 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020067 return;
68 } else if (ret == 0) {
Maxf4463672018-02-13 15:17:27 +010069 LOGIPA(link, LOGL_ERROR, "connection closed with server\n");
Harald Welte51de9ca2013-06-30 20:13:16 +020070 ipa_client_conn_close(link);
71 if (link->updown_cb)
72 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020073 return;
74 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020075 if (link->read_cb)
76 link->read_cb(link, msg);
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)) {
95 ofd->when &= ~BSC_FD_WRITE;
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
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200115static int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200116{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200117 struct ipa_client_conn *link = ofd->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200118 int error, ret;
Harald Welte4301c372011-08-19 13:33:16 +0200119 socklen_t len = sizeof(error);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200120
121 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200122 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200123 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
124 if (ret >= 0 && error > 0) {
Harald Welte51de9ca2013-06-30 20:13:16 +0200125 ipa_client_conn_close(link);
126 if (link->updown_cb)
127 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200128 return 0;
129 }
130 ofd->when &= ~BSC_FD_WRITE;
Maxf4463672018-02-13 15:17:27 +0100131 LOGIPA(link, LOGL_NOTICE, "connection done\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200132 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Harald Welte51de9ca2013-06-30 20:13:16 +0200133 if (link->updown_cb)
134 link->updown_cb(link, 1);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200135 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200136 case IPA_CLIENT_LINK_STATE_CONNECTED:
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200137 if (what & BSC_FD_READ) {
Maxf4463672018-02-13 15:17:27 +0100138 LOGIPA(link, LOGL_DEBUG, "connected read\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200139 ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200140 }
141 if (what & BSC_FD_WRITE) {
Maxf4463672018-02-13 15:17:27 +0100142 LOGIPA(link, LOGL_DEBUG, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200143 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200144 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200145 break;
146 default:
147 break;
148 }
149 return 0;
150}
151
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200152struct ipa_client_conn *
153ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200154 int priv_nr, const char *addr, uint16_t port,
Harald Welte51de9ca2013-06-30 20:13:16 +0200155 void (*updown_cb)(struct ipa_client_conn *link, int up),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200156 int (*read_cb)(struct ipa_client_conn *link,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200157 struct msgb *msgb),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200158 int (*write_cb)(struct ipa_client_conn *link),
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200159 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200160{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200161 struct ipa_client_conn *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200162
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200163 ipa_link = talloc_zero(ctx, struct ipa_client_conn);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200164 if (!ipa_link)
165 return NULL;
166
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200167 if (ts) {
Pablo Neira Ayuso00af7722011-09-08 12:47:06 +0200168 if (ts->line->driver == NULL) {
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200169 talloc_free(ipa_link);
170 return NULL;
171 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200172 ipa_link->ofd = &ts->driver.ipaccess.fd;
173 } else {
174 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
175 if (ipa_link->ofd == NULL) {
176 talloc_free(ipa_link);
177 return NULL;
178 }
179 }
180
181 ipa_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
182 ipa_link->ofd->priv_nr = priv_nr;
183 ipa_link->ofd->cb = ipa_client_fd_cb;
184 ipa_link->ofd->data = ipa_link;
Harald Welte51de9ca2013-06-30 20:13:16 +0200185 ipa_link->ofd->fd = -1;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200186 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayusoc00ee732011-06-21 12:22:49 +0200187 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200188 ipa_link->port = port;
Harald Welte51de9ca2013-06-30 20:13:16 +0200189 ipa_link->updown_cb = updown_cb;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200190 ipa_link->read_cb = read_cb;
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200191 /* default to generic write callback if not set. */
192 if (write_cb == NULL)
193 ipa_link->write_cb = ipa_client_write_default_cb;
Pablo Neira Ayuso81ed7592012-08-22 16:35:17 +0200194 else
195 ipa_link->write_cb = write_cb;
196
Pablo Neira Ayuso2220a052011-09-08 18:43:31 +0200197 if (ts)
198 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200199 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200200 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200201
202 return ipa_link;
203}
204
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200205void ipa_client_conn_destroy(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200206{
207 talloc_free(link);
208}
209
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200210int ipa_client_conn_open(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200211{
212 int ret;
213
Harald Weltee7e1b752014-08-17 21:41:34 +0200214 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200215 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200216 link->addr, link->port,
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200217 OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
Harald Welte14dd30a2016-11-26 09:37:09 +0100218 if (ret < 0)
219 return ret;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200220 link->ofd->fd = ret;
Holger Hans Peter Freyther687046b2014-12-12 17:39:58 +0100221 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200222 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200223 close(ret);
Harald Welte51de9ca2013-06-30 20:13:16 +0200224 link->ofd->fd = -1;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200225 return -EIO;
226 }
Harald Welte51de9ca2013-06-30 20:13:16 +0200227
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200228 return 0;
229}
230
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200231void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200232{
233 msgb_enqueue(&link->tx_queue, msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200234 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200235}
236
Holger Hans Peter Freyther90878592015-01-18 17:50:05 +0100237size_t ipa_client_conn_clear_queue(struct ipa_client_conn *link)
238{
239 size_t deleted = 0;
240
241 while (!llist_empty(&link->tx_queue)) {
242 struct msgb *msg = msgb_dequeue(&link->tx_queue);
243 msgb_free(msg);
244 deleted += 1;
245 }
246
247 link->ofd->when &= ~BSC_FD_WRITE;
248 return deleted;
249}
250
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200251static int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200252{
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200253 int fd, ret;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200254 struct sockaddr_in sa;
255 socklen_t sa_len = sizeof(sa);
256 struct ipa_server_link *link = ofd->data;
257
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200258 fd = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
259 if (fd < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200260 LOGP(DLINP, LOGL_ERROR, "failed to accept from origin "
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200261 "peer, reason=`%s'\n", strerror(errno));
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200262 return fd;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200263 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200264 LOGP(DLINP, LOGL_NOTICE, "accept()ed new link from %s to port %u\n",
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200265 inet_ntoa(sa.sin_addr), link->port);
266
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200267 ret = link->accept_cb(link, fd);
268 if (ret < 0) {
269 LOGP(DLINP, LOGL_ERROR,
270 "failed to processs accept()ed new link, "
271 "reason=`%s'\n", strerror(-ret));
272 close(fd);
273 return ret;
274 }
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200275
276 return 0;
277}
278
279struct ipa_server_link *
280ipa_server_link_create(void *ctx, struct e1inp_line *line,
281 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200282 int (*accept_cb)(struct ipa_server_link *link, int fd),
283 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200284{
285 struct ipa_server_link *ipa_link;
286
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200287 OSMO_ASSERT(accept_cb != NULL);
288
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200289 ipa_link = talloc_zero(ctx, struct ipa_server_link);
290 if (!ipa_link)
291 return NULL;
292
293 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
294 ipa_link->ofd.cb = ipa_server_fd_cb;
295 ipa_link->ofd.data = ipa_link;
296 ipa_link->addr = talloc_strdup(ipa_link, addr);
297 ipa_link->port = port;
298 ipa_link->accept_cb = accept_cb;
299 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200300 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200301
302 return ipa_link;
303
304}
305
306void ipa_server_link_destroy(struct ipa_server_link *link)
307{
308 talloc_free(link);
309}
310
311int ipa_server_link_open(struct ipa_server_link *link)
312{
313 int ret;
314
315 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
316 link->addr, link->port, OSMO_SOCK_F_BIND);
317 if (ret < 0)
318 return ret;
319
320 link->ofd.fd = ret;
321 if (osmo_fd_register(&link->ofd) < 0) {
322 close(ret);
323 return -EIO;
324 }
325 return 0;
326}
327
328void ipa_server_link_close(struct ipa_server_link *link)
329{
330 osmo_fd_unregister(&link->ofd);
331 close(link->ofd.fd);
332}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200333
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200334static void ipa_server_conn_read(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200335{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200336 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200337 struct msgb *msg;
338 int ret;
339
Maxf4463672018-02-13 15:17:27 +0100340 LOGIPA(conn, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200341
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200342 ret = ipa_msg_recv_buffered(ofd->fd, &msg, &conn->pending_msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200343 if (ret < 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200344 if (ret == -EAGAIN)
345 return;
346 if (ret == -EPIPE || ret == -ECONNRESET)
Maxf4463672018-02-13 15:17:27 +0100347 LOGIPA(conn, LOGL_ERROR, "lost connection with server\n");
Daniel Willmanndc4479f2011-09-15 12:56:57 +0200348 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200349 return;
350 } else if (ret == 0) {
Maxf4463672018-02-13 15:17:27 +0100351 LOGIPA(conn, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200352 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200353 return;
354 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200355 if (conn->cb)
356 conn->cb(conn, msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200357
358 return;
359}
360
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200361static void ipa_server_conn_write(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200362{
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200363 struct msgb *msg;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200364 int ret;
365
Maxf4463672018-02-13 15:17:27 +0100366 LOGIPA(conn, LOGL_DEBUG, "sending data\n");
Neels Hofmeyr01543a12017-09-14 04:32:19 +0200367 msg = msgb_dequeue(&conn->tx_queue);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200368
Neels Hofmeyr01543a12017-09-14 04:32:19 +0200369 if (!msg) {
370 conn->ofd.when &= ~BSC_FD_WRITE;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200371 return;
372 }
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200373
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200374 ret = send(conn->ofd.fd, msg->data, msg->len, 0);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200375 if (ret < 0) {
Maxf4463672018-02-13 15:17:27 +0100376 LOGIPA(conn, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200377 }
378 msgb_free(msg);
379}
380
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200381static int ipa_server_conn_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200382{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200383 struct ipa_server_conn *conn = ofd->data;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200384
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200385 LOGP(DLINP, LOGL_DEBUG, "connected read/write\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200386 if (what & BSC_FD_READ)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200387 ipa_server_conn_read(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200388 if (what & BSC_FD_WRITE)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200389 ipa_server_conn_write(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200390
391 return 0;
392}
393
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200394struct ipa_server_conn *
395ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd,
396 int (*cb)(struct ipa_server_conn *conn, struct msgb *msg),
Daniel Willmanna0d93312011-09-15 12:56:58 +0200397 int (*closed_cb)(struct ipa_server_conn *conn), void *data)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200398{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200399 struct ipa_server_conn *conn;
Harald Welteb2d727a2016-04-28 07:53:49 +0200400 struct sockaddr_in sa;
401 socklen_t sa_len = sizeof(sa);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200402
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200403 conn = talloc_zero(ctx, struct ipa_server_conn);
404 if (conn == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200405 LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in server, "
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200406 "reason=`%s'\n", strerror(errno));
407 return NULL;
408 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200409 conn->server = link;
410 conn->ofd.fd = fd;
411 conn->ofd.data = conn;
412 conn->ofd.cb = ipa_server_conn_cb;
413 conn->ofd.when = BSC_FD_READ;
414 conn->cb = cb;
Daniel Willmanna0d93312011-09-15 12:56:58 +0200415 conn->closed_cb = closed_cb;
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200416 conn->data = data;
417 INIT_LLIST_HEAD(&conn->tx_queue);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200418
Harald Welteb2d727a2016-04-28 07:53:49 +0200419 if (!getpeername(fd, (struct sockaddr *)&sa, &sa_len)) {
420 char *str = inet_ntoa(sa.sin_addr);
421 conn->addr = talloc_strdup(conn, str);
422 conn->port = ntohs(sa.sin_port);
423 }
424
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200425 if (osmo_fd_register(&conn->ofd) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200426 LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200427 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200428 return NULL;
429 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200430 return conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200431}
432
Harald Welte12814b92016-04-28 07:54:31 +0200433int ipa_server_conn_ccm(struct ipa_server_conn *conn, struct msgb *msg)
434{
435 struct tlv_parsed tlvp;
436 uint8_t msg_type = *(msg->l2h);
437 struct ipaccess_unit unit_data = {};
438 char *unitid;
439 int len, rc;
440
441 /* shared CCM handling on both server and client */
442 rc = ipa_ccm_rcvmsg_base(msg, &conn->ofd);
443 switch (rc) {
444 case -1:
445 /* error in IPA CCM processing */
446 goto err;
447 case 1:
448 /* IPA CCM message that was handled in _base */
449 return 0;
450 case 0:
451 /* IPA CCM message that we need to handle */
452 break;
453 default:
454 /* Error */
Maxf4463672018-02-13 15:17:27 +0100455 LOGIPA(conn, LOGL_ERROR, "Unexpected return from "
Harald Welte12814b92016-04-28 07:54:31 +0200456 "ipa_ccm_rcvmsg_base: %d\n", rc);
457 goto err;
458 }
459
460 switch (msg_type) {
461 case IPAC_MSGT_ID_RESP:
Harald Welte82eb55e2018-08-01 13:22:55 +0200462 rc = ipa_ccm_id_resp_parse(&tlvp, (const uint8_t *)msg->l2h+1, msgb_l2len(msg)-1);
Harald Welte12814b92016-04-28 07:54:31 +0200463 if (rc < 0) {
Maxf4463672018-02-13 15:17:27 +0100464 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESPonse with "
Harald Welte12814b92016-04-28 07:54:31 +0200465 "malformed TLVs\n");
466 goto err;
467 }
468 if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
Maxf4463672018-02-13 15:17:27 +0100469 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP without "
Harald Welte12814b92016-04-28 07:54:31 +0200470 "unit ID\n");
471 goto err;
472 }
473 len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT);
474 if (len < 1) {
Maxf4463672018-02-13 15:17:27 +0100475 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP with short"
Harald Welte12814b92016-04-28 07:54:31 +0200476 "unit ID\n");
477 goto err;
478 }
479 unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT);
480 unitid[len-1] = '\0';
481 ipa_parse_unitid(unitid, &unit_data);
482
483 /* FIXME */
484 rc = conn->ccm_cb(conn, msg, &tlvp, &unit_data);
485 if (rc < 0)
486 goto err;
487 break;
488 default:
Maxf4463672018-02-13 15:17:27 +0100489 LOGIPA(conn, LOGL_ERROR, "Unknown IPA message type\n");
Harald Welte12814b92016-04-28 07:54:31 +0200490 break;
491 }
492 return 0;
493err:
494 /* in case of any error, we close the connection */
495 ipa_server_conn_destroy(conn);
496 return -1;
497}
498
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200499void ipa_server_conn_destroy(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200500{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200501 close(conn->ofd.fd);
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200502 msgb_free(conn->pending_msg);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200503 osmo_fd_unregister(&conn->ofd);
Daniel Willmanna0d93312011-09-15 12:56:58 +0200504 if (conn->closed_cb)
505 conn->closed_cb(conn);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200506 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200507}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200508
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200509void ipa_server_conn_send(struct ipa_server_conn *conn, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200510{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200511 msgb_enqueue(&conn->tx_queue, msg);
512 conn->ofd.when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200513}