1 /**	$MirOS: src/sys/netisdn/i4b_l4mgmt.c,v 1.3 2006/10/17 20:48:53 tg Exp $	*/
2 /*	$NetBSD: i4b_l4mgmt.c,v 1.13 2003/10/03 16:38:44 pooka Exp $	*/
3 
4 /*
5  * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  *---------------------------------------------------------------------------
29  *
30  *	i4b_l4mgmt.c - layer 4 calldescriptor management utilites
31  *
32  *---------------------------------------------------------------------------*/
33 
34 #include <sys/cdefs.h>
35 
36 #include "isdn.h"
37 
38 #if NISDN > 0
39 
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/systm.h>
43 #include <sys/mbuf.h>
44 #include <sys/socket.h>
45 #include <net/if.h>
46 
47 #include <sys/timeout.h>
48 
49 #if defined(__FreeBSD__)
50 #if defined (__FreeBSD_version) && __FreeBSD_version <= 400000
51 #include <machine/random.h>
52 #else
53 #include <sys/random.h>
54 #endif
55 #elif defined(__OpenBSD__)
56 #include <dev/rndvar.h>
57 #endif
58 
59 #ifdef __FreeBSD__
60 #include <machine/i4b_debug.h>
61 #include <machine/i4b_ioctl.h>
62 #else
63 #include <netisdn/i4b_debug.h>
64 #include <netisdn/i4b_ioctl.h>
65 #endif
66 
67 #include <netisdn/i4b_l3l4.h>
68 #include <netisdn/i4b_mbuf.h>
69 #include <netisdn/i4b_isdnq931.h>
70 #include <netisdn/i4b_global.h>
71 
72 #include <netisdn/i4b_l2.h>
73 #include <netisdn/i4b_l1l2.h>
74 #include <netisdn/i4b_l4.h>
75 
76 static unsigned int get_cdid(void);
77 
78 static void i4b_init_callout(call_desc_t *);
79 static void i4b_stop_callout(call_desc_t *cd);
80 
81 call_desc_t call_desc[N_CALL_DESC];	/* call descriptor array */
82 int num_call_desc = 0;
83 
84 /*---------------------------------------------------------------------------*
85  *      return a new unique call descriptor id
86  *	--------------------------------------
87  *	returns a new calldescriptor id which is used to uniquely identyfy
88  *	a single call in the communication between kernel and userland.
89  *	this cdid is then used to associate a calldescriptor with an id.
90  *---------------------------------------------------------------------------*/
91 static unsigned int
get_cdid(void)92 get_cdid(void)
93 {
94 	static unsigned int cdid_count = 0;
95 	int i;
96 	int x;
97 
98 	x = splnet();
99 
100 	/* get next id */
101 
102 	cdid_count++;
103 
104 again:
105 	if(cdid_count == CDID_UNUSED)		/* zero is invalid */
106 		cdid_count++;
107 	else if(cdid_count > CDID_MAX)		/* wraparound ? */
108 		cdid_count = 1;
109 
110 	/* check if id already in use */
111 
112 	for(i=0; i < num_call_desc; i++)
113 	{
114 		if(call_desc[i].cdid == cdid_count)
115 		{
116 			cdid_count++;
117 			goto again;
118 		}
119 	}
120 
121 	splx(x);
122 
123 	return(cdid_count);
124 }
125 
126 /*---------------------------------------------------------------------------*
127  *      reserve a calldescriptor for later usage
128  *      ----------------------------------------
129  *      searches the calldescriptor array until an unused
130  *      descriptor is found, gets a new calldescriptor id
131  *      and reserves it by putting the id into the cdid field.
132  *      returns pointer to the calldescriptor.
133  *---------------------------------------------------------------------------*/
134 call_desc_t *
reserve_cd(void)135 reserve_cd(void)
136 {
137 	call_desc_t *cd;
138 	int x;
139 	int i;
140 
141 	x = splnet();
142 
143 	cd = NULL;
144 
145 	for(i=0; i < num_call_desc; i++)
146 	{
147 		if(call_desc[i].cdid == CDID_UNUSED)
148 		{
149 			cd = &(call_desc[i]);	/* get pointer to descriptor */
150 			NDBGL4(L4_MSG, "found free cd - index=%d cdid=%u",
151 				 i, call_desc[i].cdid);
152 			break;
153 		}
154 	}
155 	if (cd == NULL && num_call_desc < N_CALL_DESC) {
156 		i = num_call_desc++;
157 		cd = &(call_desc[i]);	/* get pointer to descriptor */
158 		NDBGL4(L4_MSG, "found free cd - index=%d cdid=%u",
159 			 i, call_desc[i].cdid);
160 	}
161 	if (cd != NULL) {
162 		memset(cd, 0, sizeof(call_desc_t)); /* clear it */
163 		cd->cdid = get_cdid();	/* fill in new cdid */
164 	}
165 
166 	splx(x);
167 
168 	if(cd == NULL)
169 		panic("reserve_cd: no free call descriptor available!");
170 
171 	i4b_init_callout(cd);
172 
173 	return(cd);
174 }
175 
176 /*---------------------------------------------------------------------------*
177  *      free a calldescriptor
178  *      ---------------------
179  *      free a unused calldescriptor by giving address of calldescriptor
180  *      and writing a 0 into the cdid field marking it as unused.
181  *---------------------------------------------------------------------------*/
182 void
freecd_by_cd(call_desc_t * cd)183 freecd_by_cd(call_desc_t *cd)
184 {
185 	int i;
186 	int x = splnet();
187 
188 	for(i=0; i < num_call_desc; i++)
189 	{
190 		if( (call_desc[i].cdid != CDID_UNUSED) &&
191 		    (&(call_desc[i]) == cd) )
192 		{
193 			NDBGL4(L4_MSG, "releasing cd - index=%d cdid=%u cr=%d",
194 				i, call_desc[i].cdid, cd->cr);
195 			call_desc[i].cdid = CDID_UNUSED;
196 			break;
197 		}
198 	}
199 
200 	if(i == N_CALL_DESC)
201 		panic("freecd_by_cd: ERROR, cd not found, cr = %d", cd->cr);
202 
203 	splx(x);
204 }
205 
206 /*
207  * ISDN is gone, get rid of all CDs for it
208  */
free_all_cd_of_isdnif(int isdnif)209 void free_all_cd_of_isdnif(int isdnif)
210 {
211 	int i;
212 	int x = splnet();
213 
214 	for(i=0; i < num_call_desc; i++)
215 	{
216 		if( (call_desc[i].cdid != CDID_UNUSED) &&
217 		    call_desc[i].isdnif == isdnif) {
218 			NDBGL4(L4_MSG, "releasing cd - index=%d cdid=%u cr=%d",
219 				i, call_desc[i].cdid, call_desc[i].cr);
220 			if (call_desc[i].callouts_inited)
221 				i4b_stop_callout(&call_desc[i]);
222 			call_desc[i].cdid = CDID_UNUSED;
223 			call_desc[i].isdnif = -1;
224 			call_desc[i].l3drv = NULL;
225 		}
226 	}
227 
228 	splx(x);
229 }
230 
231 /*---------------------------------------------------------------------------*
232  *      return pointer to calldescriptor by giving the calldescriptor id
233  *      ----------------------------------------------------------------
234  *      lookup a calldescriptor in the calldescriptor array by looking
235  *      at the cdid field. return pointer to calldescriptor if found,
236  *      else return NULL if not found.
237  *---------------------------------------------------------------------------*/
238 call_desc_t *
cd_by_cdid(unsigned int cdid)239 cd_by_cdid(unsigned int cdid)
240 {
241 	int i;
242 
243 	for(i=0; i < num_call_desc; i++)
244 	{
245 		if(call_desc[i].cdid == cdid)
246 		{
247 			NDBGL4(L4_MSG, "found cdid - index=%d cdid=%u cr=%d",
248 					i, call_desc[i].cdid, call_desc[i].cr);
249 			i4b_init_callout(&call_desc[i]);
250 			return(&(call_desc[i]));
251 		}
252 	}
253 	return(NULL);
254 }
255 
256 /*---------------------------------------------------------------------------*
257  *      search calldescriptor
258  *      ---------------------
259  *      This routine searches for the calldescriptor for a passive controller
260  *      given by unit number, callreference and callreference flag.
261  *	It returns a pointer to the calldescriptor if found, else a NULL.
262  *---------------------------------------------------------------------------*/
263 call_desc_t *
cd_by_isdnifcr(int isdnif,int cr,int crf)264 cd_by_isdnifcr(int isdnif, int cr, int crf)
265 {
266 	int i;
267 
268 	for(i=0; i < num_call_desc; i++) {
269 		if (call_desc[i].cdid != CDID_UNUSED
270 		    && call_desc[i].isdnif == isdnif
271 		    && call_desc[i].cr == cr
272 		    && call_desc[i].crflag == crf) {
273 			NDBGL4(L4_MSG, "found cd, index=%d cdid=%u cr=%d",
274 			    i, call_desc[i].cdid, call_desc[i].cr);
275 			i4b_init_callout(&call_desc[i]);
276 			return(&(call_desc[i]));
277 		}
278 	}
279 	return(NULL);
280 }
281 
282 /*---------------------------------------------------------------------------*
283  *	generate 7 bit "random" number used for outgoing Call Reference
284  *---------------------------------------------------------------------------*/
285 unsigned char
get_rand_cr(int unit)286 get_rand_cr(int unit)
287 {
288 	register int i, j;
289 	static u_char val, retval;
290 	static int called = 42;
291 
292 	val += ++called;
293 
294 	for(i=0; i < 50 ; i++, val++)
295 	{
296 		int found = 1;
297 
298 #if defined(__OpenBSD__)
299 		get_random_bytes((void *)&val, sizeof (val));
300 #elif defined(__FreeBSD__)
301 
302 #ifdef RANDOMDEV
303 		read_random((char *)&val, sizeof(val));
304 #else
305 		val = (u_char)random();
306 #endif /* RANDOMDEV */
307 
308 #else
309 		val |= unit+i;
310 		val <<= i;
311 		val ^= (time.tv_sec >> 8) ^ time.tv_usec;
312 		val <<= i;
313 		val ^= time.tv_sec ^ (time.tv_usec >> 8);
314 #endif
315 
316 		retval = val & 0x7f;
317 
318 		if(retval == 0 || retval == 0x7f)
319 			continue;
320 
321 		for(j=0; j < num_call_desc; j++)
322 		{
323 			if( (call_desc[j].cdid != CDID_UNUSED) &&
324 			    (call_desc[j].cr == retval) )
325 			{
326 				found = 0;
327 				break;
328 			}
329 		}
330 
331 		if(found)
332 			return(retval);
333 	}
334 	return(0);	/* XXX */
335 }
336 
337 static void
i4b_stop_callout(call_desc_t * cd)338 i4b_stop_callout(call_desc_t *cd)
339 {
340 	if (!cd->callouts_inited)
341 		return;
342 
343 	timeout_del(&cd->idle_timeout_handle);
344 	timeout_del(&cd->T303_callout);
345 	timeout_del(&cd->T305_callout);
346 	timeout_del(&cd->T308_callout);
347 	timeout_del(&cd->T309_callout);
348 	timeout_del(&cd->T310_callout);
349 	timeout_del(&cd->T313_callout);
350 	timeout_del(&cd->T400_callout);
351 }
352 
353 /*---------------------------------------------------------------------------*
354  *	initialize the callout handles for FreeBSD
355  *---------------------------------------------------------------------------*/
356 void
i4b_init_callout(call_desc_t * cd)357 i4b_init_callout(call_desc_t *cd)
358 {
359 	/* callout_init() translates to a NOP for OpenBSD */
360 }
361 
362 #ifdef I4B_CD_DEBUG_PRINT
363 
364 extern char *print_l3state(call_desc_t *cd);
365 
366 void i4b_print_cdp(call_desc_t *cdp);
367 void i4b_print_cdx(int index);
368 void i4b_print_cda(void);
369 void i4b_print_cdaa(void);
370 
371 /*---------------------------------------------------------------------------*
372  *	print a call descriptor by cd-pointer
373  *---------------------------------------------------------------------------*/
374 void
i4b_print_cdp(call_desc_t * cdp)375 i4b_print_cdp(call_desc_t *cdp)
376 {
377 	if((cdp > &(call_desc[num_call_desc])) || (cdp < &(call_desc[0])))
378 	{
379 		printf("i4b_print_cd: cdp out of range!\n");
380 		return;
381 	}
382 
383 	printf("i4b_print_cd: printing call descriptor %d at 0x%lx:\n", cdp - (&(call_desc[0])), (unsigned long)cdp);
384 
385 	printf("         cdid = %d\n", cdp->cdid);
386 	printf("   controller = %d (u=%d, dl=%d, b1=%d, b2=%d)\n",
387 			cdp->controller,
388 			ctrl_desc[cdp->controller].unit,
389 			ctrl_desc[cdp->controller].dl_est,
390 			ctrl_desc[cdp->controller].bch_state[CHAN_B1],
391 			ctrl_desc[cdp->controller].bch_state[CHAN_B2]);
392 	printf("           cr = 0x%02x\n", cdp->cr);
393 	printf("       crflag = %d\n", cdp->crflag);
394 	printf("    channelid = %d\n", cdp->channelid);
395 	printf("        bprot = %d\n", cdp->bprot);
396 	printf("       driver = %d\n", cdp->driver);
397 	printf("  driver_unit = %d\n", cdp->driver_unit);
398 	printf("   call_state = %d\n", cdp->call_state);
399 	printf("    Q931state = %s\n", print_l3state(cdp));
400 	printf("        event = %d\n", cdp->event);
401 	printf("     response = %d\n", cdp->response);
402 	printf("         T303 = %d\n", cdp->T303);
403 	printf("T303_first_to = %d\n", cdp->T303_first_to);
404 	printf("         T305 = %d\n", cdp->T305);
405 	printf("         T308 = %d\n", cdp->T308);
406 	printf("T308_first_to = %d\n", cdp->T308_first_to);
407 	printf("         T309 = %d\n", cdp->T309);
408 	printf("         T310 = %d\n", cdp->T310);
409 	printf("         T313 = %d\n", cdp->T313);
410 	printf("         T400 = %d\n", cdp->T400);
411 	printf("          dir = %s\n", cdp->dir == DIR_OUTGOING ? "out" : "in");
412 }
413 
414 /*---------------------------------------------------------------------------*
415  *	print a call descriptor by index
416  *---------------------------------------------------------------------------*/
417 void
i4b_print_cdx(int index)418 i4b_print_cdx(int index)
419 {
420 	if(index >= num_call_desc)
421 	{
422 		printf("i4b_print_cdx: index %d >= N_CALL_DESC %d\n", index, N_CALL_DESC);
423 		return;
424 	}
425 	i4b_print_cdp(&(call_desc[index]));
426 }
427 
428 /*---------------------------------------------------------------------------*
429  *	print all call descriptors
430  *---------------------------------------------------------------------------*/
431 void
i4b_print_cda(void)432 i4b_print_cda(void)
433 {
434 	int i;
435 
436 	for(i=0; i < num_call_desc; i++)
437 	{
438 		i4b_print_cdp(&(call_desc[i]));
439 	}
440 }
441 
442 /*---------------------------------------------------------------------------*
443  *	print all active call descriptors
444  *---------------------------------------------------------------------------*/
445 void
i4b_print_cdaa(void)446 i4b_print_cdaa(void)
447 {
448 	int i;
449 
450 	for(i=0; i < num_call_desc; i++)
451 	{
452 		if(call_desc[i].cdid != CDID_UNUSED)
453 		{
454 			i4b_print_cdp(&(call_desc[i]));
455 		}
456 	}
457 }
458 
459 #endif /* I4B_CD_DEBUG_PRINT */
460 
461 #endif /* NISDN > 0 */
462