1/*
2 * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 *
25 *---------------------------------------------------------------------------
26 *
27 *	i4b_l4if.c - Layer 3 interface to Layer 4
28 *	-------------------------------------------
29 *
30 *	$Id: i4b_l4if.c,v 1.19 2005/12/11 12:25:06 christos Exp $
31 *
32 * $FreeBSD$
33 *
34 *      last edit-date: [Fri Jan  5 11:33:47 2001]
35 *
36 *---------------------------------------------------------------------------*/
37
38#include <sys/cdefs.h>
39__KERNEL_RCSID(0, "$NetBSD: i4b_l4if.c,v 1.14.2.4 2005/03/04 16:53:45 skrll Exp $");
40
41#ifdef __FreeBSD__
42#include "i4bq931.h"
43#else
44#define	NI4BQ931	1
45#endif
46#if NI4BQ931 > 0
47
48#include <sys/param.h>
49#include <sys/kernel.h>
50#include <sys/systm.h>
51#include <sys/mbuf.h>
52#include <sys/socket.h>
53#include <net/if.h>
54
55#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
56#include <sys/callout.h>
57#endif
58
59#ifdef __FreeBSD__
60#include <machine/i4b_debug.h>
61#include <machine/i4b_ioctl.h>
62#include <machine/i4b_cause.h>
63#else
64#include <netisdn/i4b_debug.h>
65#include <netisdn/i4b_ioctl.h>
66#include <netisdn/i4b_cause.h>
67#endif
68
69#include <netisdn/i4b_isdnq931.h>
70#include <netisdn/i4b_l2.h>
71#include <netisdn/i4b_l1l2.h>
72#include <netisdn/i4b_l3l4.h>
73#include <netisdn/i4b_mbuf.h>
74#include <netisdn/i4b_global.h>
75
76#include <netisdn/i4b_l3.h>
77#include <netisdn/i4b_l3fsm.h>
78#include <netisdn/i4b_q931.h>
79
80#include <netisdn/i4b_l4.h>
81
82void n_connect_request(struct call_desc *cd);
83void n_connect_response(struct call_desc *cd, int response, int cause);
84void n_disconnect_request(struct call_desc *cd, int cause);
85void n_alert_request(struct call_desc *cd);
86void n_mgmt_command(struct isdn_l3_driver *drv, int cmd, void *parm);
87
88/*---------------------------------------------------------------------------*
89 *	i4b_mdl_status_ind - status indication from lower layers
90 *---------------------------------------------------------------------------*/
91int
92i4b_mdl_status_ind(struct isdn_l3_driver *d, int status, int parm)
93{
94	int sendup, update_leds = 0;
95	int i;
96
97	NDBGL3(L3_MSG, "isdnif = %d, status = %d, parm = %d",
98	    d->isdnif, status, parm);
99
100	switch(status)
101	{
102		case STI_ATTACH:
103			if (parm) {
104				NDBGL3(L3_MSG, "STI_ATTACH: attaching isdnif %d", d->isdnif);
105			} else {
106				NDBGL3(L3_MSG, "STI_ATTACH: dettaching isdnif %d", d->isdnif);
107			}
108			break;
109
110		case STI_L1STAT:
111			i4b_l4_l12stat(d, 1, parm);
112			update_leds = 1;
113			NDBGL3(L3_MSG, "STI_L1STAT: isdnif %d layer 1 = %s", d->isdnif, status ? "up" : "down");
114			break;
115
116		case STI_L2STAT:
117			i4b_l4_l12stat(d, 2, parm);
118			update_leds = 1;
119			NDBGL3(L3_MSG, "STI_L2STAT: isdnif %d layer 2 = %s", d->isdnif, status ? "up" : "down");
120			break;
121
122		case STI_TEIASG:
123			d->tei = parm;
124			i4b_l4_teiasg(d, parm);
125			update_leds = 1;
126			NDBGL3(L3_MSG, "STI_TEIASG: isdnif %d TEI = %d = 0x%02x", d->isdnif, parm, parm);
127			break;
128
129		case STI_PDEACT:	/* L1 T4 timeout */
130			NDBGL3(L3_ERR, "STI_PDEACT: isdnif %d TEI = %d = 0x%02x", d->isdnif, parm, parm);
131
132			update_leds = 1;
133			sendup = 0;
134
135			for(i=0; i < num_call_desc; i++)
136			{
137				if(call_desc[i].isdnif == d->isdnif)
138                		{
139					i4b_l3_stop_all_timers(&(call_desc[i]));
140					if(call_desc[i].cdid != CDID_UNUSED) {
141						sendup++;
142						call_desc[i].cdid = CDID_UNUSED;
143					}
144				}
145			}
146
147			d->dl_est = DL_DOWN;
148
149			for (i = 0; i < d->nbch; i++)
150				d->bch_state[i] = BCH_ST_FREE;
151			d->tei = -1;
152
153			if(sendup)
154			{
155				i4b_l4_pdeact(d, sendup);
156			}
157			break;
158
159		case STI_NOL1ACC:	/* no outgoing access to S0 */
160			NDBGL3(L3_ERR, "STI_NOL1ACC: isdnif %d no outgoing access to S0", d->isdnif);
161			update_leds = 1;
162
163			for(i=0; i < num_call_desc; i++)
164			{
165				if(call_desc[i].isdnif == d->isdnif)
166                		{
167					if(call_desc[i].cdid != CDID_UNUSED)
168					{
169						SET_CAUSE_TYPE(call_desc[i].cause_in, CAUSET_I4B);
170						SET_CAUSE_VAL(call_desc[i].cause_in, CAUSE_I4B_L1ERROR);
171						i4b_l4_disconnect_ind(&(call_desc[i]));
172					}
173				}
174			}
175			d->dl_est = DL_DOWN;
176
177			for (i = 0; i < d->nbch; i++)
178				d->bch_state[i] = BCH_ST_FREE;
179			d->tei = -1;
180
181			break;
182
183		default:
184			NDBGL3(L3_ERR, "ERROR, isdnif %d, unknown status value %d!", d->isdnif, status);
185			break;
186	}
187
188	if (update_leds && d != NULL)
189		update_controller_leds(d);
190
191	return(0);
192}
193
194void
195update_controller_leds(struct isdn_l3_driver *d)
196{
197	intptr_t leds = 0;
198
199	if (d->tei != -1)
200		leds |= CMRLEDS_TEI;
201	if (d->bch_state[CHAN_B1] != BCH_ST_FREE)
202		leds |= CMRLEDS_B0;
203	if (d->bch_state[CHAN_B2] != BCH_ST_FREE)
204		leds |= CMRLEDS_B1;
205
206	d->l3driver->N_MGMT_COMMAND(d, CMR_SETLEDS, (void*)leds);
207}
208
209/*---------------------------------------------------------------------------*
210 *	send command to the lower layers
211 *---------------------------------------------------------------------------*/
212void
213n_mgmt_command(struct isdn_l3_driver *d, int cmd, void *parm)
214{
215	int i;
216
217	switch(cmd)
218	{
219		case CMR_DOPEN:
220			NDBGL3(L3_MSG, "CMR_DOPEN for isdnif %d", d->isdnif);
221
222			for(i=0; i < num_call_desc; i++)
223			{
224				if(call_desc[i].isdnif == d->isdnif)
225                		{
226                			call_desc[i].cdid = CDID_UNUSED;
227				}
228			}
229			d->dl_est = DL_DOWN;
230			for (i = 0; i < d->nbch; i++)
231				d->bch_state[i] = BCH_ST_FREE;
232			d->tei = -1;
233
234			break;
235
236		case CMR_DCLOSE:
237			NDBGL3(L3_MSG, "CMR_DCLOSE for isdnif %d", d->isdnif);
238			break;
239
240		default:
241			NDBGL3(L3_MSG, "unknown cmd %d for isdnif %d",
242			    cmd, d->isdnif);
243			break;
244	}
245
246	i4b_mdl_command_req(d, cmd, parm);
247}
248
249/*---------------------------------------------------------------------------*
250 *	handle connect request message from userland
251 *---------------------------------------------------------------------------*/
252void
253n_connect_request(struct call_desc *cd)
254{
255	next_l3state(cd, EV_SETUPRQ);
256}
257
258/*---------------------------------------------------------------------------*
259 *	handle setup response message from userland
260 *---------------------------------------------------------------------------*/
261void
262n_connect_response(struct call_desc *cd, int response, int cause)
263{
264	struct isdn_l3_driver *d = cd->l3drv;
265	int chstate;
266
267	T400_stop(cd);
268
269	cd->response = response;
270	cd->cause_out = cause;
271
272	switch(response)
273	{
274		case SETUP_RESP_ACCEPT:
275			next_l3state(cd, EV_SETACRS);
276			chstate = BCH_ST_USED;
277			break;
278
279		case SETUP_RESP_REJECT:
280			next_l3state(cd, EV_SETRJRS);
281			chstate = BCH_ST_FREE;
282			break;
283
284		case SETUP_RESP_DNTCRE:
285			next_l3state(cd, EV_SETDCRS);
286			chstate = BCH_ST_FREE;
287			break;
288
289		default:	/* failsafe */
290			next_l3state(cd, EV_SETDCRS);
291			chstate = BCH_ST_FREE;
292			NDBGL3(L3_ERR, "unknown response, doing SETUP_RESP_DNTCRE");
293			break;
294	}
295
296	if((cd->channelid >= 0) && (cd->channelid < d->nbch))
297	{
298		d->bch_state[cd->channelid] = chstate;
299		/*
300		 * XXX: don't call l2 function for active cards
301		 */
302		if (d->l3driver->N_DOWNLOAD == NULL)
303			i4b_l2_channel_set_state(cd->l3drv,
304			    cd->channelid, chstate);
305		update_controller_leds(d);
306	}
307	else
308	{
309		NDBGL3(L3_MSG, "Warning, invalid channelid %d, response = %d\n", cd->channelid, response);
310	}
311}
312
313/*---------------------------------------------------------------------------*
314 *	handle disconnect request message from userland
315 *---------------------------------------------------------------------------*/
316void
317n_disconnect_request(struct call_desc *cd, int cause)
318{
319	cd->cause_out = cause;
320
321	next_l3state(cd, EV_DISCRQ);
322}
323
324/*---------------------------------------------------------------------------*
325 *	handle alert request message from userland
326 *---------------------------------------------------------------------------*/
327void
328n_alert_request(struct call_desc *cd)
329{
330	next_l3state(cd, EV_ALERTRQ);
331}
332
333#endif /* NI4BQ931 > 0 */
334