1131826Sharti/*
2131826Sharti * Copyright (c) 2003-2004
3131826Sharti *	Hartmut Brandt
4131826Sharti *	All rights reserved.
5131826Sharti *
6131826Sharti * Copyright (c) 2001-2002
7131826Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
8131826Sharti *	All rights reserved.
9131826Sharti *
10131826Sharti * Author: Harti Brandt <harti@freebsd.org>
11131826Sharti *
12131826Sharti * Redistribution of this software and documentation and use in source and
13131826Sharti * binary forms, with or without modification, are permitted provided that
14131826Sharti * the following conditions are met:
15131826Sharti *
16131826Sharti * 1. Redistributions of source code or documentation must retain the above
17131826Sharti *    copyright notice, this list of conditions and the following disclaimer.
18131826Sharti * 2. Redistributions in binary form must reproduce the above copyright
19131826Sharti *    notice, this list of conditions and the following disclaimer in the
20131826Sharti *    documentation and/or other materials provided with the distribution.
21131826Sharti *
22131826Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY THE AUTHOR
23131826Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24131826Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
25131826Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
26131826Sharti * THE AUTHOR OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
27131826Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28131826Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
29131826Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
30131826Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31131826Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32131826Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33131826Sharti *
34131826Sharti * $Begemot: libunimsg/netnatm/api/cc_port.c,v 1.1 2004/07/08 08:21:53 brandt Exp $
35131826Sharti *
36131826Sharti * ATM API as defined per af-saa-0108
37131826Sharti *
38131826Sharti * Port-global stuff (ILMI and Co.)
39131826Sharti */
40131826Sharti#include <netnatm/unimsg.h>
41131826Sharti#include <netnatm/msg/unistruct.h>
42131826Sharti#include <netnatm/api/unisap.h>
43131826Sharti#include <netnatm/sig/unidef.h>
44131826Sharti#include <netnatm/api/atmapi.h>
45131826Sharti#include <netnatm/api/ccatm.h>
46131826Sharti#include <netnatm/api/ccpriv.h>
47131826Sharti
48131826Sharti/*
49131826Sharti * Find a port with a given number
50131826Sharti */
51131826Shartistatic struct ccport *
52131826Shartifind_port(struct ccdata *cc, u_int portno)
53131826Sharti{
54131826Sharti	struct ccport *port;
55131826Sharti
56131826Sharti	TAILQ_FOREACH(port, &cc->port_list, node_link)
57131826Sharti		if (port->param.port == portno)
58131826Sharti			return (port);
59131826Sharti	return (NULL);
60131826Sharti}
61131826Sharti
62131826Sharti/*
63131826Sharti * Create a new port structure, initialize it and link it to the node.
64131826Sharti * Returns 0 on success, an errno otherwise.
65131826Sharti */
66131826Shartistruct ccport *
67131826Sharticc_port_create(struct ccdata *cc, void *uarg, u_int portno)
68131826Sharti{
69131826Sharti	struct ccport *port, *p1;
70131826Sharti
71131826Sharti	if (portno == 0 || portno > 0xffffffff)
72131826Sharti		return (NULL);
73131826Sharti
74131826Sharti	TAILQ_FOREACH(port, &cc->port_list, node_link)
75131826Sharti		if (port->param.port == portno)
76131826Sharti			return (NULL);
77131826Sharti
78131826Sharti	port = CCZALLOC(sizeof(*port));
79131826Sharti	if (port == NULL)
80131826Sharti		return (NULL);
81131826Sharti
82131826Sharti	port->uarg = uarg;
83131826Sharti	port->cc = cc;
84131826Sharti	port->admin = CCPORT_STOPPED;
85131826Sharti	LIST_INIT(&port->conn_list);
86131826Sharti	TAILQ_INIT(&port->addr_list);
87131826Sharti	port->param.port = portno;
88131826Sharti	port->param.pcr = 350053;
89131826Sharti	port->param.max_vpi_bits = 0;
90131826Sharti	port->param.max_vci_bits = 8;
91131826Sharti	port->param.max_svpc_vpi = 0;
92131826Sharti	port->param.max_svcc_vpi = 0;
93131826Sharti	port->param.min_svcc_vci = 32;
94131826Sharti	port->param.num_addrs = 0;
95131826Sharti	TAILQ_INIT(&port->cookies);
96131826Sharti
97131826Sharti	TAILQ_FOREACH(p1, &cc->port_list, node_link)
98131826Sharti		if (p1->param.port > portno) {
99131826Sharti			TAILQ_INSERT_BEFORE(p1, port, node_link);
100131826Sharti			break;
101131826Sharti		}
102131826Sharti	if (p1 == NULL)
103131826Sharti		TAILQ_INSERT_TAIL(&cc->port_list, port, node_link);
104131826Sharti
105131826Sharti	return (port);
106131826Sharti}
107131826Sharti
108131826Sharti/*
109131826Sharti * Destroy a port. This closes all connections and aborts all the users of
110131826Sharti * these connections.
111131826Sharti * This should be called only after work has returned so that no signals
112131826Sharti * are pending.
113131826Sharti */
114131826Shartivoid
115131826Sharticc_port_destroy(struct ccport *port, int shutdown)
116131826Sharti{
117131826Sharti	struct ccaddr *addr;
118131826Sharti	struct ccreq *r;
119131826Sharti
120131826Sharti	TAILQ_REMOVE(&port->cc->port_list, port, node_link);
121131826Sharti
122131826Sharti	while ((r = TAILQ_FIRST(&port->cookies)) != NULL) {
123131826Sharti		TAILQ_REMOVE(&port->cookies, r, link);
124131826Sharti		CCFREE(r);
125131826Sharti	}
126131826Sharti
127131826Sharti	/*
128131826Sharti	 * Abort all connections.
129131826Sharti	 */
130131826Sharti	while (!LIST_EMPTY(&port->conn_list))
131131826Sharti		cc_conn_abort(LIST_FIRST(&port->conn_list), shutdown);
132131826Sharti
133131826Sharti	/*
134131826Sharti	 * Free addresses.
135131826Sharti	 */
136131826Sharti	while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
137131826Sharti		TAILQ_REMOVE(&port->addr_list, addr, port_link);
138131826Sharti		CCFREE(addr);
139131826Sharti	}
140131826Sharti
141131826Sharti	CCFREE(port);
142131826Sharti}
143131826Sharti
144131826Sharti/*
145131826Sharti * Management is given up on this node. Remove all addresses from the port.
146131826Sharti */
147131826Shartivoid
148131826Sharticc_unmanage(struct ccdata *cc)
149131826Sharti{
150131826Sharti	struct ccport *port;
151131826Sharti	struct ccaddr *addr;
152131826Sharti
153131826Sharti	TAILQ_FOREACH(port, &cc->port_list, node_link) {
154131826Sharti		while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
155131826Sharti			TAILQ_REMOVE(&port->addr_list, addr, port_link);
156131826Sharti			CCFREE(addr);
157131826Sharti		}
158131826Sharti	}
159131826Sharti}
160131826Sharti
161131826Sharti/*
162131826Sharti * Compare two addresses
163131826Sharti */
164131826Shartistatic __inline int
165131826Shartiaddr_eq(const struct uni_addr *a1, const struct uni_addr *a2)
166131826Sharti{
167131826Sharti	return (a1->type == a2->type && a1->plan == a2->plan &&
168131826Sharti	    a1->len == a2->len && memcmp(a1->addr, a2->addr, a1->len) == 0);
169131826Sharti}
170131826Sharti
171131826Sharti
172131826Sharti/*
173131826Sharti * retrieve addresses
174131826Sharti */
175131826Shartiint
176131826Sharticc_get_addrs(struct ccdata *cc, u_int portno,
177131826Sharti    struct uni_addr **pa, u_int **ports, u_int *count)
178131826Sharti{
179131826Sharti	struct ccport *port = NULL;
180131826Sharti	struct ccaddr *addr;
181131826Sharti	struct uni_addr *buf, *ptr;
182131826Sharti	u_int *pports;
183131826Sharti
184131826Sharti	/*
185131826Sharti	 * If a port number is specified and the port does not exist,
186131826Sharti	 * return an error.
187131826Sharti	 */
188131826Sharti	if (portno != 0)
189131826Sharti		if ((port = find_port(cc, portno)) == NULL)
190131826Sharti			return (ENOENT);
191131826Sharti
192131826Sharti	/*
193131826Sharti	 * Count the addresses
194131826Sharti	 */
195131826Sharti	*count = 0;
196131826Sharti	if (portno != 0) {
197131826Sharti		TAILQ_FOREACH(addr, &port->addr_list, port_link)
198131826Sharti			(*count)++;
199131826Sharti	} else {
200131826Sharti		TAILQ_FOREACH(port, &cc->port_list, node_link)
201131826Sharti			TAILQ_FOREACH(addr, &port->addr_list, port_link)
202131826Sharti				(*count)++;
203131826Sharti	}
204131826Sharti
205131826Sharti	buf = CCMALLOC(*count * sizeof(struct uni_addr));
206131826Sharti	if (buf == NULL)
207131826Sharti		return (ENOMEM);
208131826Sharti	ptr = buf;
209131826Sharti
210131826Sharti	*ports = CCMALLOC(*count * sizeof(u_int));
211131826Sharti	if (*ports == NULL) {
212131826Sharti		CCFREE(buf);
213131826Sharti		return (ENOMEM);
214131826Sharti	}
215131826Sharti	pports = *ports;
216131826Sharti
217131826Sharti	if (portno != 0) {
218131826Sharti		TAILQ_FOREACH(addr, &port->addr_list, port_link) {
219131826Sharti			*ptr++ = addr->addr;
220131826Sharti			*pports++ = portno;
221131826Sharti		}
222131826Sharti	} else {
223131826Sharti		TAILQ_FOREACH(port, &cc->port_list, node_link)
224131826Sharti			TAILQ_FOREACH(addr, &port->addr_list, port_link) {
225131826Sharti				*ptr++ = addr->addr;
226131826Sharti				*pports++ = port->param.port;
227131826Sharti			}
228131826Sharti	}
229131826Sharti
230131826Sharti	*pa = buf;
231131826Sharti	return (0);
232131826Sharti}
233131826Sharti
234131826Sharti/*
235131826Sharti * return port number
236131826Sharti */
237131826Shartiu_int
238131826Sharticc_port_no(struct ccport *port)
239131826Sharti{
240131826Sharti	return (port->param.port);
241131826Sharti}
242131826Sharti
243131826Sharti/*
244131826Sharti * Address unregisterd.
245131826Sharti */
246131826Shartiint
247131826Sharticc_addr_unregister(struct ccdata *cc, u_int portno, const struct uni_addr *arg)
248131826Sharti{
249131826Sharti	struct ccport *port;
250131826Sharti	struct ccaddr *a;
251131826Sharti
252131826Sharti	if ((port = find_port(cc, portno)) == NULL)
253131826Sharti		return (ENOENT);
254131826Sharti
255131826Sharti	/* Find the address */
256131826Sharti	TAILQ_FOREACH(a, &port->addr_list, port_link)
257131826Sharti		if (addr_eq(arg, &a->addr)) {
258131826Sharti			TAILQ_REMOVE(&port->addr_list, a, port_link);
259131826Sharti			CCFREE(a);
260131826Sharti			return (0);
261131826Sharti		}
262131826Sharti
263131826Sharti	return (ENOENT);
264131826Sharti}
265131826Sharti
266131826Sharti/*
267131826Sharti * Address registerd.
268131826Sharti */
269131826Shartiint
270131826Sharticc_addr_register(struct ccdata *cc, u_int portno, const struct uni_addr *arg)
271131826Sharti{
272131826Sharti	struct ccport *port, *p1;
273131826Sharti	struct ccaddr *a;
274131826Sharti
275131826Sharti	if ((port = find_port(cc, portno)) == NULL)
276131826Sharti		return (ENOENT);
277131826Sharti
278131826Sharti	/* maybe we know it already? */
279131826Sharti	TAILQ_FOREACH(p1, &port->cc->port_list, node_link)
280131826Sharti		TAILQ_FOREACH(a, &p1->addr_list, port_link)
281131826Sharti			if (addr_eq(arg, &a->addr))
282131826Sharti				return (EISCONN);
283131826Sharti
284131826Sharti	a = CCZALLOC(sizeof(*a));
285131826Sharti	if (a == NULL)
286131826Sharti		return (ENOMEM);
287131826Sharti	a->addr = *arg;
288131826Sharti
289131826Sharti	TAILQ_INSERT_TAIL(&port->addr_list, a, port_link);
290131826Sharti
291131826Sharti	return (0);
292131826Sharti}
293131826Sharti
294131826Sharti/*
295131826Sharti * Set/get port parameters.
296131826Sharti */
297131826Shartiint
298131826Sharticc_port_get_param(struct ccdata *cc, u_int portno,
299131826Sharti    struct atm_port_info *param)
300131826Sharti{
301131826Sharti	struct ccport *port;
302131826Sharti
303131826Sharti	if ((port = find_port(cc, portno)) == NULL)
304131826Sharti		return (ENOENT);
305131826Sharti
306131826Sharti	*param = port->param;
307131826Sharti	return (0);
308131826Sharti}
309131826Sharti
310131826Sharti/* XXX maybe allow only in stopped. */
311131826Shartiint
312131826Sharticc_port_set_param(struct ccdata *cc, const struct atm_port_info *param)
313131826Sharti{
314131826Sharti	struct ccport *port;
315131826Sharti	struct ccaddr *addr;
316131826Sharti
317131826Sharti	if ((port = find_port(cc, param->port)) == NULL)
318131826Sharti		return (ENOENT);
319131826Sharti
320131826Sharti	port->param = *param;
321131826Sharti
322131826Sharti	port->param.num_addrs = 0;
323131826Sharti	TAILQ_FOREACH(addr, &port->addr_list, port_link)
324131826Sharti		port->param.num_addrs++;
325131826Sharti
326131826Sharti	return (0);
327131826Sharti}
328131826Sharti
329131826Sharti/*
330131826Sharti * get port list
331131826Sharti */
332131826Shartiint
333131826Sharticc_port_getlist(struct ccdata *cc, u_int *cnt, u_int **ports)
334131826Sharti{
335131826Sharti	struct ccport *p;
336131826Sharti	u_int n;
337131826Sharti
338131826Sharti	n = 0;
339131826Sharti	TAILQ_FOREACH(p, &cc->port_list, node_link)
340131826Sharti		n++;
341131826Sharti
342131826Sharti	*ports = CCMALLOC(n * sizeof(u_int));
343131826Sharti	if (*ports == NULL)
344131826Sharti		return (ENOMEM);
345131826Sharti
346131826Sharti	n = 0;
347131826Sharti	TAILQ_FOREACH(p, &cc->port_list, node_link)
348131826Sharti		(*ports)[n++] = p->param.port;
349131826Sharti	*cnt = n;
350131826Sharti
351131826Sharti	return (0);
352131826Sharti}
353131826Sharti
354131826Sharti/*
355131826Sharti * START and STOP signalling
356131826Sharti */
357131826Shartiint
358131826Sharticc_port_start(struct ccdata *cc, u_int portno)
359131826Sharti{
360131826Sharti	struct ccport *port;
361131826Sharti
362131826Sharti	if ((port = find_port(cc, portno)) == NULL)
363131826Sharti		return (ENOENT);
364131826Sharti	if (port->admin != CCPORT_STOPPED)
365131826Sharti		return (EISCONN);
366131826Sharti
367131826Sharti	cc->funcs->send_uni_glob(port, port->uarg,
368131826Sharti	    UNIAPI_LINK_ESTABLISH_request, 0, NULL);
369131826Sharti	port->admin = CCPORT_RUNNING;
370131826Sharti
371131826Sharti	return (0);
372131826Sharti}
373131826Sharti
374131826Shartiint
375131826Sharticc_port_stop(struct ccdata *cc, u_int portno)
376131826Sharti{
377131826Sharti	struct ccport *port;
378131826Sharti
379131826Sharti	if ((port = find_port(cc, portno)) == NULL)
380131826Sharti		return (ENOENT);
381131826Sharti	if (port->admin != CCPORT_RUNNING)
382131826Sharti		return (ENOTCONN);
383131826Sharti
384131826Sharti	port->admin = CCPORT_STOPPED;
385131826Sharti
386131826Sharti	/*
387131826Sharti	 * Abort all connections.
388131826Sharti	 */
389131826Sharti	while (!LIST_EMPTY(&port->conn_list))
390131826Sharti		cc_conn_destroy(LIST_FIRST(&port->conn_list));
391131826Sharti
392131826Sharti	return (0);
393131826Sharti}
394131826Sharti
395131826Sharti/*
396131826Sharti * is port running?
397131826Sharti */
398131826Shartiint
399131826Sharticc_port_isrunning(struct ccdata *cc, u_int portno, int *state)
400131826Sharti{
401131826Sharti	struct ccport *port;
402131826Sharti
403131826Sharti	if ((port = find_port(cc, portno)) == NULL)
404131826Sharti		return (ENOENT);
405131826Sharti	if (port->admin == CCPORT_RUNNING)
406131826Sharti		*state = 1;
407131826Sharti	else
408131826Sharti		*state = 0;
409131826Sharti	return (0);
410131826Sharti}
411131826Sharti
412131826Sharti/*
413131826Sharti * Clear address and prefix information from the named port.
414131826Sharti */
415131826Shartiint
416131826Sharticc_port_clear(struct ccdata *cc, u_int portno)
417131826Sharti{
418131826Sharti	struct ccaddr *addr;
419131826Sharti	struct ccport *port;
420131826Sharti
421131826Sharti	if ((port = find_port(cc, portno)) == NULL)
422131826Sharti		return (ENOENT);
423131826Sharti
424131826Sharti	while ((addr = TAILQ_FIRST(&port->addr_list)) != NULL) {
425131826Sharti		TAILQ_REMOVE(&port->addr_list, addr, port_link);
426131826Sharti		CCFREE(addr);
427131826Sharti	}
428131826Sharti	return (0);
429131826Sharti}
430131826Sharti
431131826Sharti/*
432131826Sharti * retrieve info on local ports
433131826Sharti */
434131826Shartistruct atm_port_list *
435131826Sharticc_get_local_port_info(struct ccdata *cc, u_int portno, size_t *lenp)
436131826Sharti{
437131826Sharti	struct atm_port_list *list;
438131826Sharti	struct atm_port_info *pp;
439131826Sharti	struct uni_addr *aa;
440131826Sharti	struct ccaddr *addr;
441131826Sharti	struct ccport *port;
442131826Sharti	u_int nports, naddrs;
443131826Sharti
444131826Sharti	/*
445131826Sharti	 * Count ports and addresses.
446131826Sharti	 */
447131826Sharti	nports = 0;
448131826Sharti	naddrs = 0;
449131826Sharti	TAILQ_FOREACH(port, &cc->port_list, node_link) {
450131826Sharti		if (portno == 0 || port->param.port == portno) {
451131826Sharti			nports++;
452131826Sharti			TAILQ_FOREACH(addr, &port->addr_list, port_link)
453131826Sharti				naddrs++;
454131826Sharti		}
455131826Sharti	}
456131826Sharti
457131826Sharti	/*
458131826Sharti	 * Size and allocate message
459131826Sharti	 */
460131826Sharti	*lenp = sizeof(*list) + nports * sizeof(*pp) + naddrs * sizeof(*aa);
461131826Sharti
462131826Sharti	list = CCZALLOC(*lenp);
463131826Sharti	if (list == NULL)
464131826Sharti		return (NULL);
465131826Sharti
466131826Sharti	/*
467131826Sharti	 * Fill the message.
468131826Sharti	 */
469131826Sharti	list->num_ports = nports;
470131826Sharti	list->num_addrs = naddrs;
471131826Sharti
472131826Sharti	pp = (void *)((u_char *)list + sizeof(*list));
473131826Sharti	aa = (void *)((u_char *)list + sizeof(*list) + nports * sizeof(*pp));
474131826Sharti
475131826Sharti	TAILQ_FOREACH(port, &cc->port_list, node_link) {
476131826Sharti		if (portno == 0 || port->param.port == portno) {
477131826Sharti			*pp = port->param;
478131826Sharti			pp->num_addrs = 0;
479131826Sharti			TAILQ_FOREACH(addr, &port->addr_list, port_link) {
480131826Sharti				*aa++ = addr->addr;
481131826Sharti				pp->num_addrs++;
482131826Sharti			}
483131826Sharti			pp++;
484131826Sharti		}
485131826Sharti	}
486131826Sharti
487131826Sharti	return (list);
488131826Sharti}
489131826Sharti
490131826Shartistatic struct ccreq *
491131826Shartifind_cookie(struct ccport *port, u_int cookie)
492131826Sharti{
493131826Sharti	struct ccreq *r;
494131826Sharti
495131826Sharti	TAILQ_FOREACH(r, &port->cookies, link)
496131826Sharti		if (r->cookie == cookie)
497131826Sharti			return (r);
498131826Sharti	return (NULL);
499131826Sharti}
500131826Sharti
501131826Sharti/*
502131826Sharti * input a response from the UNI layer to CC
503131826Sharti */
504131826Shartiint
505131826Sharticc_uni_response(struct ccport *port, u_int cookie, u_int reason, u_int state)
506131826Sharti{
507131826Sharti	struct ccconn *conn;
508131826Sharti	struct ccreq *req;
509131826Sharti
510131826Sharti	if (cookie == 0)
511131826Sharti		return (EINVAL);
512131826Sharti
513131826Sharti	if (port->admin != CCPORT_RUNNING)
514131826Sharti		return (ENOTCONN);
515131826Sharti
516131826Sharti	if ((req = find_cookie(port, cookie)) == NULL) {
517131826Sharti		cc_port_log(port, "UNI response for unknown cookie %u", cookie);
518131826Sharti		return (EINVAL);
519131826Sharti	}
520131826Sharti	conn = req->conn;
521131826Sharti
522131826Sharti	TAILQ_REMOVE(&port->cookies, req, link);
523131826Sharti	CCFREE(req);
524131826Sharti
525131826Sharti	if (reason == UNIAPI_OK)
526131826Sharti		return (cc_conn_resp(conn, CONN_SIG_OK,
527131826Sharti		    cookie, reason, state));
528131826Sharti	else
529131826Sharti		return (cc_conn_resp(conn, CONN_SIG_ERROR,
530131826Sharti		    cookie, reason, state));
531131826Sharti}
532131826Sharti
533131826Shartistatic struct ccconn *
534131826Shartifind_cref(const struct ccport *port, const struct uni_cref *cref)
535131826Sharti{
536131826Sharti	struct ccconn *conn;
537131826Sharti
538131826Sharti	LIST_FOREACH(conn, &port->conn_list, port_link)
539131826Sharti		if (conn->cref.cref == cref->cref &&
540131826Sharti		    conn->cref.flag == cref->flag)
541131826Sharti			return (conn);
542131826Sharti	return (NULL);
543131826Sharti}
544131826Sharti
545131826Sharti/*
546131826Sharti * Signal from UNI on this port
547131826Sharti */
548131826Shartiint
549131826Sharticc_uni_signal(struct ccport *port, u_int cookie, u_int sig, struct uni_msg *msg)
550131826Sharti{
551131826Sharti	int error = 0;
552131826Sharti	size_t len, ilen = 0;
553131826Sharti	struct uni_cref *cref;
554131826Sharti	struct ccconn *conn;
555131826Sharti
556131826Sharti	if (port->admin != CCPORT_RUNNING) {
557131826Sharti		error = ENOTCONN;
558131826Sharti		goto out;
559131826Sharti	}
560131826Sharti	len = (msg != NULL) ? uni_msg_len(msg) : 0;
561131826Sharti
562131826Sharti	switch ((enum uni_sig)sig) {
563131826Sharti
564131826Sharti	  case UNIAPI_ERROR:
565131826Sharti		/* handled above */
566131826Sharti		cc_port_log(port, "bad UNIAPI_ERROR cookie=%u", cookie);
567131826Sharti		error = EINVAL;
568131826Sharti		break;
569131826Sharti
570131826Sharti	  case UNIAPI_CALL_CREATED:
571131826Sharti		ilen = sizeof(struct uniapi_call_created);
572131826Sharti		if (len != ilen)
573131826Sharti			goto bad_len;
574131826Sharti
575131826Sharti		if (cookie != 0) {
576131826Sharti			/* outgoing call */
577131826Sharti			struct ccreq *req;
578131826Sharti
579131826Sharti			if ((req = find_cookie(port, cookie)) == NULL) {
580131826Sharti				cc_port_log(port, "bad cookie %u in CREATE",
581131826Sharti				    cookie);
582131826Sharti				error = EINVAL;
583131826Sharti				goto out;
584131826Sharti			}
585131826Sharti			conn = req->conn;
586131826Sharti
587131826Sharti		} else {
588131826Sharti			if ((conn = cc_conn_create(port->cc)) == NULL) {
589131826Sharti				error = ENOMEM;
590131826Sharti				goto out;
591131826Sharti			}
592131826Sharti			cc_conn_ins_port(conn, port);
593131826Sharti		}
594131826Sharti
595131826Sharti		cc_conn_sig_msg_nodef(conn, CONN_SIG_CREATED, msg);
596131826Sharti		msg = NULL;
597131826Sharti		goto out;
598131826Sharti
599131826Sharti	  case UNIAPI_CALL_DESTROYED:
600131826Sharti		ilen = sizeof(struct uniapi_call_destroyed);
601131826Sharti		if (len != ilen)
602131826Sharti			goto bad_len;
603131826Sharti
604131826Sharti		cref = &uni_msg_rptr(msg, struct uniapi_call_destroyed *)->cref;
605131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
606131826Sharti			goto unk_call;
607131826Sharti
608131826Sharti		error = cc_conn_sig(conn, CONN_SIG_DESTROYED, NULL);
609131826Sharti		goto out;
610131826Sharti
611131826Sharti	  case UNIAPI_LINK_ESTABLISH_confirm:
612131826Sharti		goto out;
613131826Sharti
614131826Sharti	  case UNIAPI_LINK_RELEASE_confirm:
615131826Sharti		/* Ups. If we administratively up, restart the link */
616131826Sharti		if (port->admin == CCPORT_RUNNING)
617131826Sharti			port->cc->funcs->send_uni_glob(port, port->uarg,
618131826Sharti			    UNIAPI_LINK_ESTABLISH_request, 0, NULL);
619131826Sharti		goto out;
620131826Sharti
621131826Sharti	  case UNIAPI_PARTY_CREATED:
622131826Sharti		ilen = sizeof(struct uniapi_party_created);
623131826Sharti		if (len != ilen)
624131826Sharti			goto bad_len;
625131826Sharti
626131826Sharti		cref = &uni_msg_rptr(msg, struct uniapi_party_created *)->cref;
627131826Sharti
628131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
629131826Sharti			goto unk_call;
630131826Sharti
631131826Sharti		error = cc_conn_sig_msg_nodef(conn,
632131826Sharti		     CONN_SIG_PARTY_CREATED, msg);
633131826Sharti		msg = NULL;
634131826Sharti		goto out;
635131826Sharti
636131826Sharti	  case UNIAPI_PARTY_DESTROYED:
637131826Sharti		ilen = sizeof(struct uniapi_party_destroyed);
638131826Sharti		if (len != ilen)
639131826Sharti			goto bad_len;
640131826Sharti
641131826Sharti		cref = &uni_msg_rptr(msg,
642131826Sharti		    struct uniapi_party_destroyed *)->cref;
643131826Sharti
644131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
645131826Sharti			goto unk_call;
646131826Sharti
647131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_DESTROYED, msg);
648131826Sharti		msg = NULL;
649131826Sharti		goto out;
650131826Sharti
651131826Sharti	  case UNIAPI_DROP_PARTY_ACK_indication:	/* UNI -> API */
652131826Sharti		ilen = sizeof(struct uniapi_drop_party_ack_indication);
653131826Sharti		if (len != ilen)
654131826Sharti			goto bad_len;
655131826Sharti
656131826Sharti		cref = &uni_msg_rptr(msg,
657131826Sharti		    struct uniapi_drop_party_ack_indication *)->drop.hdr.cref;
658131826Sharti
659131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
660131826Sharti			goto unk_call;
661131826Sharti
662131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_DROP_PARTY_ACK_IND, msg);
663131826Sharti		msg = NULL;
664131826Sharti		goto out;
665131826Sharti
666131826Sharti	  case UNIAPI_RESET_indication:			/* UNI -> API */
667131826Sharti	    {
668131826Sharti		/*
669131826Sharti		 * XXX - do the right thing
670131826Sharti		 */
671131826Sharti		struct uniapi_reset_indication *ind = uni_msg_rptr(msg,
672131826Sharti		    struct uniapi_reset_indication *);
673131826Sharti		struct uniapi_reset_response *resp;
674131826Sharti		struct uni_msg *u;
675131826Sharti
676131826Sharti		/*
677131826Sharti		 * Construct message to UNI.
678131826Sharti		 */
679131826Sharti		if ((u = uni_msg_alloc(sizeof(*resp))) == NULL)
680131826Sharti			return (ENOMEM);
681131826Sharti
682131826Sharti		resp = uni_msg_wptr(u, struct uniapi_reset_response *);
683131826Sharti		memset(resp, 0, sizeof(*resp));
684131826Sharti		u->b_wptr += sizeof(*resp);
685131826Sharti
686131826Sharti		resp->restart = ind->restart;
687131826Sharti		resp->connid = ind->connid;
688131826Sharti
689131826Sharti		port->cc->funcs->send_uni_glob(port, port->uarg,
690131826Sharti		    UNIAPI_RESET_response, 0, u);
691131826Sharti
692131826Sharti		goto out;
693131826Sharti	    }
694131826Sharti
695131826Sharti	  case UNIAPI_RELEASE_indication:		/* UNI -> API */
696131826Sharti		ilen = sizeof(struct uniapi_release_indication);
697131826Sharti		if (len != ilen)
698131826Sharti			goto bad_len;
699131826Sharti
700131826Sharti		cref = &uni_msg_rptr(msg, struct uniapi_release_indication *)
701131826Sharti		    ->release.hdr.cref;
702131826Sharti
703131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
704131826Sharti			goto unk_call;
705131826Sharti
706131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_REL_IND, msg);
707131826Sharti		msg = NULL;
708131826Sharti		goto out;
709131826Sharti
710131826Sharti	  case UNIAPI_RELEASE_confirm:			/* UNI -> API */
711131826Sharti		ilen = sizeof(struct uniapi_release_confirm);
712131826Sharti		if (len != ilen)
713131826Sharti			goto bad_len;
714131826Sharti
715131826Sharti		cref = &uni_msg_rptr(msg, struct uniapi_release_confirm *)
716131826Sharti		    ->release.hdr.cref;
717131826Sharti
718131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
719131826Sharti			goto unk_call;
720131826Sharti
721131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_REL_CONF, msg);
722131826Sharti		msg = NULL;
723131826Sharti		goto out;
724131826Sharti
725131826Sharti	  case UNIAPI_SETUP_confirm:			/* UNI -> API */
726131826Sharti		ilen = sizeof(struct uniapi_setup_confirm);
727131826Sharti		if (len != ilen)
728131826Sharti			goto bad_len;
729131826Sharti
730131826Sharti		cref = &uni_msg_rptr(msg, struct uniapi_setup_confirm *)
731131826Sharti		    ->connect.hdr.cref;
732131826Sharti
733131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
734131826Sharti			goto unk_call;
735131826Sharti
736131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_CONFIRM, msg);
737131826Sharti		msg = NULL;
738131826Sharti		goto out;
739131826Sharti
740131826Sharti
741131826Sharti	  case UNIAPI_ALERTING_indication:		/* UNI -> API */
742131826Sharti		ilen = sizeof(struct uniapi_alerting_indication);
743131826Sharti		if (len != ilen)
744131826Sharti			goto bad_len;
745131826Sharti
746131826Sharti		cref = &uni_msg_rptr(msg, struct uniapi_alerting_indication *)
747131826Sharti		    ->alerting.hdr.cref;
748131826Sharti
749131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
750131826Sharti			goto unk_call;
751131826Sharti
752131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_ALERTING_IND, msg);
753131826Sharti		msg = NULL;
754131826Sharti		goto out;
755131826Sharti
756131826Sharti
757131826Sharti	  case UNIAPI_PROCEEDING_indication:		/* UNI -> API */
758131826Sharti		ilen = sizeof(struct uniapi_proceeding_indication);
759131826Sharti		if (len != ilen)
760131826Sharti			goto bad_len;
761131826Sharti
762131826Sharti		cref = &uni_msg_rptr(msg, struct uniapi_proceeding_indication *)
763131826Sharti		    ->call_proc.hdr.cref;
764131826Sharti
765131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
766131826Sharti			goto unk_call;
767131826Sharti
768131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_PROC_IND, msg);
769131826Sharti		msg = NULL;
770131826Sharti		goto out;
771131826Sharti
772131826Sharti
773131826Sharti	  case UNIAPI_SETUP_indication:			/* UNI -> API */
774131826Sharti		ilen = sizeof(struct uniapi_setup_indication);
775131826Sharti		if (len != ilen)
776131826Sharti			goto bad_len;
777131826Sharti
778131826Sharti		cref = &uni_msg_rptr(msg, struct uniapi_setup_indication *)
779131826Sharti		    ->setup.hdr.cref;
780131826Sharti
781131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
782131826Sharti			goto unk_call;
783131826Sharti
784131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_IND, msg);
785131826Sharti		msg = NULL;
786131826Sharti		goto out;
787131826Sharti
788131826Sharti	  case UNIAPI_SETUP_COMPLETE_indication:	/* UNI -> API */
789131826Sharti		ilen = sizeof(struct uniapi_setup_complete_indication);
790131826Sharti		if (len != ilen)
791131826Sharti			goto bad_len;
792131826Sharti
793131826Sharti		cref = &uni_msg_rptr(msg,
794131826Sharti		    struct uniapi_setup_complete_indication *)
795131826Sharti		    ->connect_ack.hdr.cref;
796131826Sharti
797131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
798131826Sharti			goto unk_call;
799131826Sharti
800131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_SETUP_COMPL, msg);
801131826Sharti		msg = NULL;
802131826Sharti		goto out;
803131826Sharti
804131826Sharti	  case UNIAPI_PARTY_ALERTING_indication:	/* UNI -> API */
805131826Sharti		ilen = sizeof(struct uniapi_party_alerting_indication);
806131826Sharti		if (len != ilen)
807131826Sharti			goto bad_len;
808131826Sharti
809131826Sharti		cref = &uni_msg_rptr(msg,
810131826Sharti		    struct uniapi_party_alerting_indication *)->alert.hdr.cref;
811131826Sharti
812131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
813131826Sharti			goto unk_call;
814131826Sharti
815131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ALERTING_IND, msg);
816131826Sharti		msg = NULL;
817131826Sharti		goto out;
818131826Sharti
819131826Sharti	  case UNIAPI_ADD_PARTY_ACK_indication:		/* UNI -> API */
820131826Sharti		ilen = sizeof(struct uniapi_add_party_ack_indication);
821131826Sharti		if (len != ilen)
822131826Sharti			goto bad_len;
823131826Sharti
824131826Sharti		cref = &uni_msg_rptr(msg,
825131826Sharti		    struct uniapi_add_party_ack_indication *)->ack.hdr.cref;
826131826Sharti
827131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
828131826Sharti			goto unk_call;
829131826Sharti
830131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ADD_ACK_IND, msg);
831131826Sharti		msg = NULL;
832131826Sharti		goto out;
833131826Sharti
834131826Sharti	  case UNIAPI_ADD_PARTY_REJ_indication:		/* UNI -> API */
835131826Sharti		ilen = sizeof(struct uniapi_add_party_rej_indication);
836131826Sharti		if (len != ilen)
837131826Sharti			goto bad_len;
838131826Sharti
839131826Sharti		cref = &uni_msg_rptr(msg,
840131826Sharti		    struct uniapi_add_party_rej_indication *)->rej.hdr.cref;
841131826Sharti
842131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
843131826Sharti			goto unk_call;
844131826Sharti
845131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_PARTY_ADD_REJ_IND, msg);
846131826Sharti		msg = NULL;
847131826Sharti		goto out;
848131826Sharti
849131826Sharti	  case UNIAPI_DROP_PARTY_indication:		/* UNI -> API */
850131826Sharti		ilen = sizeof(struct uniapi_drop_party_indication);
851131826Sharti		if (len != ilen)
852131826Sharti			goto bad_len;
853131826Sharti
854131826Sharti		cref = &uni_msg_rptr(msg, struct uniapi_drop_party_indication *)
855131826Sharti		    ->drop.hdr.cref;
856131826Sharti
857131826Sharti		if ((conn = find_cref(port, cref)) == NULL)
858131826Sharti			goto unk_call;
859131826Sharti
860131826Sharti		error = cc_conn_sig_msg(conn, CONN_SIG_DROP_PARTY_IND, msg);
861131826Sharti		msg = NULL;
862131826Sharti		goto out;
863131826Sharti
864131826Sharti	  case UNIAPI_RESET_confirm:			/* UNI -> API */
865131826Sharti	  case UNIAPI_RESET_ERROR_indication:		/* UNI -> API */
866131826Sharti	  case UNIAPI_RESET_STATUS_indication:		/* UNI -> API */
867131826Sharti		/* XXX */
868131826Sharti		goto out;
869131826Sharti
870131826Sharti	  case UNIAPI_NOTIFY_indication:		/* UNI -> API */
871131826Sharti	  case UNIAPI_STATUS_indication:		/* UNI -> API */
872131826Sharti		break;
873131826Sharti
874131826Sharti	  case UNIAPI_ADD_PARTY_indication:		/* UNI -> API */
875131826Sharti		/* not supported by the API */
876131826Sharti		break;
877131826Sharti
878131826Sharti	/*
879131826Sharti	 * All these are illegal in this direction
880131826Sharti	 */
881131826Sharti	  case UNIAPI_LINK_ESTABLISH_request:		/* API -> UNI */
882131826Sharti	  case UNIAPI_LINK_RELEASE_request:		/* API -> UNI */
883131826Sharti	  case UNIAPI_RESET_request:			/* API -> UNI */
884131826Sharti	  case UNIAPI_RESET_response:			/* API -> UNI */
885131826Sharti	  case UNIAPI_RESET_ERROR_response:		/* API -> UNI */
886131826Sharti	  case UNIAPI_SETUP_request:			/* API -> UNI */
887131826Sharti	  case UNIAPI_SETUP_response:			/* API -> UNI */
888131826Sharti	  case UNIAPI_ALERTING_request:			/* API -> UNI */
889131826Sharti	  case UNIAPI_PROCEEDING_request:		/* API -> UNI */
890131826Sharti	  case UNIAPI_RELEASE_request:			/* API -> UNI */
891131826Sharti	  case UNIAPI_RELEASE_response:			/* API -> UNI */
892131826Sharti	  case UNIAPI_NOTIFY_request:			/* API -> UNI */
893131826Sharti	  case UNIAPI_STATUS_ENQUIRY_request:		/* API -> UNI */
894131826Sharti	  case UNIAPI_ADD_PARTY_request:		/* API -> UNI */
895131826Sharti	  case UNIAPI_PARTY_ALERTING_request:		/* API -> UNI */
896131826Sharti	  case UNIAPI_ADD_PARTY_ACK_request:		/* API -> UNI */
897131826Sharti	  case UNIAPI_ADD_PARTY_REJ_request:		/* API -> UNI */
898131826Sharti	  case UNIAPI_DROP_PARTY_request:		/* API -> UNI */
899131826Sharti	  case UNIAPI_DROP_PARTY_ACK_request:		/* API -> UNI */
900131826Sharti	  case UNIAPI_ABORT_CALL_request:		/* API -> UNI */
901131826Sharti	  case UNIAPI_SETUP_COMPLETE_request:		/* API -> UNI */
902131826Sharti	  case UNIAPI_MAXSIG:
903131826Sharti		break;
904131826Sharti	}
905131826Sharti	cc_port_log(port, "bad signal %u", sig);
906131826Sharti	error = EINVAL;
907131826Sharti	goto out;
908131826Sharti
909131826Sharti  bad_len:
910131826Sharti	cc_port_log(port, "signal %u bad length: %zu, need %zu", len, ilen);
911131826Sharti	error = EINVAL;
912131826Sharti	goto out;
913131826Sharti
914131826Sharti  unk_call:
915131826Sharti	cc_port_log(port, "unknown call %u/%u", cref->cref, cref->flag);
916131826Sharti	error = EINVAL;
917131826Sharti
918131826Sharti  out:
919131826Sharti	if (msg != NULL)
920131826Sharti		uni_msg_destroy(msg);
921131826Sharti	return (error);
922131826Sharti}
923131826Sharti
924