blob: 554644c7505ff7078176a234f0ac4078eef14cbe [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);
Pau Espin Pedrol493c8e62018-08-28 16:46:39 +020059 if (ret <= 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020060 if (ret == -EAGAIN)
61 return;
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);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020069 return;
70 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020071 if (link->read_cb)
72 link->read_cb(link, msg);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020073}
74
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020075static void ipa_client_write(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020076{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020077 if (link->write_cb)
78 link->write_cb(link);
79}
80
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +020081static int ipa_client_write_default_cb(struct ipa_client_conn *link)
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020082{
83 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020084 struct msgb *msg;
85 struct llist_head *lh;
86 int ret;
87
Maxf4463672018-02-13 15:17:27 +010088 LOGIPA(link, LOGL_DEBUG, "sending data\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020089
90 if (llist_empty(&link->tx_queue)) {
91 ofd->when &= ~BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020092 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020093 }
94 lh = link->tx_queue.next;
95 llist_del(lh);
96 msg = llist_entry(lh, struct msgb, list);
97
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020098 ret = send(link->ofd->fd, msg->data, msg->len, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020099 if (ret < 0) {
100 if (errno == EPIPE || errno == ENOTCONN) {
Harald Welte51de9ca2013-06-30 20:13:16 +0200101 ipa_client_conn_close(link);
102 if (link->updown_cb)
103 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200104 }
Maxf4463672018-02-13 15:17:27 +0100105 LOGIPA(link, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200106 }
107 msgb_free(msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200108 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200109}
110
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200111static int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200112{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200113 struct ipa_client_conn *link = ofd->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200114 int error, ret;
Harald Welte4301c372011-08-19 13:33:16 +0200115 socklen_t len = sizeof(error);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200116
117 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200118 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200119 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
120 if (ret >= 0 && error > 0) {
Harald Welte51de9ca2013-06-30 20:13:16 +0200121 ipa_client_conn_close(link);
122 if (link->updown_cb)
123 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200124 return 0;
125 }
126 ofd->when &= ~BSC_FD_WRITE;
Maxf4463672018-02-13 15:17:27 +0100127 LOGIPA(link, LOGL_NOTICE, "connection done\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200128 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Harald Welte51de9ca2013-06-30 20:13:16 +0200129 if (link->updown_cb)
130 link->updown_cb(link, 1);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200131 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200132 case IPA_CLIENT_LINK_STATE_CONNECTED:
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200133 if (what & BSC_FD_READ) {
Maxf4463672018-02-13 15:17:27 +0100134 LOGIPA(link, LOGL_DEBUG, "connected read\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200135 ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200136 }
137 if (what & BSC_FD_WRITE) {
Maxf4463672018-02-13 15:17:27 +0100138 LOGIPA(link, LOGL_DEBUG, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200139 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200140 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200141 break;
142 default:
143 break;
144 }
145 return 0;
146}
147
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200148struct ipa_client_conn *
149ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200150 int priv_nr, const char *addr, uint16_t port,
Harald Welte51de9ca2013-06-30 20:13:16 +0200151 void (*updown_cb)(struct ipa_client_conn *link, int up),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200152 int (*read_cb)(struct ipa_client_conn *link,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200153 struct msgb *msgb),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200154 int (*write_cb)(struct ipa_client_conn *link),
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200155 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200156{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200157 struct ipa_client_conn *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200158
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200159 ipa_link = talloc_zero(ctx, struct ipa_client_conn);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200160 if (!ipa_link)
161 return NULL;
162
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200163 if (ts) {
Pablo Neira Ayuso00af7722011-09-08 12:47:06 +0200164 if (ts->line->driver == NULL) {
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200165 talloc_free(ipa_link);
166 return NULL;
167 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200168 ipa_link->ofd = &ts->driver.ipaccess.fd;
169 } else {
170 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
171 if (ipa_link->ofd == NULL) {
172 talloc_free(ipa_link);
173 return NULL;
174 }
175 }
176
177 ipa_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
178 ipa_link->ofd->priv_nr = priv_nr;
179 ipa_link->ofd->cb = ipa_client_fd_cb;
180 ipa_link->ofd->data = ipa_link;
Harald Welte51de9ca2013-06-30 20:13:16 +0200181 ipa_link->ofd->fd = -1;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200182 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayusoc00ee732011-06-21 12:22:49 +0200183 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200184 ipa_link->port = port;
Harald Welte51de9ca2013-06-30 20:13:16 +0200185 ipa_link->updown_cb = updown_cb;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200186 ipa_link->read_cb = read_cb;
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200187 /* default to generic write callback if not set. */
188 if (write_cb == NULL)
189 ipa_link->write_cb = ipa_client_write_default_cb;
Pablo Neira Ayuso81ed7592012-08-22 16:35:17 +0200190 else
191 ipa_link->write_cb = write_cb;
192
Pablo Neira Ayuso2220a052011-09-08 18:43:31 +0200193 if (ts)
194 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200195 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200196 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200197
198 return ipa_link;
199}
200
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200201void ipa_client_conn_destroy(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200202{
203 talloc_free(link);
204}
205
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200206int ipa_client_conn_open(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200207{
208 int ret;
209
Harald Weltee7e1b752014-08-17 21:41:34 +0200210 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200211 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200212 link->addr, link->port,
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200213 OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
Harald Welte14dd30a2016-11-26 09:37:09 +0100214 if (ret < 0)
215 return ret;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200216 link->ofd->fd = ret;
Holger Hans Peter Freyther687046b2014-12-12 17:39:58 +0100217 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200218 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200219 close(ret);
Harald Welte51de9ca2013-06-30 20:13:16 +0200220 link->ofd->fd = -1;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200221 return -EIO;
222 }
Harald Welte51de9ca2013-06-30 20:13:16 +0200223
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200224 return 0;
225}
226
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200227void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200228{
229 msgb_enqueue(&link->tx_queue, msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200230 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200231}
232
Holger Hans Peter Freyther90878592015-01-18 17:50:05 +0100233size_t ipa_client_conn_clear_queue(struct ipa_client_conn *link)
234{
235 size_t deleted = 0;
236
237 while (!llist_empty(&link->tx_queue)) {
238 struct msgb *msg = msgb_dequeue(&link->tx_queue);
239 msgb_free(msg);
240 deleted += 1;
241 }
242
243 link->ofd->when &= ~BSC_FD_WRITE;
244 return deleted;
245}
246
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200247static int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200248{
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200249 int fd, ret;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200250 struct sockaddr_in sa;
251 socklen_t sa_len = sizeof(sa);
252 struct ipa_server_link *link = ofd->data;
253
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200254 fd = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
255 if (fd < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200256 LOGP(DLINP, LOGL_ERROR, "failed to accept from origin "
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200257 "peer, reason=`%s'\n", strerror(errno));
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200258 return fd;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200259 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200260 LOGP(DLINP, LOGL_NOTICE, "accept()ed new link from %s to port %u\n",
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200261 inet_ntoa(sa.sin_addr), link->port);
262
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200263 ret = link->accept_cb(link, fd);
264 if (ret < 0) {
265 LOGP(DLINP, LOGL_ERROR,
266 "failed to processs accept()ed new link, "
267 "reason=`%s'\n", strerror(-ret));
268 close(fd);
269 return ret;
270 }
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200271
272 return 0;
273}
274
275struct ipa_server_link *
276ipa_server_link_create(void *ctx, struct e1inp_line *line,
277 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200278 int (*accept_cb)(struct ipa_server_link *link, int fd),
279 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200280{
281 struct ipa_server_link *ipa_link;
282
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200283 OSMO_ASSERT(accept_cb != NULL);
284
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200285 ipa_link = talloc_zero(ctx, struct ipa_server_link);
286 if (!ipa_link)
287 return NULL;
288
289 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
290 ipa_link->ofd.cb = ipa_server_fd_cb;
291 ipa_link->ofd.data = ipa_link;
292 ipa_link->addr = talloc_strdup(ipa_link, addr);
293 ipa_link->port = port;
294 ipa_link->accept_cb = accept_cb;
295 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200296 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200297
298 return ipa_link;
299
300}
301
302void ipa_server_link_destroy(struct ipa_server_link *link)
303{
304 talloc_free(link);
305}
306
307int ipa_server_link_open(struct ipa_server_link *link)
308{
309 int ret;
310
311 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
312 link->addr, link->port, OSMO_SOCK_F_BIND);
313 if (ret < 0)
314 return ret;
315
316 link->ofd.fd = ret;
317 if (osmo_fd_register(&link->ofd) < 0) {
318 close(ret);
319 return -EIO;
320 }
321 return 0;
322}
323
324void ipa_server_link_close(struct ipa_server_link *link)
325{
326 osmo_fd_unregister(&link->ofd);
327 close(link->ofd.fd);
328}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200329
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200330static void ipa_server_conn_read(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200331{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200332 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200333 struct msgb *msg;
334 int ret;
335
Maxf4463672018-02-13 15:17:27 +0100336 LOGIPA(conn, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200337
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200338 ret = ipa_msg_recv_buffered(ofd->fd, &msg, &conn->pending_msg);
Pau Espin Pedrol3750dea2018-08-28 17:49:29 +0200339 if (ret <= 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200340 if (ret == -EAGAIN)
341 return;
Pau Espin Pedrol3750dea2018-08-28 17:49:29 +0200342 else if (ret == -EPIPE || ret == -ECONNRESET)
Maxf4463672018-02-13 15:17:27 +0100343 LOGIPA(conn, LOGL_ERROR, "lost connection with server\n");
Pau Espin Pedrol3750dea2018-08-28 17:49:29 +0200344 else if (ret == 0)
345 LOGIPA(conn, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200346 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200347 return;
348 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200349 if (conn->cb)
350 conn->cb(conn, msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200351
352 return;
353}
354
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200355static void ipa_server_conn_write(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200356{
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200357 struct msgb *msg;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200358 int ret;
359
Maxf4463672018-02-13 15:17:27 +0100360 LOGIPA(conn, LOGL_DEBUG, "sending data\n");
Neels Hofmeyr01543a12017-09-14 04:32:19 +0200361 msg = msgb_dequeue(&conn->tx_queue);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200362
Neels Hofmeyr01543a12017-09-14 04:32:19 +0200363 if (!msg) {
364 conn->ofd.when &= ~BSC_FD_WRITE;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200365 return;
366 }
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200367
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200368 ret = send(conn->ofd.fd, msg->data, msg->len, 0);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200369 if (ret < 0) {
Maxf4463672018-02-13 15:17:27 +0100370 LOGIPA(conn, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200371 }
372 msgb_free(msg);
373}
374
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200375static int ipa_server_conn_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200376{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200377 struct ipa_server_conn *conn = ofd->data;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200378
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200379 LOGP(DLINP, LOGL_DEBUG, "connected read/write\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200380 if (what & BSC_FD_READ)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200381 ipa_server_conn_read(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200382 if (what & BSC_FD_WRITE)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200383 ipa_server_conn_write(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200384
385 return 0;
386}
387
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200388struct ipa_server_conn *
389ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd,
390 int (*cb)(struct ipa_server_conn *conn, struct msgb *msg),
Daniel Willmanna0d93312011-09-15 12:56:58 +0200391 int (*closed_cb)(struct ipa_server_conn *conn), void *data)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200392{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200393 struct ipa_server_conn *conn;
Harald Welteb2d727a2016-04-28 07:53:49 +0200394 struct sockaddr_in sa;
395 socklen_t sa_len = sizeof(sa);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200396
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200397 conn = talloc_zero(ctx, struct ipa_server_conn);
398 if (conn == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200399 LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in server, "
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200400 "reason=`%s'\n", strerror(errno));
401 return NULL;
402 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200403 conn->server = link;
404 conn->ofd.fd = fd;
405 conn->ofd.data = conn;
406 conn->ofd.cb = ipa_server_conn_cb;
407 conn->ofd.when = BSC_FD_READ;
408 conn->cb = cb;
Daniel Willmanna0d93312011-09-15 12:56:58 +0200409 conn->closed_cb = closed_cb;
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200410 conn->data = data;
411 INIT_LLIST_HEAD(&conn->tx_queue);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200412
Harald Welteb2d727a2016-04-28 07:53:49 +0200413 if (!getpeername(fd, (struct sockaddr *)&sa, &sa_len)) {
414 char *str = inet_ntoa(sa.sin_addr);
415 conn->addr = talloc_strdup(conn, str);
416 conn->port = ntohs(sa.sin_port);
417 }
418
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200419 if (osmo_fd_register(&conn->ofd) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200420 LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200421 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200422 return NULL;
423 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200424 return conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200425}
426
Harald Welte12814b92016-04-28 07:54:31 +0200427int ipa_server_conn_ccm(struct ipa_server_conn *conn, struct msgb *msg)
428{
429 struct tlv_parsed tlvp;
430 uint8_t msg_type = *(msg->l2h);
431 struct ipaccess_unit unit_data = {};
432 char *unitid;
433 int len, rc;
434
435 /* shared CCM handling on both server and client */
436 rc = ipa_ccm_rcvmsg_base(msg, &conn->ofd);
437 switch (rc) {
438 case -1:
439 /* error in IPA CCM processing */
440 goto err;
441 case 1:
442 /* IPA CCM message that was handled in _base */
443 return 0;
444 case 0:
445 /* IPA CCM message that we need to handle */
446 break;
447 default:
448 /* Error */
Maxf4463672018-02-13 15:17:27 +0100449 LOGIPA(conn, LOGL_ERROR, "Unexpected return from "
Harald Welte12814b92016-04-28 07:54:31 +0200450 "ipa_ccm_rcvmsg_base: %d\n", rc);
451 goto err;
452 }
453
454 switch (msg_type) {
455 case IPAC_MSGT_ID_RESP:
Harald Welte82eb55e2018-08-01 13:22:55 +0200456 rc = ipa_ccm_id_resp_parse(&tlvp, (const uint8_t *)msg->l2h+1, msgb_l2len(msg)-1);
Harald Welte12814b92016-04-28 07:54:31 +0200457 if (rc < 0) {
Maxf4463672018-02-13 15:17:27 +0100458 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESPonse with "
Harald Welte12814b92016-04-28 07:54:31 +0200459 "malformed TLVs\n");
460 goto err;
461 }
462 if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
Maxf4463672018-02-13 15:17:27 +0100463 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP without "
Harald Welte12814b92016-04-28 07:54:31 +0200464 "unit ID\n");
465 goto err;
466 }
467 len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT);
468 if (len < 1) {
Maxf4463672018-02-13 15:17:27 +0100469 LOGIPA(conn, LOGL_ERROR, "IPA CCM RESP with short"
Harald Welte12814b92016-04-28 07:54:31 +0200470 "unit ID\n");
471 goto err;
472 }
473 unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT);
474 unitid[len-1] = '\0';
475 ipa_parse_unitid(unitid, &unit_data);
476
477 /* FIXME */
478 rc = conn->ccm_cb(conn, msg, &tlvp, &unit_data);
479 if (rc < 0)
480 goto err;
481 break;
482 default:
Maxf4463672018-02-13 15:17:27 +0100483 LOGIPA(conn, LOGL_ERROR, "Unknown IPA message type\n");
Harald Welte12814b92016-04-28 07:54:31 +0200484 break;
485 }
486 return 0;
487err:
488 /* in case of any error, we close the connection */
489 ipa_server_conn_destroy(conn);
490 return -1;
491}
492
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200493void ipa_server_conn_destroy(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200494{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200495 close(conn->ofd.fd);
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200496 msgb_free(conn->pending_msg);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200497 osmo_fd_unregister(&conn->ofd);
Daniel Willmanna0d93312011-09-15 12:56:58 +0200498 if (conn->closed_cb)
499 conn->closed_cb(conn);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200500 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200501}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200502
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200503void ipa_server_conn_send(struct ipa_server_conn *conn, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200504{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200505 msgb_enqueue(&conn->tx_queue, msg);
506 conn->ofd.when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200507}