blob: fbed038cbc63d65f22f9cf68b624b864099031c0 [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
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +020026void ipa_msg_push_header(struct msgb *msg, uint8_t proto)
27{
28 struct ipaccess_head *hh;
29
30 msg->l2h = msg->data;
31 hh = (struct ipaccess_head *) msgb_push(msg, sizeof(*hh));
32 hh->proto = proto;
33 hh->len = htons(msgb_l2len(msg));
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020034}
35
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020036void ipa_client_conn_close(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020037{
Harald Weltee68055b2013-06-30 14:21:54 +020038 /* be safe against multiple calls */
39 if (link->ofd->fd != -1) {
40 osmo_fd_unregister(link->ofd);
41 close(link->ofd->fd);
42 link->ofd->fd = -1;
43 }
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020044 msgb_free(link->pending_msg);
45 link->pending_msg = NULL;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020046}
47
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020048static void ipa_client_read(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020049{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020050 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020051 struct msgb *msg;
52 int ret;
53
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +020054 LOGP(DLINP, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020055
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020056 ret = ipa_msg_recv_buffered(ofd->fd, &msg, &link->pending_msg);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020057 if (ret < 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +020058 if (ret == -EAGAIN)
59 return;
60 if (ret == -EPIPE || ret == -ECONNRESET)
Harald Weltecc2241b2011-07-19 16:06:06 +020061 LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
Harald Welte51de9ca2013-06-30 20:13:16 +020062 ipa_client_conn_close(link);
63 if (link->updown_cb)
64 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020065 return;
66 } else if (ret == 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +020067 LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
Harald Welte51de9ca2013-06-30 20:13:16 +020068 ipa_client_conn_close(link);
69 if (link->updown_cb)
70 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020071 return;
72 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020073 if (link->read_cb)
74 link->read_cb(link, msg);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020075}
76
Pablo Neira Ayusof0995672011-09-08 12:58:38 +020077static void ipa_client_write(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020078{
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020079 if (link->write_cb)
80 link->write_cb(link);
81}
82
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +020083static int ipa_client_write_default_cb(struct ipa_client_conn *link)
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020084{
85 struct osmo_fd *ofd = link->ofd;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020086 struct msgb *msg;
87 struct llist_head *lh;
88 int ret;
89
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +020090 LOGP(DLINP, LOGL_DEBUG, "sending data\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020091
92 if (llist_empty(&link->tx_queue)) {
93 ofd->when &= ~BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +020094 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +020095 }
96 lh = link->tx_queue.next;
97 llist_del(lh);
98 msg = llist_entry(lh, struct msgb, list);
99
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200100 ret = send(link->ofd->fd, msg->data, msg->len, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200101 if (ret < 0) {
102 if (errno == EPIPE || errno == ENOTCONN) {
Harald Welte51de9ca2013-06-30 20:13:16 +0200103 ipa_client_conn_close(link);
104 if (link->updown_cb)
105 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200106 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200107 LOGP(DLINP, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200108 }
109 msgb_free(msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200110 return 0;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200111}
112
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200113static int ipa_client_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200114{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200115 struct ipa_client_conn *link = ofd->data;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200116 int error, ret;
Harald Welte4301c372011-08-19 13:33:16 +0200117 socklen_t len = sizeof(error);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200118
119 switch(link->state) {
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200120 case IPA_CLIENT_LINK_STATE_CONNECTING:
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200121 ret = getsockopt(ofd->fd, SOL_SOCKET, SO_ERROR, &error, &len);
122 if (ret >= 0 && error > 0) {
Harald Welte51de9ca2013-06-30 20:13:16 +0200123 ipa_client_conn_close(link);
124 if (link->updown_cb)
125 link->updown_cb(link, 0);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200126 return 0;
127 }
128 ofd->when &= ~BSC_FD_WRITE;
Harald Weltecc2241b2011-07-19 16:06:06 +0200129 LOGP(DLINP, LOGL_NOTICE, "connection done.\n");
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200130 link->state = IPA_CLIENT_LINK_STATE_CONNECTED;
Harald Welte51de9ca2013-06-30 20:13:16 +0200131 if (link->updown_cb)
132 link->updown_cb(link, 1);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200133 break;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200134 case IPA_CLIENT_LINK_STATE_CONNECTED:
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200135 if (what & BSC_FD_READ) {
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200136 LOGP(DLINP, LOGL_DEBUG, "connected read\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200137 ipa_client_read(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200138 }
139 if (what & BSC_FD_WRITE) {
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200140 LOGP(DLINP, LOGL_DEBUG, "connected write\n");
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200141 ipa_client_write(link);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200142 }
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200143 break;
144 default:
145 break;
146 }
147 return 0;
148}
149
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200150struct ipa_client_conn *
151ipa_client_conn_create(void *ctx, struct e1inp_ts *ts,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200152 int priv_nr, const char *addr, uint16_t port,
Harald Welte51de9ca2013-06-30 20:13:16 +0200153 void (*updown_cb)(struct ipa_client_conn *link, int up),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200154 int (*read_cb)(struct ipa_client_conn *link,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200155 struct msgb *msgb),
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200156 int (*write_cb)(struct ipa_client_conn *link),
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200157 void *data)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200158{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200159 struct ipa_client_conn *ipa_link;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200160
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200161 ipa_link = talloc_zero(ctx, struct ipa_client_conn);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200162 if (!ipa_link)
163 return NULL;
164
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200165 if (ts) {
Pablo Neira Ayuso00af7722011-09-08 12:47:06 +0200166 if (ts->line->driver == NULL) {
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200167 talloc_free(ipa_link);
168 return NULL;
169 }
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200170 ipa_link->ofd = &ts->driver.ipaccess.fd;
171 } else {
172 ipa_link->ofd = talloc_zero(ctx, struct osmo_fd);
173 if (ipa_link->ofd == NULL) {
174 talloc_free(ipa_link);
175 return NULL;
176 }
177 }
178
179 ipa_link->ofd->when |= BSC_FD_READ | BSC_FD_WRITE;
180 ipa_link->ofd->priv_nr = priv_nr;
181 ipa_link->ofd->cb = ipa_client_fd_cb;
182 ipa_link->ofd->data = ipa_link;
Harald Welte51de9ca2013-06-30 20:13:16 +0200183 ipa_link->ofd->fd = -1;
Pablo Neira Ayusoc07a8e72011-06-21 19:50:04 +0200184 ipa_link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayusoc00ee732011-06-21 12:22:49 +0200185 ipa_link->addr = talloc_strdup(ipa_link, addr);
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200186 ipa_link->port = port;
Harald Welte51de9ca2013-06-30 20:13:16 +0200187 ipa_link->updown_cb = updown_cb;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200188 ipa_link->read_cb = read_cb;
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200189 /* default to generic write callback if not set. */
190 if (write_cb == NULL)
191 ipa_link->write_cb = ipa_client_write_default_cb;
Pablo Neira Ayuso81ed7592012-08-22 16:35:17 +0200192 else
193 ipa_link->write_cb = write_cb;
194
Pablo Neira Ayuso2220a052011-09-08 18:43:31 +0200195 if (ts)
196 ipa_link->line = ts->line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200197 ipa_link->data = data;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200198 INIT_LLIST_HEAD(&ipa_link->tx_queue);
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200199
200 return ipa_link;
201}
202
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200203void ipa_client_conn_destroy(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200204{
205 talloc_free(link);
206}
207
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200208int ipa_client_conn_open(struct ipa_client_conn *link)
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200209{
210 int ret;
211
Harald Weltee7e1b752014-08-17 21:41:34 +0200212 link->state = IPA_CLIENT_LINK_STATE_CONNECTING;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200213 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
Pablo Neira Ayuso9b3a33c2011-06-21 13:52:41 +0200214 link->addr, link->port,
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200215 OSMO_SOCK_F_CONNECT|OSMO_SOCK_F_NONBLOCK);
Harald Welte14dd30a2016-11-26 09:37:09 +0100216 if (ret < 0)
217 return ret;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200218 link->ofd->fd = ret;
Holger Hans Peter Freyther687046b2014-12-12 17:39:58 +0100219 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200220 if (osmo_fd_register(link->ofd) < 0) {
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200221 close(ret);
Harald Welte51de9ca2013-06-30 20:13:16 +0200222 link->ofd->fd = -1;
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200223 return -EIO;
224 }
Harald Welte51de9ca2013-06-30 20:13:16 +0200225
Pablo Neira Ayuso96e81282011-06-09 15:06:11 +0200226 return 0;
227}
228
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200229void ipa_client_conn_send(struct ipa_client_conn *link, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200230{
231 msgb_enqueue(&link->tx_queue, msg);
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200232 link->ofd->when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200233}
234
Holger Hans Peter Freyther90878592015-01-18 17:50:05 +0100235size_t ipa_client_conn_clear_queue(struct ipa_client_conn *link)
236{
237 size_t deleted = 0;
238
239 while (!llist_empty(&link->tx_queue)) {
240 struct msgb *msg = msgb_dequeue(&link->tx_queue);
241 msgb_free(msg);
242 deleted += 1;
243 }
244
245 link->ofd->when &= ~BSC_FD_WRITE;
246 return deleted;
247}
248
Harald Welte7b6fc2e2011-08-19 21:58:48 +0200249static int ipa_server_fd_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200250{
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200251 int fd, ret;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200252 struct sockaddr_in sa;
253 socklen_t sa_len = sizeof(sa);
254 struct ipa_server_link *link = ofd->data;
255
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200256 fd = accept(ofd->fd, (struct sockaddr *)&sa, &sa_len);
257 if (fd < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200258 LOGP(DLINP, LOGL_ERROR, "failed to accept from origin "
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200259 "peer, reason=`%s'\n", strerror(errno));
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200260 return fd;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200261 }
Harald Weltecc2241b2011-07-19 16:06:06 +0200262 LOGP(DLINP, LOGL_NOTICE, "accept()ed new link from %s to port %u\n",
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200263 inet_ntoa(sa.sin_addr), link->port);
264
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200265 ret = link->accept_cb(link, fd);
266 if (ret < 0) {
267 LOGP(DLINP, LOGL_ERROR,
268 "failed to processs accept()ed new link, "
269 "reason=`%s'\n", strerror(-ret));
270 close(fd);
271 return ret;
272 }
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200273
274 return 0;
275}
276
277struct ipa_server_link *
278ipa_server_link_create(void *ctx, struct e1inp_line *line,
279 const char *addr, uint16_t port,
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200280 int (*accept_cb)(struct ipa_server_link *link, int fd),
281 void *data)
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200282{
283 struct ipa_server_link *ipa_link;
284
Pablo Neira Ayusocdda0a82013-07-08 01:13:19 +0200285 OSMO_ASSERT(accept_cb != NULL);
286
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200287 ipa_link = talloc_zero(ctx, struct ipa_server_link);
288 if (!ipa_link)
289 return NULL;
290
291 ipa_link->ofd.when |= BSC_FD_READ | BSC_FD_WRITE;
292 ipa_link->ofd.cb = ipa_server_fd_cb;
293 ipa_link->ofd.data = ipa_link;
294 ipa_link->addr = talloc_strdup(ipa_link, addr);
295 ipa_link->port = port;
296 ipa_link->accept_cb = accept_cb;
297 ipa_link->line = line;
Pablo Neira Ayusoe009f4a2011-06-23 13:36:34 +0200298 ipa_link->data = data;
Pablo Neira Ayuso986191f2011-06-21 19:56:26 +0200299
300 return ipa_link;
301
302}
303
304void ipa_server_link_destroy(struct ipa_server_link *link)
305{
306 talloc_free(link);
307}
308
309int ipa_server_link_open(struct ipa_server_link *link)
310{
311 int ret;
312
313 ret = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
314 link->addr, link->port, OSMO_SOCK_F_BIND);
315 if (ret < 0)
316 return ret;
317
318 link->ofd.fd = ret;
319 if (osmo_fd_register(&link->ofd) < 0) {
320 close(ret);
321 return -EIO;
322 }
323 return 0;
324}
325
326void ipa_server_link_close(struct ipa_server_link *link)
327{
328 osmo_fd_unregister(&link->ofd);
329 close(link->ofd.fd);
330}
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200331
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200332static void ipa_server_conn_read(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200333{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200334 struct osmo_fd *ofd = &conn->ofd;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200335 struct msgb *msg;
336 int ret;
337
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200338 LOGP(DLINP, LOGL_DEBUG, "message received\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200339
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200340 ret = ipa_msg_recv_buffered(ofd->fd, &msg, &conn->pending_msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200341 if (ret < 0) {
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200342 if (ret == -EAGAIN)
343 return;
344 if (ret == -EPIPE || ret == -ECONNRESET)
Harald Weltecc2241b2011-07-19 16:06:06 +0200345 LOGP(DLINP, LOGL_ERROR, "lost connection with server\n");
Daniel Willmanndc4479f2011-09-15 12:56:57 +0200346 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200347 return;
348 } else if (ret == 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200349 LOGP(DLINP, LOGL_ERROR, "connection closed with server\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200350 ipa_server_conn_destroy(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200351 return;
352 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200353 if (conn->cb)
354 conn->cb(conn, msg);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200355
356 return;
357}
358
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200359static void ipa_server_conn_write(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200360{
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200361 struct msgb *msg;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200362 int ret;
363
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200364 LOGP(DLINP, LOGL_DEBUG, "sending data\n");
Neels Hofmeyr01543a12017-09-14 04:32:19 +0200365 msg = msgb_dequeue(&conn->tx_queue);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200366
Neels Hofmeyr01543a12017-09-14 04:32:19 +0200367 if (!msg) {
368 conn->ofd.when &= ~BSC_FD_WRITE;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200369 return;
370 }
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200371
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200372 ret = send(conn->ofd.fd, msg->data, msg->len, 0);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200373 if (ret < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200374 LOGP(DLINP, LOGL_ERROR, "error to send\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200375 }
376 msgb_free(msg);
377}
378
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200379static int ipa_server_conn_cb(struct osmo_fd *ofd, unsigned int what)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200380{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200381 struct ipa_server_conn *conn = ofd->data;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200382
Pablo Neira Ayuso218bb8f2011-09-09 01:04:46 +0200383 LOGP(DLINP, LOGL_DEBUG, "connected read/write\n");
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200384 if (what & BSC_FD_READ)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200385 ipa_server_conn_read(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200386 if (what & BSC_FD_WRITE)
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200387 ipa_server_conn_write(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200388
389 return 0;
390}
391
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200392struct ipa_server_conn *
393ipa_server_conn_create(void *ctx, struct ipa_server_link *link, int fd,
394 int (*cb)(struct ipa_server_conn *conn, struct msgb *msg),
Daniel Willmanna0d93312011-09-15 12:56:58 +0200395 int (*closed_cb)(struct ipa_server_conn *conn), void *data)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200396{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200397 struct ipa_server_conn *conn;
Harald Welteb2d727a2016-04-28 07:53:49 +0200398 struct sockaddr_in sa;
399 socklen_t sa_len = sizeof(sa);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200400
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200401 conn = talloc_zero(ctx, struct ipa_server_conn);
402 if (conn == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200403 LOGP(DLINP, LOGL_ERROR, "cannot allocate new peer in server, "
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200404 "reason=`%s'\n", strerror(errno));
405 return NULL;
406 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200407 conn->server = link;
408 conn->ofd.fd = fd;
409 conn->ofd.data = conn;
410 conn->ofd.cb = ipa_server_conn_cb;
411 conn->ofd.when = BSC_FD_READ;
412 conn->cb = cb;
Daniel Willmanna0d93312011-09-15 12:56:58 +0200413 conn->closed_cb = closed_cb;
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200414 conn->data = data;
415 INIT_LLIST_HEAD(&conn->tx_queue);
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200416
Harald Welteb2d727a2016-04-28 07:53:49 +0200417 if (!getpeername(fd, (struct sockaddr *)&sa, &sa_len)) {
418 char *str = inet_ntoa(sa.sin_addr);
419 conn->addr = talloc_strdup(conn, str);
420 conn->port = ntohs(sa.sin_port);
421 }
422
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200423 if (osmo_fd_register(&conn->ofd) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200424 LOGP(DLINP, LOGL_ERROR, "could not register FD\n");
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200425 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200426 return NULL;
427 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200428 return conn;
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200429}
430
Harald Welte12814b92016-04-28 07:54:31 +0200431int ipa_server_conn_ccm(struct ipa_server_conn *conn, struct msgb *msg)
432{
433 struct tlv_parsed tlvp;
434 uint8_t msg_type = *(msg->l2h);
435 struct ipaccess_unit unit_data = {};
436 char *unitid;
437 int len, rc;
438
439 /* shared CCM handling on both server and client */
440 rc = ipa_ccm_rcvmsg_base(msg, &conn->ofd);
441 switch (rc) {
442 case -1:
443 /* error in IPA CCM processing */
444 goto err;
445 case 1:
446 /* IPA CCM message that was handled in _base */
447 return 0;
448 case 0:
449 /* IPA CCM message that we need to handle */
450 break;
451 default:
452 /* Error */
453 LOGP(DLINP, LOGL_ERROR, "Unexpected return from "
454 "ipa_ccm_rcvmsg_base: %d\n", rc);
455 goto err;
456 }
457
458 switch (msg_type) {
459 case IPAC_MSGT_ID_RESP:
460 rc = ipa_ccm_idtag_parse(&tlvp, (uint8_t *)msg->l2h + 2,
461 msgb_l2len(msg)-2);
462 if (rc < 0) {
463 LOGP(DLINP, LOGL_ERROR, "IPA CCM RESPonse with "
464 "malformed TLVs\n");
465 goto err;
466 }
467 if (!TLVP_PRESENT(&tlvp, IPAC_IDTAG_UNIT)) {
468 LOGP(DLINP, LOGL_ERROR, "IPA CCM RESP without "
469 "unit ID\n");
470 goto err;
471 }
472 len = TLVP_LEN(&tlvp, IPAC_IDTAG_UNIT);
473 if (len < 1) {
474 LOGP(DLINP, LOGL_ERROR, "IPA CCM RESP with short"
475 "unit ID\n");
476 goto err;
477 }
478 unitid = (char *) TLVP_VAL(&tlvp, IPAC_IDTAG_UNIT);
479 unitid[len-1] = '\0';
480 ipa_parse_unitid(unitid, &unit_data);
481
482 /* FIXME */
483 rc = conn->ccm_cb(conn, msg, &tlvp, &unit_data);
484 if (rc < 0)
485 goto err;
486 break;
487 default:
488 LOGP(DLINP, LOGL_ERROR, "Unknown IPA message type\n");
489 break;
490 }
491 return 0;
492err:
493 /* in case of any error, we close the connection */
494 ipa_server_conn_destroy(conn);
495 return -1;
496}
497
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200498void ipa_server_conn_destroy(struct ipa_server_conn *conn)
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200499{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200500 close(conn->ofd.fd);
Jacob Erlbeck98af3c32014-03-31 10:53:32 +0200501 msgb_free(conn->pending_msg);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200502 osmo_fd_unregister(&conn->ofd);
Daniel Willmanna0d93312011-09-15 12:56:58 +0200503 if (conn->closed_cb)
504 conn->closed_cb(conn);
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200505 talloc_free(conn);
Pablo Neira Ayuso6af9b612011-06-23 14:07:47 +0200506}
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200507
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200508void ipa_server_conn_send(struct ipa_server_conn *conn, struct msgb *msg)
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200509{
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200510 msgb_enqueue(&conn->tx_queue, msg);
511 conn->ofd.when |= BSC_FD_WRITE;
Pablo Neira Ayusoaf3fed92011-06-23 20:42:19 +0200512}