1/* $NetBSD: i4b_l4mgmt.c,v 1.17 2007/07/09 21:11:14 ad 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.18 2010/01/18 16:37:41 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.17 2007/07/09 21:11:14 ad 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 83static unsigned int get_cdid(void); 84 85static void i4b_init_callout(call_desc_t *); 86static void i4b_stop_callout(call_desc_t *cd); 87 88call_desc_t call_desc[N_CALL_DESC]; /* call descriptor array */ 89int 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 *---------------------------------------------------------------------------*/ 98static unsigned int 99get_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 111again: 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 *---------------------------------------------------------------------------*/ 141call_desc_t * 142reserve_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 *---------------------------------------------------------------------------*/ 189void 190freecd_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 */ 216void 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 *---------------------------------------------------------------------------*/ 245call_desc_t * 246cd_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 *---------------------------------------------------------------------------*/ 270call_desc_t * 271cd_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 *---------------------------------------------------------------------------*/ 292unsigned char 293get_rand_cr(int unit) 294{ 295 register int i, j; 296 static u_char val, retval; 297 static int called = 42; 298 struct timeval t; 299 300 val += ++called; 301 302 for(i=0; i < 50 ; i++, val++) 303 { 304 int found = 1; 305 306#if defined(__FreeBSD__) 307 308#ifdef RANDOMDEV 309 read_random((char *)&val, sizeof(val)); 310#else 311 val = (u_char)random(); 312#endif /* RANDOMDEV */ 313 314#else 315 getmicrotime(&t); 316 val |= unit+i; 317 val <<= i; 318 val ^= (t.tv_sec >> 8) ^ t.tv_usec; 319 val <<= i; 320 val ^= t.tv_sec ^ (t.tv_usec >> 8); 321#endif 322 323 retval = val & 0x7f; 324 325 if(retval == 0 || retval == 0x7f) 326 continue; 327 328 for(j=0; j < num_call_desc; j++) 329 { 330 if( (call_desc[j].cdid != CDID_UNUSED) && 331 (call_desc[j].cr == retval) ) 332 { 333 found = 0; 334 break; 335 } 336 } 337 338 if(found) 339 return(retval); 340 } 341 return(0); /* XXX */ 342} 343 344static void 345i4b_stop_callout(call_desc_t *cd) 346{ 347 if (!cd->callouts_inited) 348 return; 349 350 callout_stop(&cd->idle_timeout_handle); 351 callout_stop(&cd->T303_callout); 352 callout_stop(&cd->T305_callout); 353 callout_stop(&cd->T308_callout); 354 callout_stop(&cd->T309_callout); 355 callout_stop(&cd->T310_callout); 356 callout_stop(&cd->T313_callout); 357 callout_stop(&cd->T400_callout); 358} 359 360/*---------------------------------------------------------------------------* 361 * initialize the callout handles for FreeBSD 362 *---------------------------------------------------------------------------*/ 363void 364i4b_init_callout(call_desc_t *cd) 365{ 366 if(cd->callouts_inited == 0) 367 { 368 callout_init(&cd->idle_timeout_handle, 0); 369 callout_init(&cd->T303_callout, 0); 370 callout_init(&cd->T305_callout, 0); 371 callout_init(&cd->T308_callout, 0); 372 callout_init(&cd->T309_callout, 0); 373 callout_init(&cd->T310_callout, 0); 374 callout_init(&cd->T313_callout, 0); 375 callout_init(&cd->T400_callout, 0); 376 cd->callouts_inited = 1; 377 } 378} 379 380#endif /* NISDN > 0 */ 381