blob: 44f5baf51a59e60407fe97ee5f64a6096fa34da6 [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
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200187 conn->dst = ipa_client_conn_create(NULL, NULL, 0,
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200188 route->shared->dst.inst->net.addr,
189 route->shared->dst.inst->net.port,
Pablo Neira Ayuso88136fc2011-07-08 16:21:55 +0200190 NULL,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200191 ipa_sock_dst_cb,
Pablo Neira Ayuso8ad30c92011-09-08 13:29:06 +0200192 NULL,
Pablo Neira Ayusoc9c4fd32011-06-30 12:19:42 +0200193 conn);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200194 if (conn->dst == NULL) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200195 LOGP(DLINP, LOGL_ERROR, "could not create client: %s\n",
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200196 strerror(errno));
197 return -ENOMEM;
198 }
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200199 if (ipa_client_conn_open(conn->dst) < 0) {
Harald Weltecc2241b2011-07-19 16:06:06 +0200200 LOGP(DLINP, LOGL_ERROR, "could not start client: %s\n",
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200201 strerror(errno));
202 return -ENOMEM;
203 }
204 llist_add(&conn->head, &route->shared->conn_list);
Holger Hans Peter Freyther3a5b4362013-07-04 20:05:50 +0200205 return 0;
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200206}
207
208/*
209 * VTY commands for IPA
210 */
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200211static int __ipa_instance_add(struct vty *vty, int argc, const char *argv[])
212{
213 struct ipa_proxy_instance *ipi;
214 enum ipa_proxy_instance_net_type type;
215 struct in_addr addr;
216 uint16_t port;
217
218 if (argc < 4)
219 return CMD_ERR_INCOMPLETE;
220
221 llist_for_each_entry(ipi, &ipa_instance_list, head) {
222 if (strncmp(ipi->name, argv[0], IPA_INSTANCE_NAME) != 0)
223 continue;
224
225 vty_out(vty, "%% instance `%s' already exists%s",
226 ipi->name, VTY_NEWLINE);
227 return CMD_WARNING;
228 }
229 if (strncmp(argv[1], "bind", IPA_INSTANCE_NAME) == 0)
230 type = IPA_INSTANCE_T_BIND;
231 else if (strncmp(argv[1], "connect", IPA_INSTANCE_NAME) == 0)
232 type = IPA_INSTANCE_T_CONNECT;
233 else
234 return CMD_ERR_INCOMPLETE;
235
236 if (inet_aton(argv[2], &addr) < 0) {
237 vty_out(vty, "%% invalid address %s%s", argv[1], VTY_NEWLINE);
238 return CMD_WARNING;
239 }
240 port = atoi(argv[3]);
241
242 ipi = talloc_zero(tall_ipa_proxy_ctx, struct ipa_proxy_instance);
243 if (ipi == NULL) {
244 vty_out(vty, "%% can't allocate memory for new instance%s",
245 VTY_NEWLINE);
246 return CMD_WARNING;
247 }
Neels Hofmeyr4c57eef2018-07-26 17:28:24 +0200248 osmo_strlcpy(ipi->name, argv[0], sizeof(ipi->name));
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200249 ipi->net.type = type;
250 ipi->net.addr = talloc_strdup(tall_ipa_proxy_ctx, argv[2]);
251 ipi->net.port = port;
252 llist_add_tail(&ipi->head, &ipa_instance_list);
253
254 return CMD_SUCCESS;
255}
256
257DEFUN(ipa_instance_add, ipa_instance_add_cmd,
258 "ipa instance NAME (bind|connect) IP tcp port PORT",
259 "Bind or connect instance to address and port")
260{
261 return __ipa_instance_add(vty, argc, argv);
262}
263
264DEFUN(ipa_instance_del, ipa_instance_del_cmd,
265 "no ipa instance NAME",
266 "Delete instance to address and port")
267{
268 struct ipa_proxy_instance *ipi;
269
270 if (argc < 1)
271 return CMD_ERR_INCOMPLETE;
272
273 llist_for_each_entry(ipi, &ipa_instance_list, head) {
274 if (strncmp(ipi->name, argv[0], IPA_INSTANCE_NAME) != 0)
275 continue;
276
277 if (ipi->refcnt > 0) {
278 vty_out(vty, "%% instance `%s' is in use%s",
279 ipi->name, VTY_NEWLINE);
280 return CMD_WARNING;
281 }
282 llist_del(&ipi->head);
283 talloc_free(ipi);
284 return CMD_SUCCESS;
285 }
286 vty_out(vty, "%% instance `%s' does not exist%s",
287 ipi->name, VTY_NEWLINE);
288
289 return CMD_WARNING;
290}
291
292DEFUN(ipa_instance_show, ipa_instance_show_cmd,
293 "ipa instance show", "Show existing ipaccess proxy instances")
294{
295 struct ipa_proxy_instance *this;
296
297 llist_for_each_entry(this, &ipa_instance_list, head) {
298 vty_out(vty, "instance %s %s %s tcp port %u%s",
299 this->name, this->net.addr,
300 this->net.type == IPA_INSTANCE_T_BIND ?
301 "bind" : "connect",
302 this->net.port, VTY_NEWLINE);
303 }
304 return CMD_SUCCESS;
305}
306
307static int __ipa_route_add(struct vty *vty, int argc, const char *argv[])
308{
309 struct ipa_proxy_instance *ipi = vty->index;
310 struct ipa_proxy_instance *src = NULL, *dst = NULL;
311 uint32_t src_streamid, dst_streamid;
312 struct ipa_proxy_route *route, *matching_route = NULL;
313 struct ipa_proxy_route_shared *shared = NULL;
314 int ret;
315
316 if (argc < 4)
317 return CMD_ERR_INCOMPLETE;
318
319 llist_for_each_entry(ipi, &ipa_instance_list, head) {
320 if (strncmp(ipi->name, argv[0], IPA_INSTANCE_NAME) == 0) {
321 src = ipi;
322 continue;
323 }
324 if (strncmp(ipi->name, argv[2], IPA_INSTANCE_NAME) == 0) {
325 dst = ipi;
326 continue;
327 }
328 }
329 if (src == NULL) {
330 vty_out(vty, "%% instance `%s' does not exists%s",
331 argv[0], VTY_NEWLINE);
332 return CMD_WARNING;
333 }
334 if (dst == NULL) {
335 vty_out(vty, "%% instance `%s' does not exists%s",
336 argv[2], VTY_NEWLINE);
337 return CMD_WARNING;
338 }
339 if (src->net.type != IPA_INSTANCE_T_BIND) {
340 vty_out(vty, "%% instance `%s' is not of bind type%s",
341 argv[0], VTY_NEWLINE);
342 return CMD_WARNING;
343 }
344 if (dst->net.type != IPA_INSTANCE_T_CONNECT) {
345 vty_out(vty, "%% instance `%s' is not of connect type%s",
346 argv[2], VTY_NEWLINE);
347 return CMD_WARNING;
348 }
349 src_streamid = strtoul(argv[1], NULL, 16);
350 if (src_streamid > 0xff) {
351 vty_out(vty, "%% source streamid must be "
352 ">= 0x00 and <= 0xff%s", VTY_NEWLINE);
353 return CMD_WARNING;
354 }
355 dst_streamid = strtoul(argv[3], NULL, 16);
356 if (dst_streamid > 0xff) {
357 vty_out(vty, "%% destination streamid must be "
358 ">= 0x00 and <= 0xff%s", VTY_NEWLINE);
359 return CMD_WARNING;
360 }
361 llist_for_each_entry(route, &ipa_proxy_route_list, head) {
362 if (route->shared->src.inst == src &&
363 route->shared->dst.inst == dst) {
364 if (route->src.streamid == src_streamid &&
365 route->dst.streamid == dst_streamid) {
366 vty_out(vty, "%% this route already exists%s",
367 VTY_NEWLINE);
368 return CMD_WARNING;
369 }
370 matching_route = route;
371 break;
372 }
373 }
374 /* new route for this configuration. */
375 route = talloc_zero(tall_ipa_proxy_ctx, struct ipa_proxy_route);
376 if (route == NULL) {
377 vty_out(vty, "%% can't allocate memory for new route%s",
378 VTY_NEWLINE);
379 return CMD_WARNING;
380 }
381 route->src.streamid = src_streamid;
382 route->dst.streamid = dst_streamid;
383
384 if (matching_route != NULL) {
385 /* there's already a master route for these configuration. */
386 if (matching_route->shared->src.inst != src) {
387 vty_out(vty, "%% route does not contain "
388 "source instance `%s'%s",
389 argv[0], VTY_NEWLINE);
390 return CMD_WARNING;
391 }
392 if (matching_route->shared->dst.inst != dst) {
393 vty_out(vty, "%% route does not contain "
394 "destination instance `%s'%s",
395 argv[2], VTY_NEWLINE);
396 return CMD_WARNING;
397 }
398 /* use already existing shared routing information. */
399 shared = matching_route->shared;
400 } else {
401 struct ipa_server_link *link;
402
403 /* this is a brand new route, allocate shared routing info. */
404 shared = talloc_zero(tall_ipa_proxy_ctx, struct ipa_proxy_route_shared);
405 if (shared == NULL) {
406 vty_out(vty, "%% can't allocate memory for "
407 "new route shared%s", VTY_NEWLINE);
408 return CMD_WARNING;
409 }
410 shared->src.streamid_map.data_len =
411 sizeof(shared->src.streamid_map_data);
412 shared->src.streamid_map.data =
413 shared->src.streamid_map_data;
414 shared->dst.streamid_map.data_len =
415 sizeof(shared->dst.streamid_map_data);
416 shared->dst.streamid_map.data =
417 shared->dst.streamid_map_data;
418
419 link = ipa_server_link_create(tall_ipa_proxy_ctx, NULL,
420 "0.0.0.0",
421 src->net.port,
422 ipa_sock_src_accept_cb, route);
423 if (link == NULL) {
424 vty_out(vty, "%% can't bind instance `%s' to port%s",
425 src->name, VTY_NEWLINE);
426 return CMD_WARNING;
427 }
428 if (ipa_server_link_open(link) < 0) {
429 vty_out(vty, "%% can't bind instance `%s' to port%s",
430 src->name, VTY_NEWLINE);
431 return CMD_WARNING;
432 }
433 INIT_LLIST_HEAD(&shared->conn_list);
434 }
435 route->shared = shared;
436 src->refcnt++;
437 route->shared->src.inst = src;
438 dst->refcnt++;
439 route->shared->dst.inst = dst;
440 shared->src.streamid[src_streamid] = dst_streamid;
441 shared->dst.streamid[dst_streamid] = src_streamid;
442 ret = bitvec_set_bit_pos(&shared->src.streamid_map, src_streamid, ONE);
443 if (ret < 0) {
444 vty_out(vty, "%% bad bitmask (?)%s", VTY_NEWLINE);
445 return CMD_WARNING;
446 }
447 ret = bitvec_set_bit_pos(&shared->dst.streamid_map, dst_streamid, ONE);
448 if (ret < 0) {
449 vty_out(vty, "%% bad bitmask (?)%s", VTY_NEWLINE);
450 return CMD_WARNING;
451 }
452 shared->refcnt++;
453
454 llist_add_tail(&route->head, &ipa_proxy_route_list);
455 return CMD_SUCCESS;
456}
457
458DEFUN(ipa_route_add, ipa_route_add_cmd,
459 "ipa route instance NAME streamid HEXNUM "
460 "instance NAME streamid HEXNUM", "Add IPA route")
461{
462 return __ipa_route_add(vty, argc, argv);
463}
464
465DEFUN(ipa_route_del, ipa_route_del_cmd,
466 "no ipa route instance NAME streamid HEXNUM "
467 "instance NAME streamid HEXNUM", "Delete IPA route")
468{
469 struct ipa_proxy_instance *ipi = vty->index;
470 struct ipa_proxy_instance *src = NULL, *dst = NULL;
471 uint32_t src_streamid, dst_streamid;
472 struct ipa_proxy_route *route, *matching_route = NULL;
473 struct ipa_proxy_conn *conn, *tmp;
474
475 if (argc < 4)
476 return CMD_ERR_INCOMPLETE;
477
478 llist_for_each_entry(ipi, &ipa_instance_list, head) {
479 if (strncmp(ipi->name, argv[0], IPA_INSTANCE_NAME) == 0) {
480 src = ipi;
481 continue;
482 }
483 if (strncmp(ipi->name, argv[2], IPA_INSTANCE_NAME) == 0) {
484 dst = ipi;
485 continue;
486 }
487 }
488 if (src == NULL) {
489 vty_out(vty, "%% instance `%s' does not exists%s",
490 argv[0], VTY_NEWLINE);
491 return CMD_WARNING;
492 }
493 if (dst == NULL) {
494 vty_out(vty, "%% instance `%s' does not exists%s",
495 argv[2], VTY_NEWLINE);
496 return CMD_WARNING;
497 }
498 if (src->net.type != IPA_INSTANCE_T_BIND) {
499 vty_out(vty, "%% instance `%s' is not of bind type%s",
500 argv[0], VTY_NEWLINE);
501 return CMD_WARNING;
502 }
503 if (dst->net.type != IPA_INSTANCE_T_CONNECT) {
504 vty_out(vty, "%% instance `%s' is not of connect type%s",
505 argv[2], VTY_NEWLINE);
506 return CMD_WARNING;
507 }
508 src_streamid = strtoul(argv[1], NULL, 16);
509 if (src_streamid > 0xff) {
510 vty_out(vty, "%% source streamid must be "
511 ">= 0x00 and <= 0xff%s", VTY_NEWLINE);
512 return CMD_WARNING;
513 }
514 dst_streamid = strtoul(argv[3], NULL, 16);
515 if (dst_streamid > 0xff) {
516 vty_out(vty, "%% destination streamid must be "
517 ">= 0x00 and <= 0xff%s", VTY_NEWLINE);
518 return CMD_WARNING;
519 }
520 llist_for_each_entry(route, &ipa_proxy_route_list, head) {
521 if (route->shared->src.inst == src &&
522 route->shared->dst.inst == dst &&
523 route->src.streamid == src_streamid &&
524 route->dst.streamid == dst_streamid) {
525 matching_route = route;
526 break;
527 }
528 }
529 if (matching_route == NULL) {
530 vty_out(vty, "%% no route with that configuration%s",
531 VTY_NEWLINE);
532 return CMD_WARNING;
533 }
534 /* delete this route from list. */
535 llist_del(&matching_route->head);
536
537 if (--matching_route->shared->refcnt == 0) {
538 /* nobody else using this route, release all resources. */
539 llist_for_each_entry_safe(conn, tmp,
540 &matching_route->shared->conn_list, head) {
Pablo Neira Ayusof0995672011-09-08 12:58:38 +0200541 ipa_server_conn_destroy(conn->src);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200542 llist_del(&conn->head);
543 talloc_free(conn);
544 }
545 osmo_fd_unregister(&route->shared->bfd);
546 close(route->shared->bfd.fd);
547 route->shared->bfd.fd = -1;
548
549 talloc_free(route->shared);
550 } else {
551 /* otherwise, revert the mapping that this route applies. */
552 bitvec_set_bit_pos(&matching_route->shared->src.streamid_map,
553 src_streamid, ZERO);
554 bitvec_set_bit_pos(&matching_route->shared->dst.streamid_map,
555 dst_streamid, ZERO);
556 matching_route->shared->src.streamid[src_streamid] = 0x00;
557 matching_route->shared->dst.streamid[dst_streamid] = 0x00;
558 }
559 matching_route->shared->src.inst->refcnt--;
560 matching_route->shared->dst.inst->refcnt--;
561 talloc_free(matching_route);
562
563 return CMD_SUCCESS;
564}
565
566DEFUN(ipa_route_show, ipa_route_show_cmd,
567 "ipa route show", "Show existing ipaccess proxy routes")
568{
569 struct ipa_proxy_route *this;
570
571 llist_for_each_entry(this, &ipa_proxy_route_list, head) {
572 vty_out(vty, "route instance %s streamid 0x%.2x "
573 "instance %s streamid 0x%.2x%s",
574 this->shared->src.inst->name, this->src.streamid,
575 this->shared->dst.inst->name, this->dst.streamid,
576 VTY_NEWLINE);
577 }
578 return CMD_SUCCESS;
579}
580
581/*
582 * Config for ipaccess-proxy
583 */
584DEFUN(ipa_cfg, ipa_cfg_cmd, "ipa", "Configure the ipaccess proxy")
585{
586 vty->index = NULL;
Harald Weltecc2241b2011-07-19 16:06:06 +0200587 vty->node = L_IPA_NODE;
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200588 return CMD_SUCCESS;
589}
590
591/* all these below look like enable commands, but without the ipa prefix. */
592DEFUN(ipa_route_cfg_add, ipa_route_cfg_add_cmd,
593 "route instance NAME streamid HEXNUM "
594 "instance NAME streamid HEXNUM", "Add IPA route")
595{
596 return __ipa_route_add(vty, argc, argv);
597}
598
599DEFUN(ipa_instance_cfg_add, ipa_instance_cfg_add_cmd,
600 "instance NAME (bind|connect) IP tcp port PORT",
601 "Bind or connect instance to address and port")
602{
603 return __ipa_instance_add(vty, argc, argv);
604}
605
606struct cmd_node ipa_node = {
Harald Weltecc2241b2011-07-19 16:06:06 +0200607 L_IPA_NODE,
Jacob Erlbeck1c9dcc12013-11-11 14:13:13 +0100608 "%s(config-ipa)# ",
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200609 1,
610};
611
612static int ipa_cfg_write(struct vty *vty)
613{
614 bool heading = false;
615 struct ipa_proxy_instance *inst;
616 struct ipa_proxy_route *route;
617
618 llist_for_each_entry(inst, &ipa_instance_list, head) {
619 if (!heading) {
620 vty_out(vty, "ipa%s", VTY_NEWLINE);
621 heading = true;
622 }
623 vty_out(vty, " instance %s %s %s tcp port %u%s",
624 inst->name,
625 inst->net.type == IPA_INSTANCE_T_BIND ?
626 "bind" : "connect",
627 inst->net.addr,
628 inst->net.port, VTY_NEWLINE);
629 }
630 llist_for_each_entry(route, &ipa_proxy_route_list, head) {
631 vty_out(vty, " route instance %s streamid 0x%.2x "
632 "instance %s streamid 0x%.2x%s",
633 route->shared->src.inst->name, route->src.streamid,
634 route->shared->dst.inst->name, route->dst.streamid,
635 VTY_NEWLINE);
636 }
637 return CMD_SUCCESS;
638}
639
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200640void ipa_proxy_vty_init(void)
641{
642 tall_ipa_proxy_ctx =
643 talloc_named_const(libosmo_abis_ctx, 1, "ipa_proxy");
644
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200645 install_element(ENABLE_NODE, &ipa_instance_add_cmd);
646 install_element(ENABLE_NODE, &ipa_instance_del_cmd);
647 install_element(ENABLE_NODE, &ipa_instance_show_cmd);
648 install_element(ENABLE_NODE, &ipa_route_add_cmd);
649 install_element(ENABLE_NODE, &ipa_route_del_cmd);
650 install_element(ENABLE_NODE, &ipa_route_show_cmd);
651
652 install_element(CONFIG_NODE, &ipa_cfg_cmd);
653 install_node(&ipa_node, ipa_cfg_write);
Harald Weltecc2241b2011-07-19 16:06:06 +0200654 install_element(L_IPA_NODE, &ipa_instance_cfg_add_cmd);
655 install_element(L_IPA_NODE, &ipa_route_cfg_add_cmd);
Pablo Neira Ayuso130c4fb2011-06-23 21:15:53 +0200656}