Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / net / i4b / layer4 / i4b_l4mgmt.c
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_l4mgmt.c - layer 4 calldescriptor management utilites
28  *      -----------------------------------------------------------
29  *
30  *      $Id: i4b_l4mgmt.c,v 1.34 2000/09/01 14:11:51 hm Exp $ 
31  *
32  * $FreeBSD: src/sys/i4b/layer4/i4b_l4mgmt.c,v 1.6.2.2 2001/08/10 14:08:43 obrien Exp $
33  *
34  *      last edit-date: [Fri Oct 13 15:58:34 2000]
35  *
36  *---------------------------------------------------------------------------*/
37
38 #include "i4b.h"
39
40 #if NI4B > 0
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/mbuf.h>
45
46 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
47 #include <sys/callout.h>
48 #endif
49
50 #ifdef __FreeBSD__
51 #include <machine/i4b_debug.h>
52 #include <machine/i4b_ioctl.h>
53 #else
54 #include <i4b/i4b_debug.h>
55 #include <i4b/i4b_ioctl.h>
56 #endif
57
58 #include <i4b/include/i4b_l3l4.h>
59 #include <i4b/include/i4b_global.h>
60
61 #include <i4b/layer4/i4b_l4.h>
62
63 call_desc_t call_desc[N_CALL_DESC];     /* call descriptor array */
64
65 static unsigned int get_cdid(void);
66
67 int nctrl;                              /* number of attached controllers */
68
69 #if (defined(__NetBSD__) && __NetBSD_Version__ >= 104230000) || defined(__FreeBSD__)
70 void i4b_init_callout(call_desc_t *);
71 #endif
72
73 /*---------------------------------------------------------------------------*
74  *      return a new unique call descriptor id
75  *      --------------------------------------
76  *      returns a new calldescriptor id which is used to uniquely identyfy
77  *      a single call in the communication between kernel and userland.
78  *      this cdid is then used to associate a calldescriptor with an id.
79  *---------------------------------------------------------------------------*/
80 static unsigned int
81 get_cdid(void)
82 {
83         static unsigned int cdid_count = 0;
84         int i;
85         int x;
86
87         x = SPLI4B();   
88
89         /* get next id */
90         
91         cdid_count++;
92         
93 again:
94         if(cdid_count == CDID_UNUSED)           /* zero is invalid */
95                 cdid_count++;
96         else if(cdid_count > CDID_MAX)          /* wraparound ? */
97                 cdid_count = 1;
98
99         /* check if id already in use */
100         
101         for(i=0; i < N_CALL_DESC; i++)
102         {
103                 if(call_desc[i].cdid == cdid_count)
104                 {
105                         cdid_count++;
106                         goto again;
107                 }
108         }
109
110         splx(x);
111         
112         return(cdid_count);
113 }
114
115 /*---------------------------------------------------------------------------*
116  *      reserve a calldescriptor for later usage
117  *      ----------------------------------------
118  *      searches the calldescriptor array until an unused
119  *      descriptor is found, gets a new calldescriptor id
120  *      and reserves it by putting the id into the cdid field.
121  *      returns pointer to the calldescriptor.
122  *---------------------------------------------------------------------------*/
123 call_desc_t *
124 reserve_cd(void)
125 {
126         call_desc_t *cd;
127         int x;
128         int i;
129
130         x = SPLI4B();
131
132         cd = NULL;
133         
134         for(i=0; i < N_CALL_DESC; i++)
135         {
136                 if(call_desc[i].cdid == CDID_UNUSED)
137                 {
138                         bzero(&call_desc[i], sizeof(call_desc_t)); /* clear it */
139                         call_desc[i].cdid = get_cdid(); /* fill in new cdid */
140                         cd = &(call_desc[i]);   /* get pointer to descriptor */
141                         NDBGL4(L4_MSG, "found free cd - index=%d cdid=%u",
142                                  i, call_desc[i].cdid);
143                         break;
144                 }
145         }
146
147         splx(x);
148
149         if(cd == NULL)
150                 panic("reserve_cd: no free call descriptor available!");
151
152 #if (defined(__NetBSD__) && __NetBSD_Version__ >= 104230000) || defined(__FreeBSD__)
153         i4b_init_callout(cd);
154 #endif
155
156         return(cd);
157 }
158
159 /*---------------------------------------------------------------------------*
160  *      free a calldescriptor
161  *      ---------------------
162  *      free a unused calldescriptor by giving address of calldescriptor
163  *      and writing a 0 into the cdid field marking it as unused.
164  *---------------------------------------------------------------------------*/
165 void
166 freecd_by_cd(call_desc_t *cd)
167 {
168         int i;
169         int x = SPLI4B();
170         
171         for(i=0; i < N_CALL_DESC; i++)
172         {
173                 if( (call_desc[i].cdid != CDID_UNUSED) &&
174                     (&(call_desc[i]) == cd) )
175                 {
176                         NDBGL4(L4_MSG, "releasing cd - index=%d cdid=%u cr=%d",
177                                 i, call_desc[i].cdid, cd->cr);
178                         call_desc[i].cdid = CDID_UNUSED;
179                         break;
180                 }
181         }
182
183         if(i == N_CALL_DESC)
184                 panic("freecd_by_cd: ERROR, cd not found, cr = %d\n", cd->cr);
185
186         splx(x);                
187 }
188
189 /*---------------------------------------------------------------------------*
190  *      return pointer to calldescriptor by giving the calldescriptor id
191  *      ----------------------------------------------------------------
192  *      lookup a calldescriptor in the calldescriptor array by looking
193  *      at the cdid field. return pointer to calldescriptor if found,
194  *      else return NULL if not found.
195  *---------------------------------------------------------------------------*/
196 call_desc_t *
197 cd_by_cdid(unsigned int cdid)
198 {
199         int i;
200
201         for(i=0; i < N_CALL_DESC; i++)
202         {
203                 if(call_desc[i].cdid == cdid)
204                 {
205                         NDBGL4(L4_MSG, "found cdid - index=%d cdid=%u cr=%d",
206                                         i, call_desc[i].cdid, call_desc[i].cr);
207 #if (defined(__NetBSD__) && __NetBSD_Version__ >= 104230000) || defined(__FreeBSD__)
208                         i4b_init_callout(&call_desc[i]);
209 #endif
210                         return(&(call_desc[i]));
211                 }
212         }
213         return(NULL);
214 }
215
216 /*---------------------------------------------------------------------------*
217  *      search calldescriptor
218  *      ---------------------
219  *      This routine searches for the calldescriptor for a passive controller
220  *      given by unit number, callreference and callreference flag.
221  *      It returns a pointer to the calldescriptor if found, else a NULL.
222  *---------------------------------------------------------------------------*/
223 call_desc_t *
224 cd_by_unitcr(int unit, int cr, int crf)
225 {
226         int i;
227
228         for(i=0; i < N_CALL_DESC; i++)
229         {
230           if((call_desc[i].cdid != CDID_UNUSED)                                       &&
231              (ctrl_desc[call_desc[i].controller].ctrl_type == CTRL_PASSIVE) &&
232              (ctrl_desc[call_desc[i].controller].unit == unit)              &&
233              (call_desc[i].cr == cr)                                        &&
234              (call_desc[i].crflag == crf) )
235           {
236             NDBGL4(L4_MSG, "found cd, index=%d cdid=%u cr=%d",
237                         i, call_desc[i].cdid, call_desc[i].cr);
238 #if (defined(__NetBSD__) && __NetBSD_Version__ >= 104230000) || defined(__FreeBSD__)
239             i4b_init_callout(&call_desc[i]);
240 #endif
241             return(&(call_desc[i]));
242           }
243         }
244         return(NULL);
245 }
246
247 /*---------------------------------------------------------------------------*
248  *      generate 7 bit "random" number used for outgoing Call Reference
249  *---------------------------------------------------------------------------*/
250 unsigned char
251 get_rand_cr(int unit)
252 {
253         register int i, j;
254         static u_char val, retval;
255         static int called = 42;
256         
257         val += ++called;
258         
259         for(i=0; i < 50 ; i++, val++)
260         {
261                 int found = 1;
262                 
263 #if defined(__FreeBSD__)
264
265 #ifdef RANDOMDEV
266                 read_random((char *)&val, sizeof(val));
267 #else
268                 val = (u_char)random();
269 #endif /* RANDOMDEV */
270
271 #else
272                 val |= unit+i;
273                 val <<= i;
274                 val ^= (time.tv_sec >> 8) ^ time.tv_usec;
275                 val <<= i;
276                 val ^= time.tv_sec ^ (time.tv_usec >> 8);
277 #endif
278
279                 retval = val & 0x7f;
280                 
281                 if(retval == 0 || retval == 0x7f)
282                         continue;
283
284                 for(j=0; j < N_CALL_DESC; j++)
285                 {
286                         if( (call_desc[j].cdid != CDID_UNUSED) &&
287                             (call_desc[j].cr == retval) )
288                         {
289                                 found = 0;
290                                 break;
291                         }
292                 }
293
294                 if(found)
295                         return(retval);
296         }
297         return(0);      /* XXX */
298 }
299
300 /*---------------------------------------------------------------------------*
301  *      initialize the callout handles for FreeBSD
302  *---------------------------------------------------------------------------*/
303 #if (defined(__NetBSD__) && __NetBSD_Version__ >= 104230000) || defined(__FreeBSD__)
304 void
305 i4b_init_callout(call_desc_t *cd)
306 {
307         if(cd->callouts_inited == 0)
308         {
309 #ifdef __FreeBSD__
310                 callout_handle_init(&cd->idle_timeout_handle);
311                 callout_handle_init(&cd->T303_callout);
312                 callout_handle_init(&cd->T305_callout);
313                 callout_handle_init(&cd->T308_callout);
314                 callout_handle_init(&cd->T309_callout);
315                 callout_handle_init(&cd->T310_callout);
316                 callout_handle_init(&cd->T313_callout);
317                 callout_handle_init(&cd->T400_callout);
318 #else
319                 callout_init(&cd->idle_timeout_handle);
320                 callout_init(&cd->T303_callout);
321                 callout_init(&cd->T305_callout);
322                 callout_init(&cd->T308_callout);
323                 callout_init(&cd->T309_callout);
324                 callout_init(&cd->T310_callout);
325                 callout_init(&cd->T313_callout);
326                 callout_init(&cd->T400_callout);
327 #endif
328                 cd->callouts_inited = 1;
329         }
330 }
331 #endif
332
333 /*---------------------------------------------------------------------------*
334  *      daemon is attached
335  *---------------------------------------------------------------------------*/
336 void 
337 i4b_l4_daemon_attached(void)
338 {
339         int i;
340
341         int x = SPLI4B();
342         
343         for(i=0; i < nctrl; i++)
344         {
345 /*XXX*/         if(ctrl_desc[i].ctrl_type == CTRL_PASSIVE)
346                 {
347                         NDBGL4(L4_MSG, "CMR_DOPEN sent to unit %d", ctrl_desc[i].unit);
348                         (*ctrl_desc[i].N_MGMT_COMMAND)(ctrl_desc[i].unit, CMR_DOPEN, 0);
349                 }
350         }
351         splx(x);
352 }
353
354 /*---------------------------------------------------------------------------*
355  *      daemon is detached
356  *---------------------------------------------------------------------------*/
357 void 
358 i4b_l4_daemon_detached(void)
359 {
360         int i;
361
362         int x = SPLI4B();
363
364         for(i=0; i < nctrl; i++)
365         {
366 /*XXX*/         if(ctrl_desc[i].ctrl_type == CTRL_PASSIVE)
367                 {
368                         NDBGL4(L4_MSG, "CMR_DCLOSE sent to unit %d", ctrl_desc[i].unit);
369                         (*ctrl_desc[i].N_MGMT_COMMAND)(ctrl_desc[i].unit, CMR_DCLOSE, 0);
370                 }
371         }
372         splx(x);
373 }
374
375 #ifdef I4B_CD_DEBUG_PRINT
376
377 extern char *print_l3state(call_desc_t *cd);
378
379 void i4b_print_cdp(call_desc_t *cdp);
380 void i4b_print_cdx(int index);
381 void i4b_print_cda(void);
382 void i4b_print_cdaa(void);
383         
384 /*---------------------------------------------------------------------------*
385  *      print a call descriptor by cd-pointer
386  *---------------------------------------------------------------------------*/
387 void 
388 i4b_print_cdp(call_desc_t *cdp)
389 {
390         if((cdp > &(call_desc[N_CALL_DESC])) || (cdp < &(call_desc[0])))
391         {
392                 printf("i4b_print_cd: cdp out of range!\n");
393                 return;
394         }
395
396         printf("i4b_print_cd: printing call descriptor %d at 0x%lx:\n", cdp - (&(call_desc[0])), (unsigned long)cdp);
397
398         printf("         cdid = %d\n", cdp->cdid);
399         printf("   controller = %d (u=%d, dl=%d, b1=%d, b2=%d)\n",
400                         cdp->controller,
401                         ctrl_desc[cdp->controller].unit,
402                         ctrl_desc[cdp->controller].dl_est,
403                         ctrl_desc[cdp->controller].bch_state[CHAN_B1],
404                         ctrl_desc[cdp->controller].bch_state[CHAN_B2]); 
405         printf("           cr = 0x%02x\n", cdp->cr);
406         printf("       crflag = %d\n", cdp->crflag);
407         printf("    channelid = %d\n", cdp->channelid);
408         printf("        bprot = %d\n", cdp->bprot);
409         printf("       driver = %d\n", cdp->driver);
410         printf("  driver_unit = %d\n", cdp->driver_unit);
411         printf("   call_state = %d\n", cdp->call_state);
412         printf("    Q931state = %s\n", print_l3state(cdp));
413         printf("        event = %d\n", cdp->event);
414         printf("     response = %d\n", cdp->response);
415         printf("         T303 = %d\n", cdp->T303);
416         printf("T303_first_to = %d\n", cdp->T303_first_to);
417         printf("         T305 = %d\n", cdp->T305);
418         printf("         T308 = %d\n", cdp->T308);
419         printf("T308_first_to = %d\n", cdp->T308_first_to);
420         printf("         T309 = %d\n", cdp->T309);
421         printf("         T310 = %d\n", cdp->T310);
422         printf("         T313 = %d\n", cdp->T313);
423         printf("         T400 = %d\n", cdp->T400);
424         printf("          dir = %s\n", cdp->dir == DIR_OUTGOING ? "out" : "in");
425 }
426
427 /*---------------------------------------------------------------------------*
428  *      print a call descriptor by index
429  *---------------------------------------------------------------------------*/
430 void 
431 i4b_print_cdx(int index)
432 {
433         if(index >= N_CALL_DESC)
434         {
435                 printf("i4b_print_cdx: index %d >= N_CALL_DESC %d\n", index, N_CALL_DESC);
436                 return;
437         }
438         i4b_print_cdp(&(call_desc[index]));
439 }
440
441 /*---------------------------------------------------------------------------*
442  *      print all call descriptors
443  *---------------------------------------------------------------------------*/
444 void 
445 i4b_print_cda(void)
446 {
447         int i;
448
449         for(i=0; i < N_CALL_DESC; i++)
450         {
451                 i4b_print_cdp(&(call_desc[i]));
452         }
453 }
454
455 /*---------------------------------------------------------------------------*
456  *      print all active call descriptors
457  *---------------------------------------------------------------------------*/
458 void 
459 i4b_print_cdaa(void)
460 {
461         int i;
462
463         for(i=0; i < N_CALL_DESC; i++)
464         {
465                 if(call_desc[i].cdid != CDID_UNUSED)
466                 {
467                         i4b_print_cdp(&(call_desc[i]));
468                 }
469         }
470 }
471
472 #endif /* I4B_CD_DEBUG_PRINT */
473
474 #endif /* NI4BQ931 > 0 */