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