2 * Copyright (c) 2003-2004
6 * Copyright (c) 2001-2002
7 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
10 * Author: Harti Brandt <harti@freebsd.org>
12 * Redistribution of this software and documentation and use in source and
13 * binary forms, with or without modification, are permitted provided that
14 * the following conditions are met:
16 * 1. Redistributions of source code or documentation must retain the above
17 * copyright notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
22 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
23 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
25 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
26 * THE AUTHOR OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * $Begemot: libunimsg/netnatm/api/cc_port.c,v 1.1 2004/07/08 08:21:53 brandt Exp $
36 * ATM API as defined per af-saa-0108
38 * Port-global stuff (ILMI and Co.)
40 #include <netnatm/unimsg.h>
41 #include <netnatm/msg/unistruct.h>
42 #include <netnatm/api/unisap.h>
43 #include <netnatm/sig/unidef.h>
44 #include <netnatm/api/atmapi.h>
45 #include <netnatm/api/ccatm.h>
46 #include <netnatm/api/ccpriv.h>
49 * Find a port with a given number
51 static struct ccport *
52 find_port(struct ccdata *cc, u_int portno)
56 TAILQ_FOREACH(port, &cc->port_list, node_link)
57 if (port->param.port == portno)
63 * Create a new port structure, initialize it and link it to the node.
64 * Returns 0 on success, an errno otherwise.
67 cc_port_create(struct ccdata *cc, void *uarg, u_int portno)
69 struct ccport *port, *p1;
71 if (portno == 0 || portno > 0xffffffff)
74 TAILQ_FOREACH(port, &cc->port_list, node_link)
75 if (port->param.port == portno)
78 port = CCZALLOC(sizeof(*port));
84 port->admin = CCPORT_STOPPED;
85 LIST_INIT(&port->conn_list);
86 TAILQ_INIT(&port->addr_list);
87 port->param.port = portno;
88 port->param.pcr = 350053;
89 port->param.max_vpi_bits = 0;
90 port->param.max_vci_bits = 8;
91 port->param.max_svpc_vpi = 0;
92 port->param.max_svcc_vpi = 0;
93 port->param.min_svcc_vci = 32;
94 port->param.num_addrs = 0;
95 TAILQ_INIT(&port->cookies);
97 TAILQ_FOREACH(p1, &cc->port_list, node_link)
98 if (p1->param.port > portno) {
99 TAILQ_INSERT_BEFORE(p1, port, node_link);
103 TAILQ_INSERT_TAIL(&cc->port_list, port, node_link);
109 * Destroy a port. This closes all connections and aborts all the users of
111 * This should be called only after work has returned so that no signals
115 cc_port_destroy(struct ccport *port, int shutdown)
120 TAILQ_REMOVE(&port->cc->port_list, port, node_link);
122 while ((r = TAILQ_FIRST(&port->cookies)) != NULL) {
123 TAILQ_REMOVE(&port->cookies, r, link);
128 * Abort all connections.
130 while (!LIST_EMPTY(&port->conn_list))
131 cc_conn_abort(LIST_FIRST(&port->conn_list), shutdown);
136 while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
137 TAILQ_REMOVE(&port->addr_list, addr, port_link);
145 * Management is given up on this node. Remove all addresses from the port.
148 cc_unmanage(struct ccdata *cc)
153 TAILQ_FOREACH(port, &cc->port_list, node_link) {
154 while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
155 TAILQ_REMOVE(&port->addr_list, addr, port_link);
162 * Compare two addresses
165 addr_eq(const struct uni_addr *a1, const struct uni_addr *a2)
167 return (a1->type == a2->type && a1->plan == a2->plan &&
168 a1->len == a2->len && memcmp(a1->addr, a2->addr, a1->len) == 0);
176 cc_get_addrs(struct ccdata *cc, u_int portno,
177 struct uni_addr **pa, u_int **ports, u_int *count)
179 struct ccport *port = NULL;
181 struct uni_addr *buf, *ptr;
185 * If a port number is specified and the port does not exist,
189 if ((port = find_port(cc, portno)) == NULL)
193 * Count the addresses
197 TAILQ_FOREACH(addr, &port->addr_list, port_link)
200 TAILQ_FOREACH(port, &cc->port_list, node_link)
201 TAILQ_FOREACH(addr, &port->addr_list, port_link)
205 buf = CCMALLOC(*count * sizeof(struct uni_addr));
210 *ports = CCMALLOC(*count * sizeof(u_int));
211 if (*ports == NULL) {
218 TAILQ_FOREACH(addr, &port->addr_list, port_link) {
223 TAILQ_FOREACH(port, &cc->port_list, node_link)
224 TAILQ_FOREACH(addr, &port->addr_list, port_link) {
226 *pports++ = port->param.port;
238 cc_port_no(struct ccport *port)
240 return (port->param.port);
244 * Address unregisterd.
247 cc_addr_unregister(struct ccdata *cc, u_int portno, const struct uni_addr *arg)
252 if ((port = find_port(cc, portno)) == NULL)
255 /* Find the address */
256 TAILQ_FOREACH(a, &port->addr_list, port_link)
257 if (addr_eq(arg, &a->addr)) {
258 TAILQ_REMOVE(&port->addr_list, a, port_link);
270 cc_addr_register(struct ccdata *cc, u_int portno, const struct uni_addr *arg)
272 struct ccport *port, *p1;
275 if ((port = find_port(cc, portno)) == NULL)
278 /* maybe we know it already? */
279 TAILQ_FOREACH(p1, &port->cc->port_list, node_link)
280 TAILQ_FOREACH(a, &p1->addr_list, port_link)
281 if (addr_eq(arg, &a->addr))
284 a = CCZALLOC(sizeof(*a));
289 TAILQ_INSERT_TAIL(&port->addr_list, a, port_link);
295 * Set/get port parameters.
298 cc_port_get_param(struct ccdata *cc, u_int portno,
299 struct atm_port_info *param)
303 if ((port = find_port(cc, portno)) == NULL)
306 *param = port->param;
310 /* XXX maybe allow only in stopped. */
312 cc_port_set_param(struct ccdata *cc, const struct atm_port_info *param)
317 if ((port = find_port(cc, param->port)) == NULL)
320 port->param = *param;
322 port->param.num_addrs = 0;
323 TAILQ_FOREACH(addr, &port->addr_list, port_link)
324 port->param.num_addrs++;
333 cc_port_getlist(struct ccdata *cc, u_int *cnt, u_int **ports)
339 TAILQ_FOREACH(p, &cc->port_list, node_link)
342 *ports = CCMALLOC(n * sizeof(u_int));
347 TAILQ_FOREACH(p, &cc->port_list, node_link)
348 (*ports)[n++] = p->param.port;
355 * START and STOP signalling
358 cc_port_start(struct ccdata *cc, u_int portno)
362 if ((port = find_port(cc, portno)) == NULL)
364 if (port->admin != CCPORT_STOPPED)
367 cc->funcs->send_uni_glob(port, port->uarg,
368 UNIAPI_LINK_ESTABLISH_request, 0, NULL);
369 port->admin = CCPORT_RUNNING;
375 cc_port_stop(struct ccdata *cc, u_int portno)
379 if ((port = find_port(cc, portno)) == NULL)
381 if (port->admin != CCPORT_RUNNING)
384 port->admin = CCPORT_STOPPED;
387 * Abort all connections.
389 while (!LIST_EMPTY(&port->conn_list))
390 cc_conn_destroy(LIST_FIRST(&port->conn_list));
399 cc_port_isrunning(struct ccdata *cc, u_int portno, int *state)
403 if ((port = find_port(cc, portno)) == NULL)
405 if (port->admin == CCPORT_RUNNING)
413 * Clear address and prefix information from the named port.
416 cc_port_clear(struct ccdata *cc, u_int portno)
421 if ((port = find_port(cc, portno)) == NULL)
424 while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
425 TAILQ_REMOVE(&port->addr_list, addr, port_link);
432 * retrieve info on local ports
434 struct atm_port_list *
435 cc_get_local_port_info(struct ccdata *cc, u_int portno, size_t *lenp)
437 struct atm_port_list *list;
438 struct atm_port_info *pp;
442 u_int nports, naddrs;
445 * Count ports and addresses.
449 TAILQ_FOREACH(port, &cc->port_list, node_link) {
450 if (portno == 0 || port->param.port == portno) {
452 TAILQ_FOREACH(addr, &port->addr_list, port_link)
458 * Size and allocate message
460 *lenp = sizeof(*list) + nports * sizeof(*pp) + naddrs * sizeof(*aa);
462 list = CCZALLOC(*lenp);
469 list->num_ports = nports;
470 list->num_addrs = naddrs;
472 pp = (void *)((u_char *)list + sizeof(*list));
473 aa = (void *)((u_char *)list + sizeof(*list) + nports * sizeof(*pp));
475 TAILQ_FOREACH(port, &cc->port_list, node_link) {
476 if (portno == 0 || port->param.port == portno) {
479 TAILQ_FOREACH(addr, &port->addr_list, port_link) {
490 static struct ccreq *
491 find_cookie(struct ccport *port, u_int cookie)
495 TAILQ_FOREACH(r, &port->cookies, link)
496 if (r->cookie == cookie)
502 * input a response from the UNI layer to CC
505 cc_uni_response(struct ccport *port, u_int cookie, u_int reason, u_int state)
513 if (port->admin != CCPORT_RUNNING)
516 if ((req = find_cookie(port, cookie)) == NULL) {
517 cc_port_log(port, "UNI response for unknown cookie %u", cookie);
522 TAILQ_REMOVE(&port->cookies, req, link);
525 if (reason == UNIAPI_OK)
526 return (cc_conn_resp(conn, CONN_SIG_OK,
527 cookie, reason, state));
529 return (cc_conn_resp(conn, CONN_SIG_ERROR,
530 cookie, reason, state));
533 static struct ccconn *
534 find_cref(const struct ccport *port, const struct uni_cref *cref)
538 LIST_FOREACH(conn, &port->conn_list, port_link)
539 if (conn->cref.cref == cref->cref &&
540 conn->cref.flag == cref->flag)
546 * Signal from UNI on this port
549 cc_uni_signal(struct ccport *port, u_int cookie, u_int sig, struct uni_msg *msg)
552 size_t len, ilen = 0;
553 struct uni_cref *cref;
556 if (port->admin != CCPORT_RUNNING) {
560 len = (msg != NULL) ? uni_msg_len(msg) : 0;
562 switch ((enum uni_sig)sig) {
566 cc_port_log(port, "bad UNIAPI_ERROR cookie=%u", cookie);
570 case UNIAPI_CALL_CREATED:
571 ilen = sizeof(struct uniapi_call_created);
579 if ((req = find_cookie(port, cookie)) == NULL) {
580 cc_port_log(port, "bad cookie %u in CREATE",
588 if ((conn = cc_conn_create(port->cc)) == NULL) {
592 cc_conn_ins_port(conn, port);
595 cc_conn_sig_msg_nodef(conn, CONN_SIG_CREATED, msg);
599 case UNIAPI_CALL_DESTROYED:
600 ilen = sizeof(struct uniapi_call_destroyed);
604 cref = &uni_msg_rptr(msg, struct uniapi_call_destroyed *)->cref;
605 if ((conn = find_cref(port, cref)) == NULL)
608 error = cc_conn_sig(conn, CONN_SIG_DESTROYED, NULL);
611 case UNIAPI_LINK_ESTABLISH_confirm:
614 case UNIAPI_LINK_RELEASE_confirm:
615 /* Ups. If we administratively up, restart the link */
616 if (port->admin == CCPORT_RUNNING)
617 port->cc->funcs->send_uni_glob(port, port->uarg,
618 UNIAPI_LINK_ESTABLISH_request, 0, NULL);
621 case UNIAPI_PARTY_CREATED:
622 ilen = sizeof(struct uniapi_party_created);
626 cref = &uni_msg_rptr(msg, struct uniapi_party_created *)->cref;
628 if ((conn = find_cref(port, cref)) == NULL)
631 error = cc_conn_sig_msg_nodef(conn,
632 CONN_SIG_PARTY_CREATED, msg);
636 case UNIAPI_PARTY_DESTROYED:
637 ilen = sizeof(struct uniapi_party_destroyed);
641 cref = &uni_msg_rptr(msg,
642 struct uniapi_party_destroyed *)->cref;
644 if ((conn = find_cref(port, cref)) == NULL)
647 error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_DESTROYED, msg);
651 case UNIAPI_DROP_PARTY_ACK_indication: /* UNI -> API */
652 ilen = sizeof(struct uniapi_drop_party_ack_indication);
656 cref = &uni_msg_rptr(msg,
657 struct uniapi_drop_party_ack_indication *)->drop.hdr.cref;
659 if ((conn = find_cref(port, cref)) == NULL)
662 error = cc_conn_sig_msg(conn, CONN_SIG_DROP_PARTY_ACK_IND, msg);
666 case UNIAPI_RESET_indication: /* UNI -> API */
669 * XXX - do the right thing
671 struct uniapi_reset_indication *ind = uni_msg_rptr(msg,
672 struct uniapi_reset_indication *);
673 struct uniapi_reset_response *resp;
677 * Construct message to UNI.
679 if ((u = uni_msg_alloc(sizeof(*resp))) == NULL)
682 resp = uni_msg_wptr(u, struct uniapi_reset_response *);
683 memset(resp, 0, sizeof(*resp));
684 u->b_wptr += sizeof(*resp);
686 resp->restart = ind->restart;
687 resp->connid = ind->connid;
689 port->cc->funcs->send_uni_glob(port, port->uarg,
690 UNIAPI_RESET_response, 0, u);
695 case UNIAPI_RELEASE_indication: /* UNI -> API */
696 ilen = sizeof(struct uniapi_release_indication);
700 cref = &uni_msg_rptr(msg, struct uniapi_release_indication *)
703 if ((conn = find_cref(port, cref)) == NULL)
706 error = cc_conn_sig_msg(conn, CONN_SIG_REL_IND, msg);
710 case UNIAPI_RELEASE_confirm: /* UNI -> API */
711 ilen = sizeof(struct uniapi_release_confirm);
715 cref = &uni_msg_rptr(msg, struct uniapi_release_confirm *)
718 if ((conn = find_cref(port, cref)) == NULL)
721 error = cc_conn_sig_msg(conn, CONN_SIG_REL_CONF, msg);
725 case UNIAPI_SETUP_confirm: /* UNI -> API */
726 ilen = sizeof(struct uniapi_setup_confirm);
730 cref = &uni_msg_rptr(msg, struct uniapi_setup_confirm *)
733 if ((conn = find_cref(port, cref)) == NULL)
736 error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_CONFIRM, msg);
741 case UNIAPI_ALERTING_indication: /* UNI -> API */
742 ilen = sizeof(struct uniapi_alerting_indication);
746 cref = &uni_msg_rptr(msg, struct uniapi_alerting_indication *)
749 if ((conn = find_cref(port, cref)) == NULL)
752 error = cc_conn_sig_msg(conn, CONN_SIG_ALERTING_IND, msg);
757 case UNIAPI_PROCEEDING_indication: /* UNI -> API */
758 ilen = sizeof(struct uniapi_proceeding_indication);
762 cref = &uni_msg_rptr(msg, struct uniapi_proceeding_indication *)
763 ->call_proc.hdr.cref;
765 if ((conn = find_cref(port, cref)) == NULL)
768 error = cc_conn_sig_msg(conn, CONN_SIG_PROC_IND, msg);
773 case UNIAPI_SETUP_indication: /* UNI -> API */
774 ilen = sizeof(struct uniapi_setup_indication);
778 cref = &uni_msg_rptr(msg, struct uniapi_setup_indication *)
781 if ((conn = find_cref(port, cref)) == NULL)
784 error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_IND, msg);
788 case UNIAPI_SETUP_COMPLETE_indication: /* UNI -> API */
789 ilen = sizeof(struct uniapi_setup_complete_indication);
793 cref = &uni_msg_rptr(msg,
794 struct uniapi_setup_complete_indication *)
795 ->connect_ack.hdr.cref;
797 if ((conn = find_cref(port, cref)) == NULL)
800 error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_COMPL, msg);
804 case UNIAPI_PARTY_ALERTING_indication: /* UNI -> API */
805 ilen = sizeof(struct uniapi_party_alerting_indication);
809 cref = &uni_msg_rptr(msg,
810 struct uniapi_party_alerting_indication *)->alert.hdr.cref;
812 if ((conn = find_cref(port, cref)) == NULL)
815 error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ALERTING_IND, msg);
819 case UNIAPI_ADD_PARTY_ACK_indication: /* UNI -> API */
820 ilen = sizeof(struct uniapi_add_party_ack_indication);
824 cref = &uni_msg_rptr(msg,
825 struct uniapi_add_party_ack_indication *)->ack.hdr.cref;
827 if ((conn = find_cref(port, cref)) == NULL)
830 error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ADD_ACK_IND, msg);
834 case UNIAPI_ADD_PARTY_REJ_indication: /* UNI -> API */
835 ilen = sizeof(struct uniapi_add_party_rej_indication);
839 cref = &uni_msg_rptr(msg,
840 struct uniapi_add_party_rej_indication *)->rej.hdr.cref;
842 if ((conn = find_cref(port, cref)) == NULL)
845 error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ADD_REJ_IND, msg);
849 case UNIAPI_DROP_PARTY_indication: /* UNI -> API */
850 ilen = sizeof(struct uniapi_drop_party_indication);
854 cref = &uni_msg_rptr(msg, struct uniapi_drop_party_indication *)
857 if ((conn = find_cref(port, cref)) == NULL)
860 error = cc_conn_sig_msg(conn, CONN_SIG_DROP_PARTY_IND, msg);
864 case UNIAPI_RESET_confirm: /* UNI -> API */
865 case UNIAPI_RESET_ERROR_indication: /* UNI -> API */
866 case UNIAPI_RESET_STATUS_indication: /* UNI -> API */
870 case UNIAPI_NOTIFY_indication: /* UNI -> API */
871 case UNIAPI_STATUS_indication: /* UNI -> API */
874 case UNIAPI_ADD_PARTY_indication: /* UNI -> API */
875 /* not supported by the API */
879 * All these are illegal in this direction
881 case UNIAPI_LINK_ESTABLISH_request: /* API -> UNI */
882 case UNIAPI_LINK_RELEASE_request: /* API -> UNI */
883 case UNIAPI_RESET_request: /* API -> UNI */
884 case UNIAPI_RESET_response: /* API -> UNI */
885 case UNIAPI_RESET_ERROR_response: /* API -> UNI */
886 case UNIAPI_SETUP_request: /* API -> UNI */
887 case UNIAPI_SETUP_response: /* API -> UNI */
888 case UNIAPI_ALERTING_request: /* API -> UNI */
889 case UNIAPI_PROCEEDING_request: /* API -> UNI */
890 case UNIAPI_RELEASE_request: /* API -> UNI */
891 case UNIAPI_RELEASE_response: /* API -> UNI */
892 case UNIAPI_NOTIFY_request: /* API -> UNI */
893 case UNIAPI_STATUS_ENQUIRY_request: /* API -> UNI */
894 case UNIAPI_ADD_PARTY_request: /* API -> UNI */
895 case UNIAPI_PARTY_ALERTING_request: /* API -> UNI */
896 case UNIAPI_ADD_PARTY_ACK_request: /* API -> UNI */
897 case UNIAPI_ADD_PARTY_REJ_request: /* API -> UNI */
898 case UNIAPI_DROP_PARTY_request: /* API -> UNI */
899 case UNIAPI_DROP_PARTY_ACK_request: /* API -> UNI */
900 case UNIAPI_ABORT_CALL_request: /* API -> UNI */
901 case UNIAPI_SETUP_COMPLETE_request: /* API -> UNI */
905 cc_port_log(port, "bad signal %u", sig);
910 cc_port_log(port, "signal %u bad length: %zu, need %zu", len, ilen);
915 cc_port_log(port, "unknown call %u/%u", cref->cref, cref->flag);
920 uni_msg_destroy(msg);