blob: 441dd3f4b68924c04ec30d26ee86ebe09e8abbf5 [file] [log] [blame]
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +02001#include "internal.h"
2
3#include <stdio.h>
4#include <stdbool.h>
5#include <unistd.h>
6#include <stdlib.h>
7#include <errno.h>
8#include <string.h>
9#include <time.h>
10#include <sys/fcntl.h>
11#include <sys/socket.h>
12#include <sys/ioctl.h>
13#include <arpa/inet.h>
14
15#include <osmocom/core/select.h>
16#include <osmocom/core/bitvec.h>
17#include <osmocom/gsm/tlv.h>
18#include <osmocom/core/msgb.h>
19#include <osmocom/core/logging.h>
Harald Welte71d87b22011-07-18 14:49:56 +020020#include <osmocom/core/talloc.h>
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +020021#include <osmocom/abis/e1_input.h>
22#include <osmocom/abis/ipaccess.h>
23#include <osmocom/core/socket.h>
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +020024
25#include <osmocom/abis/ipa.h>
26#include <osmocom/vty/vty.h>
27#include <osmocom/vty/command.h>
28
29static void *tall_ipa_proxy_ctx;
30
31/*
32 * data structures used by the IPA VTY commands
33 */
34static LLIST_HEAD(ipa_instance_list);
35
36enum ipa_proxy_instance_net_type {
37 IPA_INSTANCE_T_NONE,
38 IPA_INSTANCE_T_BIND,
39 IPA_INSTANCE_T_CONNECT,
40 IPA_INSTANCE_T_MAX
41};
42
43struct ipa_proxy_instance_net {
44 char *addr;
45 uint16_t port;
46 enum ipa_proxy_instance_net_type type;
47};
48
49struct ipa_proxy_instance {
50 struct llist_head head;
51#define IPA_INSTANCE_NAME 16
52 char name[IPA_INSTANCE_NAME];
53 struct ipa_proxy_instance_net net;
54 int refcnt;
55};
56
57static LLIST_HEAD(ipa_proxy_route_list);
58
59/* Several routes pointing to the same instances share this. */
60struct ipa_proxy_route_shared {
61 int refcnt;
62
63 /* this file descriptor is used to accept() new connections. */
64 struct osmo_fd bfd;
65
66 struct {
67 struct ipa_proxy_instance *inst;
68 struct bitvec streamid_map;
69 uint8_t streamid_map_data[(0xff+1)/8];
Holger Hans Peter Freythera677cbc2013-07-04 19:52:41 +020070 uint8_t streamid[0xff + 1];
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +020071 } src;
72 struct {
73 struct ipa_proxy_instance *inst;
74 struct bitvec streamid_map;
75 uint8_t streamid_map_data[(0xff+1)/8];
Holger Hans Peter Freythera677cbc2013-07-04 19:52:41 +020076 uint8_t streamid[0xff + 1];
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +020077 } dst;
78
79 struct llist_head conn_list;
80};
81
82/* One route is composed of two instances. */
83struct ipa_proxy_route {
84 struct llist_head head;
85
86 struct {
87 uint8_t streamid;
88 } src;
89 struct {
90 uint8_t streamid;
91 } dst;
92
93 struct ipa_proxy_route_shared *shared;
94};
95
96enum ipa_conn_state {
97 IPA_CONN_S_NONE,
98 IPA_CONN_S_CONNECTING,
99 IPA_CONN_S_CONNECTED,
100 IPA_CONN_S_MAX
101};
102
103/* One route may forward more than one connection. */
104struct ipa_proxy_conn {
105 struct llist_head head;
106
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200107 struct ipa_server_conn *src;
108 struct ipa_client_conn *dst;
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200109 struct ipa_proxy_route *route;
110};
111
112/*
113 * socket callbacks used by IPA VTY commands
114 */
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200115static int ipa_sock_dst_cb(struct ipa_client_conn *link, struct msgb *msg)
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200116{
117 struct ipaccess_head *hh;
118 struct ipa_proxy_conn *conn = link->data;
119
Harald Weltecc2241b2011-07-19 16:06:06 +0200120 LOGP(DLINP, LOGL_NOTICE, "received message from client side\n");
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200121
122 hh = (struct ipaccess_head *)msg->data;
123 /* check if we have a route for this message. */
124 if (bitvec_get_bit_pos(
125 &conn->route->shared->dst.streamid_map,
126 hh->proto) != ONE) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200127 LOGP(DLINP, LOGL_NOTICE, "we don't have a "
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200128 "route for streamid 0x%x\n", hh->proto);
129 msgb_free(msg);
130 return 0;
131 }
132 /* mangle message, if required. */
133 hh->proto = conn->route->shared->src.streamid[hh->proto];
134
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200135 ipa_server_conn_send(conn->src, msg);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200136 return 0;
137}
138
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200139static int ipa_sock_src_cb(struct ipa_server_conn *peer, struct msgb *msg)
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200140{
141 struct ipaccess_head *hh;
142 struct ipa_proxy_conn *conn = peer->data;
143
Harald Weltecc2241b2011-07-19 16:06:06 +0200144 LOGP(DLINP, LOGL_NOTICE, "received message from server side\n");
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200145
146 hh = (struct ipaccess_head *)msg->data;
147 /* check if we have a route for this message. */
148 if (bitvec_get_bit_pos(&conn->route->shared->src.streamid_map,
149 hh->proto) != ONE) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200150 LOGP(DLINP, LOGL_NOTICE, "we don't have a "
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200151 "route for streamid 0x%x\n", hh->proto);
152 msgb_free(msg);
153 return 0;
154 }
155 /* mangle message, if required. */
156 hh->proto = conn->route->shared->dst.streamid[hh->proto];
157
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200158 ipa_client_conn_send(conn->dst, msg);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200159 return 0;
160}
161
162static int
163ipa_sock_src_accept_cb(struct ipa_server_link *link, int fd)
164{
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200165 struct ipa_proxy_route *route = link->data;
166 struct ipa_proxy_conn *conn;
167
168 conn = talloc_zero(tall_ipa_proxy_ctx, struct ipa_proxy_conn);
169 if (conn == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200170 LOGP(DLINP, LOGL_ERROR, "cannot allocate memory for "
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200171 "origin IPA\n");
172 close(fd);
Holger Hans Peter Freyther3a5b4362013-07-04 20:05:50 +0200173 return -ENOMEM;
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200174 }
175 conn->route = route;
176
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200177 conn->src = ipa_server_conn_create(tall_ipa_proxy_ctx, link, fd,
Daniel Willmanna0d93312011-09-15 12:56:58 +0200178 ipa_sock_src_cb, NULL, conn);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200179 if (conn->src == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200180 LOGP(DLINP, LOGL_ERROR, "could not create server peer: %s\n",
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200181 strerror(errno));
182 return -ENOMEM;
183 }
184
Harald Weltecc2241b2011-07-19 16:06:06 +0200185 LOGP(DLINP, LOGL_NOTICE, "now trying to connect to destination\n");
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200186
Pau Espin Pedrolb6e28bf2019-11-08 17:30:28 +0100187 conn->dst = ipa_client_conn_create2(NULL, NULL, 0,
188 NULL, 0,
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200189 route->shared->dst.inst->net.addr,
190 route->shared->dst.inst->net.port,
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +0200191 NULL,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200192 ipa_sock_dst_cb,
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200193 NULL,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200194 conn);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200195 if (conn->dst == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200196 LOGP(DLINP, LOGL_ERROR, "could not create client: %s\n",
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200197 strerror(errno));
198 return -ENOMEM;
199 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200200 if (ipa_client_conn_open(conn->dst) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200201 LOGP(DLINP, LOGL_ERROR, "could not start client: %s\n",
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200202 strerror(errno));
203 return -ENOMEM;
204 }
205 llist_add(&conn->head, &route->shared->conn_list);
Holger Hans Peter Freyther3a5b4362013-07-04 20:05:50 +0200206 return 0;
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200207}
208
209/*
210 * VTY commands for IPA
211 */
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200212static int __ipa_instance_add(struct vty *vty, int argc, const char *argv[])
213{
214 struct ipa_proxy_instance *ipi;
215 enum ipa_proxy_instance_net_type type;
216 struct in_addr addr;
217 uint16_t port;
218
219 if (argc < 4)
220 return CMD_ERR_INCOMPLETE;
221
222 llist_for_each_entry(ipi, &ipa_instance_list, head) {
223 if (strncmp(ipi->name, argv[0], IPA_INSTANCE_NAME) != 0)
224 continue;
225
226 vty_out(vty, "%% instance `%s' already exists%s",
227 ipi->name, VTY_NEWLINE);
228 return CMD_WARNING;
229 }
230 if (strncmp(argv[1], "bind", IPA_INSTANCE_NAME) == 0)
231 type = IPA_INSTANCE_T_BIND;
232 else if (strncmp(argv[1], "connect", IPA_INSTANCE_NAME) == 0)
233 type = IPA_INSTANCE_T_CONNECT;
234 else
235 return CMD_ERR_INCOMPLETE;
236
237 if (inet_aton(argv[2], &addr) < 0) {
238 vty_out(vty, "%% invalid address %s%s", argv[1], VTY_NEWLINE);
239 return CMD_WARNING;
240 }
241 port = atoi(argv[3]);
242
243 ipi = talloc_zero(tall_ipa_proxy_ctx, struct ipa_proxy_instance);
244 if (ipi == NULL) {
245 vty_out(vty, "%% can't allocate memory for new instance%s",
246 VTY_NEWLINE);
247 return CMD_WARNING;
248 }
Neels Hofmeyr4c57eef2018-07-26 17:28:24 +0200249 osmo_strlcpy(ipi->name, argv[0], sizeof(ipi->name));
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200250 ipi->net.type = type;
251 ipi->net.addr = talloc_strdup(tall_ipa_proxy_ctx, argv[2]);
252 ipi->net.port = port;
253 llist_add_tail(&ipi->head, &ipa_instance_list);
254
255 return CMD_SUCCESS;
256}
257
258DEFUN(ipa_instance_add, ipa_instance_add_cmd,
259 "ipa instance NAME (bind|connect) IP tcp port PORT",
260 "Bind or connect instance to address and port")
261{
262 return __ipa_instance_add(vty, argc, argv);
263}
264
265DEFUN(ipa_instance_del, ipa_instance_del_cmd,
266 "no ipa instance NAME",
267 "Delete instance to address and port")
268{
269 struct ipa_proxy_instance *ipi;
270
271 if (argc < 1)
272 return CMD_ERR_INCOMPLETE;
273
274 llist_for_each_entry(ipi, &ipa_instance_list, head) {
275 if (strncmp(ipi->name, argv[0], IPA_INSTANCE_NAME) != 0)
276 continue;
277
278 if (ipi->refcnt > 0) {
279 vty_out(vty, "%% instance `%s' is in use%s",
280 ipi->name, VTY_NEWLINE);
281 return CMD_WARNING;
282 }
283 llist_del(&ipi->head);
284 talloc_free(ipi);
285 return CMD_SUCCESS;
286 }
287 vty_out(vty, "%% instance `%s' does not exist%s",
288 ipi->name, VTY_NEWLINE);
289
290 return CMD_WARNING;
291}
292
293DEFUN(ipa_instance_show, ipa_instance_show_cmd,
294 "ipa instance show", "Show existing ipaccess proxy instances")
295{
296 struct ipa_proxy_instance *this;
297
298 llist_for_each_entry(this, &ipa_instance_list, head) {
299 vty_out(vty, "instance %s %s %s tcp port %u%s",
300 this->name, this->net.addr,
301 this->net.type == IPA_INSTANCE_T_BIND ?
302 "bind" : "connect",
303 this->net.port, VTY_NEWLINE);
304 }
305 return CMD_SUCCESS;
306}
307
308static int __ipa_route_add(struct vty *vty, int argc, const char *argv[])
309{
310 struct ipa_proxy_instance *ipi = vty->index;
311 struct ipa_proxy_instance *src = NULL, *dst = NULL;
312 uint32_t src_streamid, dst_streamid;
313 struct ipa_proxy_route *route, *matching_route = NULL;
314 struct ipa_proxy_route_shared *shared = NULL;
315 int ret;
316
317 if (argc < 4)
318 return CMD_ERR_INCOMPLETE;
319
320 llist_for_each_entry(ipi, &ipa_instance_list, head) {
321 if (strncmp(ipi->name, argv[0], IPA_INSTANCE_NAME) == 0) {
322 src = ipi;
323 continue;
324 }
325 if (strncmp(ipi->name, argv[2], IPA_INSTANCE_NAME) == 0) {
326 dst = ipi;
327 continue;
328 }
329 }
330 if (src == NULL) {
331 vty_out(vty, "%% instance `%s' does not exists%s",
332 argv[0], VTY_NEWLINE);
333 return CMD_WARNING;
334 }
335 if (dst == NULL) {
336 vty_out(vty, "%% instance `%s' does not exists%s",
337 argv[2], VTY_NEWLINE);
338 return CMD_WARNING;
339 }
340 if (src->net.type != IPA_INSTANCE_T_BIND) {
341 vty_out(vty, "%% instance `%s' is not of bind type%s",
342 argv[0], VTY_NEWLINE);
343 return CMD_WARNING;
344 }
345 if (dst->net.type != IPA_INSTANCE_T_CONNECT) {
346 vty_out(vty, "%% instance `%s' is not of connect type%s",
347 argv[2], VTY_NEWLINE);
348 return CMD_WARNING;
349 }
350 src_streamid = strtoul(argv[1], NULL, 16);
351 if (src_streamid > 0xff) {
352 vty_out(vty, "%% source streamid must be "
353 ">= 0x00 and <= 0xff%s", VTY_NEWLINE);
354 return CMD_WARNING;
355 }
356 dst_streamid = strtoul(argv[3], NULL, 16);
357 if (dst_streamid > 0xff) {
358 vty_out(vty, "%% destination streamid must be "
359 ">= 0x00 and <= 0xff%s", VTY_NEWLINE);
360 return CMD_WARNING;
361 }
362 llist_for_each_entry(route, &ipa_proxy_route_list, head) {
363 if (route->shared->src.inst == src &&
364 route->shared->dst.inst == dst) {
365 if (route->src.streamid == src_streamid &&
366 route->dst.streamid == dst_streamid) {
367 vty_out(vty, "%% this route already exists%s",
368 VTY_NEWLINE);
369 return CMD_WARNING;
370 }
371 matching_route = route;
372 break;
373 }
374 }
375 /* new route for this configuration. */
376 route = talloc_zero(tall_ipa_proxy_ctx, struct ipa_proxy_route);
377 if (route == NULL) {
378 vty_out(vty, "%% can't allocate memory for new route%s",
379 VTY_NEWLINE);
380 return CMD_WARNING;
381 }
382 route->src.streamid = src_streamid;
383 route->dst.streamid = dst_streamid;
384
385 if (matching_route != NULL) {
386 /* there's already a master route for these configuration. */
387 if (matching_route->shared->src.inst != src) {
388 vty_out(vty, "%% route does not contain "
389 "source instance `%s'%s",
390 argv[0], VTY_NEWLINE);
391 return CMD_WARNING;
392 }
393 if (matching_route->shared->dst.inst != dst) {
394 vty_out(vty, "%% route does not contain "
395 "destination instance `%s'%s",
396 argv[2], VTY_NEWLINE);
397 return CMD_WARNING;
398 }
399 /* use already existing shared routing information. */
400 shared = matching_route->shared;
401 } else {
402 struct ipa_server_link *link;
403
404 /* this is a brand new route, allocate shared routing info. */
405 shared = talloc_zero(tall_ipa_proxy_ctx, struct ipa_proxy_route_shared);
406 if (shared == NULL) {
407 vty_out(vty, "%% can't allocate memory for "
408 "new route shared%s", VTY_NEWLINE);
409 return CMD_WARNING;
410 }
411 shared->src.streamid_map.data_len =
412 sizeof(shared->src.streamid_map_data);
413 shared->src.streamid_map.data =
414 shared->src.streamid_map_data;
415 shared->dst.streamid_map.data_len =
416 sizeof(shared->dst.streamid_map_data);
417 shared->dst.streamid_map.data =
418 shared->dst.streamid_map_data;
419
420 link = ipa_server_link_create(tall_ipa_proxy_ctx, NULL,
421 "0.0.0.0",
422 src->net.port,
423 ipa_sock_src_accept_cb, route);
424 if (link == NULL) {
425 vty_out(vty, "%% can't bind instance `%s' to port%s",
426 src->name, VTY_NEWLINE);
427 return CMD_WARNING;
428 }
429 if (ipa_server_link_open(link) < 0) {
430 vty_out(vty, "%% can't bind instance `%s' to port%s",
431 src->name, VTY_NEWLINE);
432 return CMD_WARNING;
433 }
434 INIT_LLIST_HEAD(&shared->conn_list);
435 }
436 route->shared = shared;
437 src->refcnt++;
438 route->shared->src.inst = src;
439 dst->refcnt++;
440 route->shared->dst.inst = dst;
441 shared->src.streamid[src_streamid] = dst_streamid;
442 shared->dst.streamid[dst_streamid] = src_streamid;
443 ret = bitvec_set_bit_pos(&shared->src.streamid_map, src_streamid, ONE);
444 if (ret < 0) {
445 vty_out(vty, "%% bad bitmask (?)%s", VTY_NEWLINE);
446 return CMD_WARNING;
447 }
448 ret = bitvec_set_bit_pos(&shared->dst.streamid_map, dst_streamid, ONE);
449 if (ret < 0) {
450 vty_out(vty, "%% bad bitmask (?)%s", VTY_NEWLINE);
451 return CMD_WARNING;
452 }
453 shared->refcnt++;
454
455 llist_add_tail(&route->head, &ipa_proxy_route_list);
456 return CMD_SUCCESS;
457}
458
459DEFUN(ipa_route_add, ipa_route_add_cmd,
460 "ipa route instance NAME streamid HEXNUM "
461 "instance NAME streamid HEXNUM", "Add IPA route")
462{
463 return __ipa_route_add(vty, argc, argv);
464}
465
466DEFUN(ipa_route_del, ipa_route_del_cmd,
467 "no ipa route instance NAME streamid HEXNUM "
468 "instance NAME streamid HEXNUM", "Delete IPA route")
469{
470 struct ipa_proxy_instance *ipi = vty->index;
471 struct ipa_proxy_instance *src = NULL, *dst = NULL;
472 uint32_t src_streamid, dst_streamid;
473 struct ipa_proxy_route *route, *matching_route = NULL;
474 struct ipa_proxy_conn *conn, *tmp;
475
476 if (argc < 4)
477 return CMD_ERR_INCOMPLETE;
478
479 llist_for_each_entry(ipi, &ipa_instance_list, head) {
480 if (strncmp(ipi->name, argv[0], IPA_INSTANCE_NAME) == 0) {
481 src = ipi;
482 continue;
483 }
484 if (strncmp(ipi->name, argv[2], IPA_INSTANCE_NAME) == 0) {
485 dst = ipi;
486 continue;
487 }
488 }
489 if (src == NULL) {
490 vty_out(vty, "%% instance `%s' does not exists%s",
491 argv[0], VTY_NEWLINE);
492 return CMD_WARNING;
493 }
494 if (dst == NULL) {
495 vty_out(vty, "%% instance `%s' does not exists%s",
496 argv[2], VTY_NEWLINE);
497 return CMD_WARNING;
498 }
499 if (src->net.type != IPA_INSTANCE_T_BIND) {
500 vty_out(vty, "%% instance `%s' is not of bind type%s",
501 argv[0], VTY_NEWLINE);
502 return CMD_WARNING;
503 }
504 if (dst->net.type != IPA_INSTANCE_T_CONNECT) {
505 vty_out(vty, "%% instance `%s' is not of connect type%s",
506 argv[2], VTY_NEWLINE);
507 return CMD_WARNING;
508 }
509 src_streamid = strtoul(argv[1], NULL, 16);
510 if (src_streamid > 0xff) {
511 vty_out(vty, "%% source streamid must be "
512 ">= 0x00 and <= 0xff%s", VTY_NEWLINE);
513 return CMD_WARNING;
514 }
515 dst_streamid = strtoul(argv[3], NULL, 16);
516 if (dst_streamid > 0xff) {
517 vty_out(vty, "%% destination streamid must be "
518 ">= 0x00 and <= 0xff%s", VTY_NEWLINE);
519 return CMD_WARNING;
520 }
521 llist_for_each_entry(route, &ipa_proxy_route_list, head) {
522 if (route->shared->src.inst == src &&
523 route->shared->dst.inst == dst &&
524 route->src.streamid == src_streamid &&
525 route->dst.streamid == dst_streamid) {
526 matching_route = route;
527 break;
528 }
529 }
530 if (matching_route == NULL) {
531 vty_out(vty, "%% no route with that configuration%s",
532 VTY_NEWLINE);
533 return CMD_WARNING;
534 }
535 /* delete this route from list. */
536 llist_del(&matching_route->head);
537
538 if (--matching_route->shared->refcnt == 0) {
539 /* nobody else using this route, release all resources. */
540 llist_for_each_entry_safe(conn, tmp,
541 &matching_route->shared->conn_list, head) {
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200542 ipa_server_conn_destroy(conn->src);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200543 llist_del(&conn->head);
544 talloc_free(conn);
545 }
546 osmo_fd_unregister(&route->shared->bfd);
547 close(route->shared->bfd.fd);
548 route->shared->bfd.fd = -1;
549
550 talloc_free(route->shared);
551 } else {
552 /* otherwise, revert the mapping that this route applies. */
553 bitvec_set_bit_pos(&matching_route->shared->src.streamid_map,
554 src_streamid, ZERO);
555 bitvec_set_bit_pos(&matching_route->shared->dst.streamid_map,
556 dst_streamid, ZERO);
557 matching_route->shared->src.streamid[src_streamid] = 0x00;
558 matching_route->shared->dst.streamid[dst_streamid] = 0x00;
559 }
560 matching_route->shared->src.inst->refcnt--;
561 matching_route->shared->dst.inst->refcnt--;
562 talloc_free(matching_route);
563
564 return CMD_SUCCESS;
565}
566
567DEFUN(ipa_route_show, ipa_route_show_cmd,
568 "ipa route show", "Show existing ipaccess proxy routes")
569{
570 struct ipa_proxy_route *this;
571
572 llist_for_each_entry(this, &ipa_proxy_route_list, head) {
573 vty_out(vty, "route instance %s streamid 0x%.2x "
574 "instance %s streamid 0x%.2x%s",
575 this->shared->src.inst->name, this->src.streamid,
576 this->shared->dst.inst->name, this->dst.streamid,
577 VTY_NEWLINE);
578 }
579 return CMD_SUCCESS;
580}
581
582/*
583 * Config for ipaccess-proxy
584 */
585DEFUN(ipa_cfg, ipa_cfg_cmd, "ipa", "Configure the ipaccess proxy")
586{
587 vty->index = NULL;
Harald Weltecc2241b2011-07-19 16:06:06 +0200588 vty->node = L_IPA_NODE;
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200589 return CMD_SUCCESS;
590}
591
592/* all these below look like enable commands, but without the ipa prefix. */
593DEFUN(ipa_route_cfg_add, ipa_route_cfg_add_cmd,
594 "route instance NAME streamid HEXNUM "
595 "instance NAME streamid HEXNUM", "Add IPA route")
596{
597 return __ipa_route_add(vty, argc, argv);
598}
599
600DEFUN(ipa_instance_cfg_add, ipa_instance_cfg_add_cmd,
601 "instance NAME (bind|connect) IP tcp port PORT",
602 "Bind or connect instance to address and port")
603{
604 return __ipa_instance_add(vty, argc, argv);
605}
606
607struct cmd_node ipa_node = {
Harald Weltecc2241b2011-07-19 16:06:06 +0200608 L_IPA_NODE,
Jacob Erlbeck1c9dcc12013-11-11 14:13:13 +0100609 "%s(config-ipa)# ",
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200610 1,
611};
612
613static int ipa_cfg_write(struct vty *vty)
614{
615 bool heading = false;
616 struct ipa_proxy_instance *inst;
617 struct ipa_proxy_route *route;
618
619 llist_for_each_entry(inst, &ipa_instance_list, head) {
620 if (!heading) {
621 vty_out(vty, "ipa%s", VTY_NEWLINE);
622 heading = true;
623 }
624 vty_out(vty, " instance %s %s %s tcp port %u%s",
625 inst->name,
626 inst->net.type == IPA_INSTANCE_T_BIND ?
627 "bind" : "connect",
628 inst->net.addr,
629 inst->net.port, VTY_NEWLINE);
630 }
631 llist_for_each_entry(route, &ipa_proxy_route_list, head) {
632 vty_out(vty, " route instance %s streamid 0x%.2x "
633 "instance %s streamid 0x%.2x%s",
634 route->shared->src.inst->name, route->src.streamid,
635 route->shared->dst.inst->name, route->dst.streamid,
636 VTY_NEWLINE);
637 }
638 return CMD_SUCCESS;
639}
640
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200641void ipa_proxy_vty_init(void)
642{
643 tall_ipa_proxy_ctx =
644 talloc_named_const(libosmo_abis_ctx, 1, "ipa_proxy");
645
Vadim Yanitskiy82ef2a22020-10-04 16:15:52 +0700646 install_lib_element(ENABLE_NODE, &ipa_instance_add_cmd);
647 install_lib_element(ENABLE_NODE, &ipa_instance_del_cmd);
648 install_lib_element(ENABLE_NODE, &ipa_instance_show_cmd);
649 install_lib_element(ENABLE_NODE, &ipa_route_add_cmd);
650 install_lib_element(ENABLE_NODE, &ipa_route_del_cmd);
651 install_lib_element(ENABLE_NODE, &ipa_route_show_cmd);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200652
Vadim Yanitskiy82ef2a22020-10-04 16:15:52 +0700653 install_lib_element(CONFIG_NODE, &ipa_cfg_cmd);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200654 install_node(&ipa_node, ipa_cfg_write);
Vadim Yanitskiy82ef2a22020-10-04 16:15:52 +0700655 install_lib_element(L_IPA_NODE, &ipa_instance_cfg_add_cmd);
656 install_lib_element(L_IPA_NODE, &ipa_route_cfg_add_cmd);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200657}