| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* $Id: l3ni1.c,v 2.8.2.3 2004/01/13 14:31:25 keil Exp $ | 
 | 2 |  * | 
 | 3 |  * NI1 D-channel protocol | 
 | 4 |  * | 
 | 5 |  * Author       Matt Henderson & Guy Ellis | 
 | 6 |  * Copyright    by Traverse Technologies Pty Ltd, www.travers.com.au | 
 | 7 |  *  | 
 | 8 |  * This software may be used and distributed according to the terms | 
 | 9 |  * of the GNU General Public License, incorporated herein by reference. | 
 | 10 |  * | 
 | 11 |  * 2000.6.6 Initial implementation of routines for US NI1  | 
 | 12 |  * Layer 3 protocol based on the EURO/DSS1 D-channel protocol  | 
 | 13 |  * driver written by Karsten Keil et al.   | 
 | 14 |  * NI-1 Hall of Fame - Thanks to....  | 
 | 15 |  * Ragnar Paulson - for some handy code fragments | 
 | 16 |  * Will Scales - beta tester extraordinaire | 
 | 17 |  * Brett Whittacre - beta tester and remote devel system in Vegas | 
 | 18 |  * | 
 | 19 |  */ | 
 | 20 |  | 
 | 21 | #include "hisax.h" | 
 | 22 | #include "isdnl3.h" | 
 | 23 | #include "l3ni1.h" | 
 | 24 | #include <linux/ctype.h> | 
| Tejun Heo | 5a0e3ad | 2010-03-24 17:04:11 +0900 | [diff] [blame] | 25 | #include <linux/slab.h> | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 26 |  | 
 | 27 | extern char *HiSax_getrev(const char *revision); | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 28 | static const char *ni1_revision = "$Revision: 2.8.2.3 $"; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 29 |  | 
 | 30 | #define EXT_BEARER_CAPS 1 | 
 | 31 |  | 
 | 32 | #define	MsgHead(ptr, cref, mty) \ | 
 | 33 | 	*ptr++ = 0x8; \ | 
 | 34 | 	if (cref == -1) { \ | 
 | 35 | 		*ptr++ = 0x0; \ | 
 | 36 | 	} else { \ | 
 | 37 | 		*ptr++ = 0x1; \ | 
 | 38 | 		*ptr++ = cref^0x80; \ | 
 | 39 | 	} \ | 
 | 40 | 	*ptr++ = mty | 
 | 41 |  | 
 | 42 |  | 
 | 43 | /**********************************************/ | 
 | 44 | /* get a new invoke id for remote operations. */ | 
 | 45 | /* Only a return value != 0 is valid          */ | 
 | 46 | /**********************************************/ | 
 | 47 | static unsigned char new_invoke_id(struct PStack *p) | 
 | 48 | { | 
 | 49 | 	unsigned char retval; | 
 | 50 | 	int i; | 
 | 51 |    | 
 | 52 | 	i = 32; /* maximum search depth */ | 
 | 53 |  | 
 | 54 | 	retval = p->prot.ni1.last_invoke_id + 1; /* try new id */ | 
 | 55 | 	while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) { | 
 | 56 | 		p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8; | 
 | 57 | 		i--; | 
 | 58 | 	}   | 
 | 59 | 	if (i) { | 
 | 60 | 		while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7))) | 
 | 61 | 		retval++;  | 
 | 62 | 	} else | 
 | 63 | 		retval = 0; | 
 | 64 | 	p->prot.ni1.last_invoke_id = retval; | 
 | 65 | 	p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7)); | 
 | 66 | 	return(retval);   | 
 | 67 | } /* new_invoke_id */ | 
 | 68 |  | 
 | 69 | /*************************/ | 
 | 70 | /* free a used invoke id */ | 
 | 71 | /*************************/ | 
 | 72 | static void free_invoke_id(struct PStack *p, unsigned char id) | 
 | 73 | { | 
 | 74 |  | 
 | 75 |   if (!id) return; /* 0 = invalid value */ | 
 | 76 |  | 
 | 77 |   p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7)); | 
 | 78 | } /* free_invoke_id */   | 
 | 79 |  | 
 | 80 |  | 
 | 81 | /**********************************************************/ | 
 | 82 | /* create a new l3 process and fill in ni1 specific data */ | 
 | 83 | /**********************************************************/ | 
 | 84 | static struct l3_process | 
 | 85 | *ni1_new_l3_process(struct PStack *st, int cr) | 
 | 86 | {  struct l3_process *proc; | 
 | 87 |  | 
 | 88 |    if (!(proc = new_l3_process(st, cr)))  | 
 | 89 |      return(NULL); | 
 | 90 |  | 
 | 91 |    proc->prot.ni1.invoke_id = 0; | 
 | 92 |    proc->prot.ni1.remote_operation = 0; | 
 | 93 |    proc->prot.ni1.uus1_data[0] = '\0'; | 
 | 94 |     | 
 | 95 |    return(proc); | 
 | 96 | } /* ni1_new_l3_process */ | 
 | 97 |  | 
 | 98 | /************************************************/ | 
 | 99 | /* free a l3 process and all ni1 specific data */ | 
 | 100 | /************************************************/  | 
 | 101 | static void | 
 | 102 | ni1_release_l3_process(struct l3_process *p) | 
 | 103 | { | 
 | 104 |    free_invoke_id(p->st,p->prot.ni1.invoke_id); | 
 | 105 |    release_l3_process(p); | 
 | 106 | } /* ni1_release_l3_process */ | 
 | 107 |   | 
 | 108 | /********************************************************/ | 
 | 109 | /* search a process with invoke id id and dummy callref */ | 
 | 110 | /********************************************************/ | 
 | 111 | static struct l3_process * | 
 | 112 | l3ni1_search_dummy_proc(struct PStack *st, int id) | 
 | 113 | { struct l3_process *pc = st->l3.proc; /* start of processes */ | 
 | 114 |  | 
 | 115 |   if (!id) return(NULL); | 
 | 116 |  | 
 | 117 |   while (pc) | 
 | 118 |    { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id)) | 
 | 119 |        return(pc); | 
 | 120 |      pc = pc->next; | 
 | 121 |    }  | 
 | 122 |   return(NULL); | 
 | 123 | } /* l3ni1_search_dummy_proc */ | 
 | 124 |  | 
 | 125 | /*******************************************************************/ | 
 | 126 | /* called when a facility message with a dummy callref is received */ | 
 | 127 | /* and a return result is delivered. id specifies the invoke id.   */ | 
 | 128 | /*******************************************************************/  | 
 | 129 | static void  | 
 | 130 | l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen) | 
 | 131 | { isdn_ctrl ic; | 
 | 132 |   struct IsdnCardState *cs; | 
 | 133 |   struct l3_process *pc = NULL;  | 
 | 134 |  | 
 | 135 |   if ((pc = l3ni1_search_dummy_proc(st, id))) | 
 | 136 |    { L3DelTimer(&pc->timer); /* remove timer */ | 
 | 137 |  | 
 | 138 |      cs = pc->st->l1.hardware; | 
 | 139 |      ic.driver = cs->myid; | 
 | 140 |      ic.command = ISDN_STAT_PROT; | 
 | 141 |      ic.arg = NI1_STAT_INVOKE_RES; | 
 | 142 |      ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; | 
 | 143 |      ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; | 
 | 144 |      ic.parm.ni1_io.proc = pc->prot.ni1.proc; | 
 | 145 |      ic.parm.ni1_io.timeout= 0; | 
 | 146 |      ic.parm.ni1_io.datalen = nlen; | 
 | 147 |      ic.parm.ni1_io.data = p; | 
 | 148 |      free_invoke_id(pc->st, pc->prot.ni1.invoke_id); | 
 | 149 |      pc->prot.ni1.invoke_id = 0; /* reset id */ | 
 | 150 |  | 
 | 151 |      cs->iif.statcallb(&ic); | 
 | 152 |      ni1_release_l3_process(pc);  | 
 | 153 |    } | 
 | 154 |   else | 
 | 155 |    l3_debug(st, "dummy return result id=0x%x result len=%d",id,nlen); | 
 | 156 | } /* l3ni1_dummy_return_result */ | 
 | 157 |  | 
 | 158 | /*******************************************************************/ | 
 | 159 | /* called when a facility message with a dummy callref is received */ | 
 | 160 | /* and a return error is delivered. id specifies the invoke id.    */ | 
 | 161 | /*******************************************************************/  | 
 | 162 | static void  | 
 | 163 | l3ni1_dummy_error_return(struct PStack *st, int id, ulong error) | 
 | 164 | { isdn_ctrl ic; | 
 | 165 |   struct IsdnCardState *cs; | 
 | 166 |   struct l3_process *pc = NULL;  | 
 | 167 |  | 
 | 168 |   if ((pc = l3ni1_search_dummy_proc(st, id))) | 
 | 169 |    { L3DelTimer(&pc->timer); /* remove timer */ | 
 | 170 |  | 
 | 171 |      cs = pc->st->l1.hardware; | 
 | 172 |      ic.driver = cs->myid; | 
 | 173 |      ic.command = ISDN_STAT_PROT; | 
 | 174 |      ic.arg = NI1_STAT_INVOKE_ERR; | 
 | 175 |      ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; | 
 | 176 |      ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; | 
 | 177 |      ic.parm.ni1_io.proc = pc->prot.ni1.proc; | 
 | 178 |      ic.parm.ni1_io.timeout= error; | 
 | 179 |      ic.parm.ni1_io.datalen = 0; | 
 | 180 |      ic.parm.ni1_io.data = NULL; | 
 | 181 |      free_invoke_id(pc->st, pc->prot.ni1.invoke_id); | 
 | 182 |      pc->prot.ni1.invoke_id = 0; /* reset id */ | 
 | 183 |  | 
 | 184 |      cs->iif.statcallb(&ic); | 
 | 185 |      ni1_release_l3_process(pc);  | 
 | 186 |    } | 
 | 187 |   else | 
 | 188 |    l3_debug(st, "dummy return error id=0x%x error=0x%lx",id,error); | 
 | 189 | } /* l3ni1_error_return */ | 
 | 190 |  | 
 | 191 | /*******************************************************************/ | 
 | 192 | /* called when a facility message with a dummy callref is received */ | 
 | 193 | /* and a invoke is delivered. id specifies the invoke id.          */ | 
 | 194 | /*******************************************************************/  | 
 | 195 | static void  | 
 | 196 | l3ni1_dummy_invoke(struct PStack *st, int cr, int id,  | 
 | 197 |                     int ident, u_char *p, u_char nlen) | 
 | 198 | { isdn_ctrl ic; | 
 | 199 |   struct IsdnCardState *cs; | 
 | 200 |  | 
 | 201 |   l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d", | 
 | 202 |                (cr == -1) ? "local" : "broadcast",id,ident,nlen); | 
 | 203 |   if (cr >= -1) return; /* ignore local data */ | 
 | 204 |  | 
 | 205 |   cs = st->l1.hardware; | 
 | 206 |   ic.driver = cs->myid; | 
 | 207 |   ic.command = ISDN_STAT_PROT; | 
 | 208 |   ic.arg = NI1_STAT_INVOKE_BRD; | 
 | 209 |   ic.parm.ni1_io.hl_id = id; | 
 | 210 |   ic.parm.ni1_io.ll_id = 0; | 
 | 211 |   ic.parm.ni1_io.proc = ident; | 
 | 212 |   ic.parm.ni1_io.timeout= 0; | 
 | 213 |   ic.parm.ni1_io.datalen = nlen; | 
 | 214 |   ic.parm.ni1_io.data = p; | 
 | 215 |  | 
 | 216 |   cs->iif.statcallb(&ic); | 
 | 217 | } /* l3ni1_dummy_invoke */ | 
 | 218 |  | 
 | 219 | static void | 
 | 220 | l3ni1_parse_facility(struct PStack *st, struct l3_process *pc, | 
 | 221 |                       int cr, u_char * p) | 
 | 222 | { | 
 | 223 | 	int qd_len = 0; | 
 | 224 | 	unsigned char nlen = 0, ilen, cp_tag; | 
 | 225 | 	int ident, id; | 
 | 226 | 	ulong err_ret; | 
 | 227 |  | 
 | 228 | 	if (pc)  | 
 | 229 | 		st = pc->st; /* valid Stack */ | 
 | 230 | 	else | 
 | 231 | 		if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */ | 
 | 232 |  | 
 | 233 | 	p++; | 
 | 234 | 	qd_len = *p++; | 
 | 235 | 	if (qd_len == 0) { | 
 | 236 | 		l3_debug(st, "qd_len == 0"); | 
 | 237 | 		return; | 
 | 238 | 	} | 
 | 239 | 	if ((*p & 0x1F) != 0x11) {	/* Service discriminator, supplementary service */ | 
 | 240 | 		l3_debug(st, "supplementary service != 0x11"); | 
 | 241 | 		return; | 
 | 242 | 	} | 
 | 243 | 	while (qd_len > 0 && !(*p & 0x80)) {	/* extension ? */ | 
 | 244 | 		p++; | 
 | 245 | 		qd_len--; | 
 | 246 | 	} | 
 | 247 | 	if (qd_len < 2) { | 
 | 248 | 		l3_debug(st, "qd_len < 2"); | 
 | 249 | 		return; | 
 | 250 | 	} | 
 | 251 | 	p++; | 
 | 252 | 	qd_len--; | 
 | 253 | 	if ((*p & 0xE0) != 0xA0) {	/* class and form */ | 
 | 254 | 		l3_debug(st, "class and form != 0xA0"); | 
 | 255 | 		return; | 
 | 256 | 	} | 
 | 257 |         | 
 | 258 |         cp_tag = *p & 0x1F; /* remember tag value */ | 
 | 259 |  | 
 | 260 |         p++; | 
 | 261 | 	qd_len--; | 
 | 262 | 	if (qd_len < 1)  | 
 | 263 |           { l3_debug(st, "qd_len < 1"); | 
 | 264 | 	    return; | 
 | 265 | 	  } | 
 | 266 | 	if (*p & 0x80)  | 
 | 267 |           { /* length format indefinite or limited */ | 
 | 268 | 	    nlen = *p++ & 0x7F; /* number of len bytes or indefinite */ | 
 | 269 |             if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) || | 
 | 270 |                 (nlen > 1))    | 
 | 271 | 	     { l3_debug(st, "length format error or not implemented"); | 
 | 272 | 	       return; | 
 | 273 |              } | 
 | 274 |             if (nlen == 1) | 
 | 275 | 	     { nlen = *p++; /* complete length */ | 
 | 276 |                qd_len--; | 
 | 277 |              }  | 
 | 278 |             else | 
 | 279 | 	     { qd_len -= 2; /* trailing null bytes */ | 
 | 280 |                if ((*(p+qd_len)) || (*(p+qd_len+1))) | 
 | 281 | 		{ l3_debug(st,"length format indefinite error"); | 
 | 282 |                   return; | 
 | 283 |                 } | 
 | 284 |                nlen = qd_len; | 
 | 285 |              } | 
 | 286 | 	  } | 
 | 287 |         else | 
 | 288 | 	  { nlen = *p++; | 
 | 289 | 	    qd_len--; | 
 | 290 |           }  | 
 | 291 | 	if (qd_len < nlen)  | 
 | 292 |           { l3_debug(st, "qd_len < nlen"); | 
 | 293 | 	    return; | 
 | 294 | 	  } | 
 | 295 | 	qd_len -= nlen; | 
 | 296 |  | 
 | 297 | 	if (nlen < 2)  | 
 | 298 |           { l3_debug(st, "nlen < 2"); | 
 | 299 | 	    return; | 
 | 300 | 	  } | 
 | 301 |         if (*p != 0x02)  | 
 | 302 |           {  /* invoke identifier tag */ | 
 | 303 | 	     l3_debug(st, "invoke identifier tag !=0x02"); | 
 | 304 | 	     return; | 
 | 305 | 	  } | 
 | 306 | 	p++; | 
 | 307 | 	nlen--; | 
 | 308 | 	if (*p & 0x80)  | 
 | 309 |           { /* length format */ | 
 | 310 | 	    l3_debug(st, "invoke id length format 2"); | 
 | 311 | 	    return; | 
 | 312 | 	  } | 
 | 313 | 	ilen = *p++; | 
 | 314 | 	nlen--; | 
 | 315 | 	if (ilen > nlen || ilen == 0)  | 
 | 316 |           { l3_debug(st, "ilen > nlen || ilen == 0"); | 
 | 317 | 	    return; | 
 | 318 | 	  } | 
 | 319 | 	nlen -= ilen; | 
 | 320 | 	id = 0; | 
 | 321 | 	while (ilen > 0)  | 
 | 322 |           { id = (id << 8) | (*p++ & 0xFF);	/* invoke identifier */ | 
 | 323 | 	    ilen--; | 
 | 324 | 	  } | 
 | 325 |  | 
 | 326 | 	switch (cp_tag) {	/* component tag */ | 
 | 327 | 		case 1:	/* invoke */ | 
 | 328 | 				if (nlen < 2) { | 
 | 329 | 					l3_debug(st, "nlen < 2 22"); | 
 | 330 | 					return; | 
 | 331 | 				} | 
 | 332 | 				if (*p != 0x02) {	/* operation value */ | 
 | 333 | 					l3_debug(st, "operation value !=0x02"); | 
 | 334 | 					return; | 
 | 335 | 				} | 
 | 336 | 				p++; | 
 | 337 | 				nlen--; | 
 | 338 | 				ilen = *p++; | 
 | 339 | 				nlen--; | 
 | 340 | 				if (ilen > nlen || ilen == 0) { | 
 | 341 | 					l3_debug(st, "ilen > nlen || ilen == 0 22"); | 
 | 342 | 					return; | 
 | 343 | 				} | 
 | 344 | 				nlen -= ilen; | 
 | 345 | 				ident = 0; | 
 | 346 | 				while (ilen > 0) { | 
 | 347 | 					ident = (ident << 8) | (*p++ & 0xFF); | 
 | 348 | 					ilen--; | 
 | 349 | 				} | 
 | 350 |  | 
 | 351 | 				if (!pc)  | 
 | 352 | 				{ | 
 | 353 | 					l3ni1_dummy_invoke(st, cr, id, ident, p, nlen); | 
 | 354 | 					return; | 
 | 355 | 				}  | 
 | 356 | 				l3_debug(st, "invoke break"); | 
 | 357 | 				break; | 
 | 358 | 		case 2:	/* return result */ | 
 | 359 | 			 /* if no process available handle separately */  | 
 | 360 |                         if (!pc) | 
 | 361 | 			 { if (cr == -1)  | 
 | 362 |                              l3ni1_dummy_return_result(st, id, p, nlen); | 
 | 363 |                            return;  | 
 | 364 |                          }    | 
 | 365 |                         if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) | 
 | 366 |                           { /* Diversion successful */ | 
 | 367 |                             free_invoke_id(st,pc->prot.ni1.invoke_id); | 
 | 368 |                             pc->prot.ni1.remote_result = 0; /* success */      | 
 | 369 |                             pc->prot.ni1.invoke_id = 0; | 
 | 370 |                             pc->redir_result = pc->prot.ni1.remote_result;  | 
 | 371 |                             st->l3.l3l4(st, CC_REDIR | INDICATION, pc);                                  } /* Diversion successful */ | 
 | 372 |                         else | 
 | 373 |                           l3_debug(st,"return error unknown identifier"); | 
 | 374 | 			break; | 
 | 375 | 		case 3:	/* return error */ | 
 | 376 |                             err_ret = 0; | 
 | 377 | 	                    if (nlen < 2)  | 
 | 378 |                               { l3_debug(st, "return error nlen < 2"); | 
 | 379 | 	                        return; | 
 | 380 | 	                      } | 
 | 381 |                             if (*p != 0x02)  | 
 | 382 |                               { /* result tag */ | 
 | 383 | 	                        l3_debug(st, "invoke error tag !=0x02"); | 
 | 384 | 	                        return; | 
 | 385 | 	                      } | 
 | 386 | 	                    p++; | 
 | 387 | 	                    nlen--; | 
 | 388 | 	                    if (*p > 4)  | 
 | 389 |                               { /* length format */ | 
 | 390 | 	                        l3_debug(st, "invoke return errlen > 4 "); | 
 | 391 | 	                        return; | 
 | 392 | 	                      } | 
 | 393 | 	                    ilen = *p++; | 
 | 394 | 	                    nlen--; | 
 | 395 | 	                    if (ilen > nlen || ilen == 0)  | 
 | 396 |                               { l3_debug(st, "error return ilen > nlen || ilen == 0"); | 
 | 397 | 	                        return; | 
 | 398 | 	                       } | 
 | 399 | 	                    nlen -= ilen; | 
 | 400 | 	                    while (ilen > 0)  | 
 | 401 |                              { err_ret = (err_ret << 8) | (*p++ & 0xFF);	/* error value */ | 
 | 402 | 	                       ilen--; | 
 | 403 | 	                     } | 
 | 404 | 			 /* if no process available handle separately */  | 
 | 405 |                         if (!pc) | 
 | 406 | 			 { if (cr == -1) | 
 | 407 |                              l3ni1_dummy_error_return(st, id, err_ret); | 
 | 408 |                            return;  | 
 | 409 |                          }    | 
 | 410 |                         if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id)) | 
 | 411 |                           { /* Deflection error */ | 
 | 412 |                             free_invoke_id(st,pc->prot.ni1.invoke_id); | 
 | 413 |                             pc->prot.ni1.remote_result = err_ret; /* result */ | 
 | 414 |                             pc->prot.ni1.invoke_id = 0;  | 
 | 415 |                             pc->redir_result = pc->prot.ni1.remote_result;  | 
 | 416 |                             st->l3.l3l4(st, CC_REDIR | INDICATION, pc);   | 
 | 417 |                           } /* Deflection error */ | 
 | 418 |                         else | 
 | 419 |                           l3_debug(st,"return result unknown identifier"); | 
 | 420 | 			break; | 
 | 421 | 		default: | 
 | 422 | 			l3_debug(st, "facility default break tag=0x%02x",cp_tag); | 
 | 423 | 			break; | 
 | 424 | 	} | 
 | 425 | } | 
 | 426 |  | 
 | 427 | static void | 
 | 428 | l3ni1_message(struct l3_process *pc, u_char mt) | 
 | 429 | { | 
 | 430 | 	struct sk_buff *skb; | 
 | 431 | 	u_char *p; | 
 | 432 |  | 
 | 433 | 	if (!(skb = l3_alloc_skb(4))) | 
 | 434 | 		return; | 
 | 435 | 	p = skb_put(skb, 4); | 
 | 436 | 	MsgHead(p, pc->callref, mt); | 
 | 437 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 438 | } | 
 | 439 |  | 
 | 440 | static void | 
 | 441 | l3ni1_message_plus_chid(struct l3_process *pc, u_char mt) | 
 | 442 | /* sends an l3 messages plus channel id -  added GE 05/09/00 */ | 
 | 443 | { | 
 | 444 | 	struct sk_buff *skb; | 
 | 445 | 	u_char tmp[16]; | 
 | 446 | 	u_char *p = tmp; | 
 | 447 | 	u_char chid; | 
 | 448 |  | 
 | 449 | 	chid = (u_char)(pc->para.bchannel & 0x03) | 0x88; | 
 | 450 | 	MsgHead(p, pc->callref, mt); | 
 | 451 | 	*p++ = IE_CHANNEL_ID; | 
 | 452 | 	*p++ = 0x01; | 
 | 453 | 	*p++ = chid; | 
 | 454 |  | 
 | 455 | 	if (!(skb = l3_alloc_skb(7))) | 
 | 456 | 		return; | 
 | 457 | 	memcpy(skb_put(skb, 7), tmp, 7); | 
 | 458 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 459 | } | 
 | 460 |  | 
 | 461 | static void | 
 | 462 | l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause) | 
 | 463 | { | 
 | 464 | 	struct sk_buff *skb; | 
 | 465 | 	u_char tmp[16]; | 
 | 466 | 	u_char *p = tmp; | 
 | 467 | 	int l; | 
 | 468 |  | 
 | 469 | 	MsgHead(p, pc->callref, mt); | 
 | 470 | 	*p++ = IE_CAUSE; | 
 | 471 | 	*p++ = 0x2; | 
 | 472 | 	*p++ = 0x80; | 
 | 473 | 	*p++ = cause | 0x80; | 
 | 474 |  | 
 | 475 | 	l = p - tmp; | 
 | 476 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 477 | 		return; | 
 | 478 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 479 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 480 | } | 
 | 481 |  | 
 | 482 | static void | 
 | 483 | l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg) | 
 | 484 | { | 
 | 485 | 	u_char tmp[16]; | 
 | 486 | 	u_char *p = tmp; | 
 | 487 | 	int l; | 
 | 488 | 	struct sk_buff *skb; | 
 | 489 |  | 
 | 490 | 	MsgHead(p, pc->callref, MT_STATUS); | 
 | 491 |  | 
 | 492 | 	*p++ = IE_CAUSE; | 
 | 493 | 	*p++ = 0x2; | 
 | 494 | 	*p++ = 0x80; | 
 | 495 | 	*p++ = pc->para.cause | 0x80; | 
 | 496 |  | 
 | 497 | 	*p++ = IE_CALL_STATE; | 
 | 498 | 	*p++ = 0x1; | 
 | 499 | 	*p++ = pc->state & 0x3f; | 
 | 500 |  | 
 | 501 | 	l = p - tmp; | 
 | 502 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 503 | 		return; | 
 | 504 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 505 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 506 | } | 
 | 507 |  | 
 | 508 | static void | 
 | 509 | l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg) | 
 | 510 | { | 
 | 511 | 	/* This routine is called if here was no SETUP made (checks in ni1up and in | 
 | 512 | 	 * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code | 
 | 513 | 	 * MT_STATUS_ENQUIRE in the NULL state is handled too | 
 | 514 | 	 */ | 
 | 515 | 	u_char tmp[16]; | 
 | 516 | 	u_char *p = tmp; | 
 | 517 | 	int l; | 
 | 518 | 	struct sk_buff *skb; | 
 | 519 |  | 
 | 520 | 	switch (pc->para.cause) { | 
 | 521 | 		case 81:	/* invalid callreference */ | 
 | 522 | 		case 88:	/* incomp destination */ | 
 | 523 | 		case 96:	/* mandory IE missing */ | 
 | 524 | 		case 100:       /* invalid IE contents */ | 
 | 525 | 		case 101:	/* incompatible Callstate */ | 
 | 526 | 			MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); | 
 | 527 | 			*p++ = IE_CAUSE; | 
 | 528 | 			*p++ = 0x2; | 
 | 529 | 			*p++ = 0x80; | 
 | 530 | 			*p++ = pc->para.cause | 0x80; | 
 | 531 | 			break; | 
 | 532 | 		default: | 
 | 533 | 			printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n", | 
 | 534 | 				pc->para.cause); | 
 | 535 | 			return; | 
 | 536 | 	} | 
 | 537 | 	l = p - tmp; | 
 | 538 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 539 | 		return; | 
 | 540 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 541 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 542 | 	ni1_release_l3_process(pc); | 
 | 543 | } | 
 | 544 |  | 
 | 545 | static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, | 
 | 546 | 		IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC, | 
 | 547 | 		IE_USER_USER, -1}; | 
 | 548 | static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1, | 
 | 549 | 		IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1}; | 
 | 550 | static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,  | 
 | 551 | 		IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL, | 
 | 552 | 		IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1}; | 
 | 553 | static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1}; | 
 | 554 | static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY, | 
 | 555 | 		IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; | 
 | 556 | static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, | 
 | 557 | 		IE_CALLED_PN, -1}; | 
 | 558 | static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1}; | 
 | 559 | static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS | | 
 | 560 | 		IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1}; | 
 | 561 | static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY, | 
 | 562 | 		IE_SIGNAL, IE_USER_USER, -1}; | 
 | 563 | /* a RELEASE_COMPLETE with errors don't require special actions  | 
 | 564 | static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1}; | 
 | 565 | */ | 
 | 566 | static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, | 
 | 567 | 		IE_DISPLAY, -1}; | 
 | 568 | static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; | 
 | 569 | static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER  | IE_MANDATORY, | 
 | 570 | 		IE_CHANNEL_ID| IE_MANDATORY, IE_FACILITY, IE_PROGRESS, | 
 | 571 | 		IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN, | 
 | 572 | 		IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR, | 
 | 573 | 		IE_LLC, IE_HLC, IE_USER_USER, -1}; | 
 | 574 | static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, | 
 | 575 | 		IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1}; | 
 | 576 | static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE | | 
 | 577 | 		IE_MANDATORY, IE_DISPLAY, -1}; | 
 | 578 | static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1}; | 
 | 579 | static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1}; | 
 | 580 | static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; | 
 | 581 | /* not used  | 
 | 582 |  * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY, | 
 | 583 |  *		IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1}; | 
 | 584 |  * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1}; | 
 | 585 |  * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND | | 
 | 586 |  *		IE_MANDATORY, -1}; | 
 | 587 |  */ | 
 | 588 | static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1}; | 
 | 589 | static int comp_required[] = {1,2,3,5,6,7,9,10,11,14,15,-1}; | 
 | 590 | static int l3_valid_states[] = {0,1,2,3,4,6,7,8,9,10,11,12,15,17,19,25,-1}; | 
 | 591 |  | 
 | 592 | struct ie_len { | 
 | 593 | 	int ie; | 
 | 594 | 	int len; | 
 | 595 | }; | 
 | 596 |  | 
 | 597 | static | 
 | 598 | struct ie_len max_ie_len[] = { | 
 | 599 | 	{IE_SEGMENT, 4}, | 
 | 600 | 	{IE_BEARER, 12}, | 
 | 601 | 	{IE_CAUSE, 32}, | 
 | 602 | 	{IE_CALL_ID, 10}, | 
 | 603 | 	{IE_CALL_STATE, 3}, | 
 | 604 | 	{IE_CHANNEL_ID,	34}, | 
 | 605 | 	{IE_FACILITY, 255}, | 
 | 606 | 	{IE_PROGRESS, 4}, | 
 | 607 | 	{IE_NET_FAC, 255}, | 
 | 608 | 	{IE_NOTIFY, 3}, | 
 | 609 | 	{IE_DISPLAY, 82}, | 
 | 610 | 	{IE_DATE, 8}, | 
 | 611 | 	{IE_KEYPAD, 34}, | 
 | 612 | 	{IE_SIGNAL, 3}, | 
 | 613 | 	{IE_INFORATE, 6}, | 
 | 614 | 	{IE_E2E_TDELAY, 11}, | 
 | 615 | 	{IE_TDELAY_SEL, 5}, | 
 | 616 | 	{IE_PACK_BINPARA, 3}, | 
 | 617 | 	{IE_PACK_WINSIZE, 4}, | 
 | 618 | 	{IE_PACK_SIZE, 4}, | 
 | 619 | 	{IE_CUG, 7}, | 
 | 620 | 	{IE_REV_CHARGE, 3}, | 
 | 621 | 	{IE_CALLING_PN, 24}, | 
 | 622 | 	{IE_CALLING_SUB, 23}, | 
 | 623 | 	{IE_CALLED_PN, 24}, | 
 | 624 | 	{IE_CALLED_SUB, 23}, | 
 | 625 | 	{IE_REDIR_NR, 255}, | 
 | 626 | 	{IE_TRANS_SEL, 255}, | 
 | 627 | 	{IE_RESTART_IND, 3}, | 
 | 628 | 	{IE_LLC, 18}, | 
 | 629 | 	{IE_HLC, 5}, | 
 | 630 | 	{IE_USER_USER, 131}, | 
 | 631 | 	{-1,0}, | 
 | 632 | }; | 
 | 633 |  | 
 | 634 | static int | 
 | 635 | getmax_ie_len(u_char ie) { | 
 | 636 | 	int i = 0; | 
 | 637 | 	while (max_ie_len[i].ie != -1) { | 
 | 638 | 		if (max_ie_len[i].ie == ie) | 
 | 639 | 			return(max_ie_len[i].len); | 
 | 640 | 		i++; | 
 | 641 | 	} | 
 | 642 | 	return(255); | 
 | 643 | } | 
 | 644 |  | 
 | 645 | static int | 
 | 646 | ie_in_set(struct l3_process *pc, u_char ie, int *checklist) { | 
 | 647 | 	int ret = 1; | 
 | 648 |  | 
 | 649 | 	while (*checklist != -1) { | 
 | 650 | 		if ((*checklist & 0xff) == ie) { | 
 | 651 | 			if (ie & 0x80) | 
 | 652 | 				return(-ret); | 
 | 653 | 			else | 
 | 654 | 				return(ret); | 
 | 655 | 		} | 
 | 656 | 		ret++; | 
 | 657 | 		checklist++; | 
 | 658 | 	} | 
 | 659 | 	return(0); | 
 | 660 | } | 
 | 661 |  | 
 | 662 | static int | 
 | 663 | check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist) | 
 | 664 | { | 
 | 665 | 	int *cl = checklist; | 
 | 666 | 	u_char mt; | 
 | 667 | 	u_char *p, ie; | 
 | 668 | 	int l, newpos, oldpos; | 
 | 669 | 	int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0; | 
 | 670 | 	u_char codeset = 0; | 
 | 671 | 	u_char old_codeset = 0; | 
 | 672 | 	u_char codelock = 1; | 
 | 673 | 	 | 
 | 674 | 	p = skb->data; | 
 | 675 | 	/* skip cr */ | 
 | 676 | 	p++; | 
 | 677 | 	l = (*p++) & 0xf; | 
 | 678 | 	p += l; | 
 | 679 | 	mt = *p++; | 
 | 680 | 	oldpos = 0; | 
 | 681 | 	while ((p - skb->data) < skb->len) { | 
 | 682 | 		if ((*p & 0xf0) == 0x90) { /* shift codeset */ | 
 | 683 | 			old_codeset = codeset; | 
 | 684 | 			codeset = *p & 7; | 
 | 685 | 			if (*p & 0x08) | 
 | 686 | 				codelock = 0; | 
 | 687 | 			else | 
 | 688 | 				codelock = 1; | 
 | 689 | 			if (pc->debug & L3_DEB_CHECK) | 
 | 690 | 				l3_debug(pc->st, "check IE shift%scodeset %d->%d", | 
 | 691 | 					codelock ? " locking ": " ", old_codeset, codeset); | 
 | 692 | 			p++; | 
 | 693 | 			continue; | 
 | 694 | 		} | 
 | 695 | 		if (!codeset) { /* only codeset 0 */ | 
 | 696 | 			if ((newpos = ie_in_set(pc, *p, cl))) { | 
 | 697 | 				if (newpos > 0) { | 
 | 698 | 					if (newpos < oldpos) | 
 | 699 | 						err_seq++; | 
 | 700 | 					else | 
 | 701 | 						oldpos = newpos; | 
 | 702 | 				} | 
 | 703 | 			} else { | 
 | 704 | 				if (ie_in_set(pc, *p, comp_required)) | 
 | 705 | 					err_compr++; | 
 | 706 | 				else | 
 | 707 | 					err_ureg++; | 
 | 708 | 			} | 
 | 709 | 		} | 
 | 710 | 		ie = *p++; | 
 | 711 | 		if (ie & 0x80) { | 
 | 712 | 			l = 1; | 
 | 713 | 		} else { | 
 | 714 | 			l = *p++; | 
 | 715 | 			p += l; | 
 | 716 | 			l += 2; | 
 | 717 | 		} | 
 | 718 | 		if (!codeset && (l > getmax_ie_len(ie))) | 
 | 719 | 			err_len++; | 
 | 720 | 		if (!codelock) { | 
 | 721 | 			if (pc->debug & L3_DEB_CHECK) | 
 | 722 | 				l3_debug(pc->st, "check IE shift back codeset %d->%d", | 
 | 723 | 					codeset, old_codeset); | 
 | 724 | 			codeset = old_codeset; | 
 | 725 | 			codelock = 1; | 
 | 726 | 		} | 
 | 727 | 	} | 
 | 728 | 	if (err_compr | err_ureg | err_len | err_seq) { | 
 | 729 | 		if (pc->debug & L3_DEB_CHECK) | 
 | 730 | 			l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d", | 
 | 731 | 				mt, err_compr, err_ureg, err_len, err_seq); | 
 | 732 | 		if (err_compr) | 
 | 733 | 			return(ERR_IE_COMPREHENSION); | 
 | 734 | 		if (err_ureg) | 
 | 735 | 			return(ERR_IE_UNRECOGNIZED); | 
 | 736 | 		if (err_len) | 
 | 737 | 			return(ERR_IE_LENGTH); | 
 | 738 | 		if (err_seq) | 
 | 739 | 			return(ERR_IE_SEQUENCE); | 
 | 740 | 	}  | 
 | 741 | 	return(0); | 
 | 742 | } | 
 | 743 |  | 
 | 744 | /* verify if a message type exists and contain no IE error */ | 
 | 745 | static int | 
 | 746 | l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg) | 
 | 747 | { | 
 | 748 | 	switch (mt) { | 
 | 749 | 		case MT_ALERTING: | 
 | 750 | 		case MT_CALL_PROCEEDING: | 
 | 751 | 		case MT_CONNECT: | 
 | 752 | 		case MT_CONNECT_ACKNOWLEDGE: | 
 | 753 | 		case MT_DISCONNECT: | 
 | 754 | 		case MT_INFORMATION: | 
 | 755 | 		case MT_FACILITY: | 
 | 756 | 		case MT_NOTIFY: | 
 | 757 | 		case MT_PROGRESS: | 
 | 758 | 		case MT_RELEASE: | 
 | 759 | 		case MT_RELEASE_COMPLETE: | 
 | 760 | 		case MT_SETUP: | 
 | 761 | 		case MT_SETUP_ACKNOWLEDGE: | 
 | 762 | 		case MT_RESUME_ACKNOWLEDGE: | 
 | 763 | 		case MT_RESUME_REJECT: | 
 | 764 | 		case MT_SUSPEND_ACKNOWLEDGE: | 
 | 765 | 		case MT_SUSPEND_REJECT: | 
 | 766 | 		case MT_USER_INFORMATION: | 
 | 767 | 		case MT_RESTART: | 
 | 768 | 		case MT_RESTART_ACKNOWLEDGE: | 
 | 769 | 		case MT_CONGESTION_CONTROL: | 
 | 770 | 		case MT_STATUS: | 
 | 771 | 		case MT_STATUS_ENQUIRY: | 
 | 772 | 			if (pc->debug & L3_DEB_CHECK) | 
 | 773 | 				l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt); | 
 | 774 | 			break; | 
 | 775 | 		case MT_RESUME: /* RESUME only in user->net */ | 
 | 776 | 		case MT_SUSPEND: /* SUSPEND only in user->net */ | 
 | 777 | 		default: | 
 | 778 | 			if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN)) | 
 | 779 | 				l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt); | 
 | 780 | 			pc->para.cause = 97; | 
 | 781 | 			l3ni1_status_send(pc, 0, NULL); | 
 | 782 | 			return(1); | 
 | 783 | 	} | 
 | 784 | 	return(0); | 
 | 785 | } | 
 | 786 |  | 
 | 787 | static void | 
 | 788 | l3ni1_std_ie_err(struct l3_process *pc, int ret) { | 
 | 789 |  | 
 | 790 | 	if (pc->debug & L3_DEB_CHECK) | 
 | 791 | 		l3_debug(pc->st, "check_infoelements ret %d", ret); | 
 | 792 | 	switch(ret) { | 
 | 793 | 		case 0:  | 
 | 794 | 			break; | 
 | 795 | 		case ERR_IE_COMPREHENSION: | 
 | 796 | 			pc->para.cause = 96; | 
 | 797 | 			l3ni1_status_send(pc, 0, NULL); | 
 | 798 | 			break; | 
 | 799 | 		case ERR_IE_UNRECOGNIZED: | 
 | 800 | 			pc->para.cause = 99; | 
 | 801 | 			l3ni1_status_send(pc, 0, NULL); | 
 | 802 | 			break; | 
 | 803 | 		case ERR_IE_LENGTH: | 
 | 804 | 			pc->para.cause = 100; | 
 | 805 | 			l3ni1_status_send(pc, 0, NULL); | 
 | 806 | 			break; | 
 | 807 | 		case ERR_IE_SEQUENCE: | 
 | 808 | 		default: | 
 | 809 | 			break; | 
 | 810 | 	} | 
 | 811 | } | 
 | 812 |  | 
 | 813 | static int | 
 | 814 | l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) { | 
 | 815 | 	u_char *p; | 
 | 816 |  | 
 | 817 | 	p = skb->data; | 
 | 818 | 	if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { | 
 | 819 | 		p++; | 
 | 820 | 		if (*p != 1) { /* len for BRI = 1 */ | 
 | 821 | 			if (pc->debug & L3_DEB_WARN) | 
 | 822 | 				l3_debug(pc->st, "wrong chid len %d", *p); | 
 | 823 | 			return (-2); | 
 | 824 | 		} | 
 | 825 | 		p++; | 
 | 826 | 		if (*p & 0x60) { /* only base rate interface */ | 
 | 827 | 			if (pc->debug & L3_DEB_WARN) | 
 | 828 | 				l3_debug(pc->st, "wrong chid %x", *p); | 
 | 829 | 			return (-3); | 
 | 830 | 		} | 
 | 831 | 		return(*p & 0x3); | 
 | 832 | 	} else | 
 | 833 | 		return(-1); | 
 | 834 | } | 
 | 835 |  | 
 | 836 | static int | 
 | 837 | l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) { | 
 | 838 | 	u_char l, i=0; | 
 | 839 | 	u_char *p; | 
 | 840 |  | 
 | 841 | 	p = skb->data; | 
 | 842 | 	pc->para.cause = 31; | 
 | 843 | 	pc->para.loc = 0; | 
 | 844 | 	if ((p = findie(p, skb->len, IE_CAUSE, 0))) { | 
 | 845 | 		p++; | 
 | 846 | 		l = *p++; | 
 | 847 | 		if (l>30) | 
 | 848 | 			return(1); | 
 | 849 | 		if (l) { | 
 | 850 | 			pc->para.loc = *p++; | 
 | 851 | 			l--; | 
 | 852 | 		} else { | 
 | 853 | 			return(2); | 
 | 854 | 		} | 
 | 855 | 		if (l && !(pc->para.loc & 0x80)) { | 
 | 856 | 			l--; | 
 | 857 | 			p++; /* skip recommendation */ | 
 | 858 | 		} | 
 | 859 | 		if (l) { | 
 | 860 | 			pc->para.cause = *p++; | 
 | 861 | 			l--; | 
 | 862 | 			if (!(pc->para.cause & 0x80)) | 
 | 863 | 				return(3); | 
 | 864 | 		} else | 
 | 865 | 			return(4); | 
 | 866 | 		while (l && (i<6)) { | 
 | 867 | 			pc->para.diag[i++] = *p++; | 
 | 868 | 			l--; | 
 | 869 | 		} | 
 | 870 | 	} else | 
 | 871 | 		return(-1); | 
 | 872 | 	return(0); | 
 | 873 | } | 
 | 874 |  | 
 | 875 | static void | 
 | 876 | l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd) | 
 | 877 | { | 
 | 878 | 	struct sk_buff *skb; | 
 | 879 | 	u_char tmp[16+40]; | 
 | 880 | 	u_char *p = tmp; | 
 | 881 | 	int l; | 
 | 882 |  | 
 | 883 | 	MsgHead(p, pc->callref, cmd); | 
 | 884 |  | 
 | 885 |         if (pc->prot.ni1.uus1_data[0]) | 
 | 886 | 	 { *p++ = IE_USER_USER; /* UUS info element */ | 
 | 887 |            *p++ = strlen(pc->prot.ni1.uus1_data) + 1; | 
 | 888 |            *p++ = 0x04; /* IA5 chars */ | 
 | 889 |            strcpy(p,pc->prot.ni1.uus1_data); | 
 | 890 |            p += strlen(pc->prot.ni1.uus1_data); | 
 | 891 |            pc->prot.ni1.uus1_data[0] = '\0';    | 
 | 892 |          }  | 
 | 893 |  | 
 | 894 | 	l = p - tmp; | 
 | 895 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 896 | 		return; | 
 | 897 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 898 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 899 | } /* l3ni1_msg_with_uus */ | 
 | 900 |  | 
 | 901 | static void | 
 | 902 | l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg) | 
 | 903 | { | 
 | 904 | 	StopAllL3Timer(pc); | 
 | 905 | 	newl3state(pc, 19); | 
 | 906 | 	if (!pc->prot.ni1.uus1_data[0])  | 
 | 907 | 		l3ni1_message(pc, MT_RELEASE); | 
 | 908 | 	else | 
 | 909 | 		l3ni1_msg_with_uus(pc, MT_RELEASE); | 
 | 910 | 	L3AddTimer(&pc->timer, T308, CC_T308_1); | 
 | 911 | } | 
 | 912 |  | 
 | 913 | static void | 
 | 914 | l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg) | 
 | 915 | { | 
 | 916 | 	struct sk_buff *skb = arg; | 
 | 917 | 	int ret; | 
 | 918 |  | 
 | 919 | 	if ((ret = l3ni1_get_cause(pc, skb))>0) { | 
 | 920 | 		if (pc->debug & L3_DEB_WARN) | 
 | 921 | 			l3_debug(pc->st, "RELCMPL get_cause ret(%d)",ret); | 
 | 922 | 	} else if (ret < 0) | 
 | 923 | 		pc->para.cause = NO_CAUSE; | 
 | 924 | 	StopAllL3Timer(pc); | 
 | 925 | 	newl3state(pc, 0); | 
 | 926 | 	pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); | 
 | 927 | 	ni1_release_l3_process(pc); | 
 | 928 | } | 
 | 929 |  | 
 | 930 | #if EXT_BEARER_CAPS | 
 | 931 |  | 
 | 932 | static u_char * | 
 | 933 | EncodeASyncParams(u_char * p, u_char si2) | 
 | 934 | {				// 7c 06 88  90 21 42 00 bb | 
 | 935 |  | 
 | 936 | 	p[0] = 0; | 
 | 937 | 	p[1] = 0x40;		// Intermediate rate: 16 kbit/s jj 2000.02.19 | 
 | 938 | 	p[2] = 0x80; | 
 | 939 | 	if (si2 & 32)		// 7 data bits | 
 | 940 |  | 
 | 941 | 		p[2] += 16; | 
 | 942 | 	else			// 8 data bits | 
 | 943 |  | 
 | 944 | 		p[2] += 24; | 
 | 945 |  | 
 | 946 | 	if (si2 & 16)		// 2 stop bits | 
 | 947 |  | 
 | 948 | 		p[2] += 96; | 
 | 949 | 	else			// 1 stop bit | 
 | 950 |  | 
 | 951 | 		p[2] += 32; | 
 | 952 |  | 
 | 953 | 	if (si2 & 8)		// even parity | 
 | 954 |  | 
 | 955 | 		p[2] += 2; | 
 | 956 | 	else			// no parity | 
 | 957 |  | 
 | 958 | 		p[2] += 3; | 
 | 959 |  | 
 | 960 | 	switch (si2 & 0x07) { | 
 | 961 | 		case 0: | 
 | 962 | 			p[0] = 66;	// 1200 bit/s | 
 | 963 |  | 
 | 964 | 			break; | 
 | 965 | 		case 1: | 
 | 966 | 			p[0] = 88;	// 1200/75 bit/s | 
 | 967 |  | 
 | 968 | 			break; | 
 | 969 | 		case 2: | 
 | 970 | 			p[0] = 87;	// 75/1200 bit/s | 
 | 971 |  | 
 | 972 | 			break; | 
 | 973 | 		case 3: | 
 | 974 | 			p[0] = 67;	// 2400 bit/s | 
 | 975 |  | 
 | 976 | 			break; | 
 | 977 | 		case 4: | 
 | 978 | 			p[0] = 69;	// 4800 bit/s | 
 | 979 |  | 
 | 980 | 			break; | 
 | 981 | 		case 5: | 
 | 982 | 			p[0] = 72;	// 9600 bit/s | 
 | 983 |  | 
 | 984 | 			break; | 
 | 985 | 		case 6: | 
 | 986 | 			p[0] = 73;	// 14400 bit/s | 
 | 987 |  | 
 | 988 | 			break; | 
 | 989 | 		case 7: | 
 | 990 | 			p[0] = 75;	// 19200 bit/s | 
 | 991 |  | 
 | 992 | 			break; | 
 | 993 | 	} | 
 | 994 | 	return p + 3; | 
 | 995 | } | 
 | 996 |  | 
 | 997 | static u_char | 
 | 998 | EncodeSyncParams(u_char si2, u_char ai) | 
 | 999 | { | 
 | 1000 |  | 
 | 1001 | 	switch (si2) { | 
 | 1002 | 		case 0: | 
 | 1003 | 			return ai + 2;	// 1200 bit/s | 
 | 1004 |  | 
 | 1005 | 		case 1: | 
 | 1006 | 			return ai + 24;		// 1200/75 bit/s | 
 | 1007 |  | 
 | 1008 | 		case 2: | 
 | 1009 | 			return ai + 23;		// 75/1200 bit/s | 
 | 1010 |  | 
 | 1011 | 		case 3: | 
 | 1012 | 			return ai + 3;	// 2400 bit/s | 
 | 1013 |  | 
 | 1014 | 		case 4: | 
 | 1015 | 			return ai + 5;	// 4800 bit/s | 
 | 1016 |  | 
 | 1017 | 		case 5: | 
 | 1018 | 			return ai + 8;	// 9600 bit/s | 
 | 1019 |  | 
 | 1020 | 		case 6: | 
 | 1021 | 			return ai + 9;	// 14400 bit/s | 
 | 1022 |  | 
 | 1023 | 		case 7: | 
 | 1024 | 			return ai + 11;		// 19200 bit/s | 
 | 1025 |  | 
 | 1026 | 		case 8: | 
 | 1027 | 			return ai + 14;		// 48000 bit/s | 
 | 1028 |  | 
 | 1029 | 		case 9: | 
 | 1030 | 			return ai + 15;		// 56000 bit/s | 
 | 1031 |  | 
 | 1032 | 		case 15: | 
 | 1033 | 			return ai + 40;		// negotiate bit/s | 
 | 1034 |  | 
 | 1035 | 		default: | 
 | 1036 | 			break; | 
 | 1037 | 	} | 
 | 1038 | 	return ai; | 
 | 1039 | } | 
 | 1040 |  | 
 | 1041 |  | 
 | 1042 | static u_char | 
 | 1043 | DecodeASyncParams(u_char si2, u_char * p) | 
 | 1044 | { | 
 | 1045 | 	u_char info; | 
 | 1046 |  | 
 | 1047 | 	switch (p[5]) { | 
 | 1048 | 		case 66:	// 1200 bit/s | 
 | 1049 |  | 
 | 1050 | 			break;	// si2 don't change | 
 | 1051 |  | 
 | 1052 | 		case 88:	// 1200/75 bit/s | 
 | 1053 |  | 
 | 1054 | 			si2 += 1; | 
 | 1055 | 			break; | 
 | 1056 | 		case 87:	// 75/1200 bit/s | 
 | 1057 |  | 
 | 1058 | 			si2 += 2; | 
 | 1059 | 			break; | 
 | 1060 | 		case 67:	// 2400 bit/s | 
 | 1061 |  | 
 | 1062 | 			si2 += 3; | 
 | 1063 | 			break; | 
 | 1064 | 		case 69:	// 4800 bit/s | 
 | 1065 |  | 
 | 1066 | 			si2 += 4; | 
 | 1067 | 			break; | 
 | 1068 | 		case 72:	// 9600 bit/s | 
 | 1069 |  | 
 | 1070 | 			si2 += 5; | 
 | 1071 | 			break; | 
 | 1072 | 		case 73:	// 14400 bit/s | 
 | 1073 |  | 
 | 1074 | 			si2 += 6; | 
 | 1075 | 			break; | 
 | 1076 | 		case 75:	// 19200 bit/s | 
 | 1077 |  | 
 | 1078 | 			si2 += 7; | 
 | 1079 | 			break; | 
 | 1080 | 	} | 
 | 1081 |  | 
 | 1082 | 	info = p[7] & 0x7f; | 
 | 1083 | 	if ((info & 16) && (!(info & 8)))	// 7 data bits | 
 | 1084 |  | 
 | 1085 | 		si2 += 32;	// else 8 data bits | 
 | 1086 |  | 
 | 1087 | 	if ((info & 96) == 96)	// 2 stop bits | 
 | 1088 |  | 
 | 1089 | 		si2 += 16;	// else 1 stop bit | 
 | 1090 |  | 
 | 1091 | 	if ((info & 2) && (!(info & 1)))	// even parity | 
 | 1092 |  | 
 | 1093 | 		si2 += 8;	// else no parity | 
 | 1094 |  | 
 | 1095 | 	return si2; | 
 | 1096 | } | 
 | 1097 |  | 
 | 1098 |  | 
 | 1099 | static u_char | 
 | 1100 | DecodeSyncParams(u_char si2, u_char info) | 
 | 1101 | { | 
 | 1102 | 	info &= 0x7f; | 
 | 1103 | 	switch (info) { | 
 | 1104 | 		case 40:	// bit/s negotiation failed  ai := 165 not 175! | 
 | 1105 |  | 
 | 1106 | 			return si2 + 15; | 
 | 1107 | 		case 15:	// 56000 bit/s failed, ai := 0 not 169 ! | 
 | 1108 |  | 
 | 1109 | 			return si2 + 9; | 
 | 1110 | 		case 14:	// 48000 bit/s | 
 | 1111 |  | 
 | 1112 | 			return si2 + 8; | 
 | 1113 | 		case 11:	// 19200 bit/s | 
 | 1114 |  | 
 | 1115 | 			return si2 + 7; | 
 | 1116 | 		case 9:	// 14400 bit/s | 
 | 1117 |  | 
 | 1118 | 			return si2 + 6; | 
 | 1119 | 		case 8:	// 9600  bit/s | 
 | 1120 |  | 
 | 1121 | 			return si2 + 5; | 
 | 1122 | 		case 5:	// 4800  bit/s | 
 | 1123 |  | 
 | 1124 | 			return si2 + 4; | 
 | 1125 | 		case 3:	// 2400  bit/s | 
 | 1126 |  | 
 | 1127 | 			return si2 + 3; | 
 | 1128 | 		case 23:	// 75/1200 bit/s | 
 | 1129 |  | 
 | 1130 | 			return si2 + 2; | 
 | 1131 | 		case 24:	// 1200/75 bit/s | 
 | 1132 |  | 
 | 1133 | 			return si2 + 1; | 
 | 1134 | 		default:	// 1200 bit/s | 
 | 1135 |  | 
 | 1136 | 			return si2; | 
 | 1137 | 	} | 
 | 1138 | } | 
 | 1139 |  | 
 | 1140 | static u_char | 
 | 1141 | DecodeSI2(struct sk_buff *skb) | 
 | 1142 | { | 
 | 1143 | 	u_char *p;		//, *pend=skb->data + skb->len; | 
 | 1144 |  | 
 | 1145 | 	if ((p = findie(skb->data, skb->len, 0x7c, 0))) { | 
 | 1146 | 		switch (p[4] & 0x0f) { | 
 | 1147 | 			case 0x01: | 
 | 1148 | 				if (p[1] == 0x04)	// sync. Bitratenadaption | 
 | 1149 |  | 
 | 1150 | 					return DecodeSyncParams(160, p[5]);	// V.110/X.30 | 
 | 1151 |  | 
 | 1152 | 				else if (p[1] == 0x06)	// async. Bitratenadaption | 
 | 1153 |  | 
 | 1154 | 					return DecodeASyncParams(192, p);	// V.110/X.30 | 
 | 1155 |  | 
 | 1156 | 				break; | 
 | 1157 | 			case 0x08:	// if (p[5] == 0x02) // sync. Bitratenadaption | 
 | 1158 | 				if (p[1] > 3)  | 
 | 1159 | 					return DecodeSyncParams(176, p[5]);	// V.120 | 
 | 1160 | 				break; | 
 | 1161 | 		} | 
 | 1162 | 	} | 
 | 1163 | 	return 0; | 
 | 1164 | } | 
 | 1165 |  | 
 | 1166 | #endif | 
 | 1167 |  | 
 | 1168 |  | 
 | 1169 | static void | 
 | 1170 | l3ni1_setup_req(struct l3_process *pc, u_char pr, | 
 | 1171 | 		 void *arg) | 
 | 1172 | { | 
 | 1173 | 	struct sk_buff *skb; | 
 | 1174 | 	u_char tmp[128]; | 
 | 1175 | 	u_char *p = tmp; | 
 | 1176 |  | 
 | 1177 | 	u_char *teln; | 
 | 1178 | 	u_char *sub; | 
 | 1179 | 	u_char *sp; | 
 | 1180 | 	int l; | 
 | 1181 |  | 
 | 1182 | 	MsgHead(p, pc->callref, MT_SETUP); | 
 | 1183 |  | 
 | 1184 | 	teln = pc->para.setup.phone; | 
 | 1185 |  | 
 | 1186 | 	*p++ = 0xa1;		/* complete indicator */ | 
 | 1187 | 	/* | 
 | 1188 | 	 * Set Bearer Capability, Map info from 1TR6-convention to NI1 | 
 | 1189 | 	 */ | 
 | 1190 | 	switch (pc->para.setup.si1) { | 
 | 1191 | 	case 1:	                  /* Telephony                                */ | 
 | 1192 | 		*p++ = IE_BEARER; | 
 | 1193 | 		*p++ = 0x3;	  /* Length                                   */ | 
 | 1194 | 		*p++ = 0x90;	  /* 3.1khz Audio      			      */ | 
 | 1195 | 		*p++ = 0x90;	  /* Circuit-Mode 64kbps                      */ | 
 | 1196 | 		*p++ = 0xa2;	  /* u-Law Audio                              */ | 
 | 1197 | 		break; | 
 | 1198 | 	case 5:	                  /* Datatransmission 64k, BTX                */ | 
 | 1199 | 	case 7:	                  /* Datatransmission 64k                     */ | 
 | 1200 | 	default: | 
 | 1201 | 		*p++ = IE_BEARER; | 
 | 1202 | 		*p++ = 0x2;	  /* Length                                   */ | 
 | 1203 | 		*p++ = 0x88;	  /* Coding Std. CCITT, unrestr. dig. Inform. */ | 
 | 1204 | 		*p++ = 0x90;	  /* Circuit-Mode 64kbps                      */ | 
 | 1205 | 		break; | 
 | 1206 | 	} | 
 | 1207 |  | 
 | 1208 | 	sub = NULL; | 
 | 1209 | 	sp = teln; | 
 | 1210 | 	while (*sp) { | 
 | 1211 | 		if ('.' == *sp) { | 
 | 1212 | 			sub = sp; | 
 | 1213 | 			*sp = 0; | 
 | 1214 | 		} else | 
 | 1215 | 			sp++; | 
 | 1216 | 	} | 
 | 1217 | 	 | 
 | 1218 | 	*p++ = IE_KEYPAD; | 
 | 1219 | 	*p++ = strlen(teln); | 
 | 1220 | 	while (*teln) | 
 | 1221 | 		*p++ = (*teln++) & 0x7F; | 
 | 1222 |  | 
 | 1223 | 	if (sub) | 
 | 1224 | 		*sub++ = '.'; | 
 | 1225 | 	 | 
 | 1226 | #if EXT_BEARER_CAPS | 
 | 1227 | 	if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) {	// sync. Bitratenadaption, V.110/X.30 | 
 | 1228 |  | 
 | 1229 | 		*p++ = IE_LLC; | 
 | 1230 | 		*p++ = 0x04; | 
 | 1231 | 		*p++ = 0x88; | 
 | 1232 | 		*p++ = 0x90; | 
 | 1233 | 		*p++ = 0x21; | 
 | 1234 | 		*p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80); | 
 | 1235 | 	} else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) {	// sync. Bitratenadaption, V.120 | 
 | 1236 |  | 
 | 1237 | 		*p++ = IE_LLC; | 
 | 1238 | 		*p++ = 0x05; | 
 | 1239 | 		*p++ = 0x88; | 
 | 1240 | 		*p++ = 0x90; | 
 | 1241 | 		*p++ = 0x28; | 
 | 1242 | 		*p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0); | 
 | 1243 | 		*p++ = 0x82; | 
 | 1244 | 	} else if (pc->para.setup.si2 >= 192) {		// async. Bitratenadaption, V.110/X.30 | 
 | 1245 |  | 
 | 1246 | 		*p++ = IE_LLC; | 
 | 1247 | 		*p++ = 0x06; | 
 | 1248 | 		*p++ = 0x88; | 
 | 1249 | 		*p++ = 0x90; | 
 | 1250 | 		*p++ = 0x21; | 
 | 1251 | 		p = EncodeASyncParams(p, pc->para.setup.si2 - 192); | 
 | 1252 | 	} else { | 
 | 1253 | 	  switch (pc->para.setup.si1) { | 
 | 1254 | 		case 1:	                /* Telephony                                */ | 
 | 1255 | 			*p++ = IE_LLC; | 
 | 1256 | 			*p++ = 0x3;	/* Length                                   */ | 
 | 1257 | 			*p++ = 0x90;	/* Coding Std. CCITT, 3.1 kHz audio         */ | 
 | 1258 | 			*p++ = 0x90;	/* Circuit-Mode 64kbps                      */ | 
 | 1259 | 			*p++ = 0xa2;	/* u-Law Audio                              */ | 
 | 1260 | 			break; | 
 | 1261 | 		case 5:	                /* Datatransmission 64k, BTX                */ | 
 | 1262 | 		case 7:	                /* Datatransmission 64k                     */ | 
 | 1263 | 		default: | 
 | 1264 | 			*p++ = IE_LLC; | 
 | 1265 | 			*p++ = 0x2;	/* Length                                   */ | 
 | 1266 | 			*p++ = 0x88;	/* Coding Std. CCITT, unrestr. dig. Inform. */ | 
 | 1267 | 			*p++ = 0x90;	/* Circuit-Mode 64kbps                      */ | 
 | 1268 | 			break; | 
 | 1269 | 	  } | 
 | 1270 | 	} | 
 | 1271 | #endif | 
 | 1272 | 	l = p - tmp; | 
 | 1273 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 1274 | { | 
 | 1275 | 		return; | 
 | 1276 | } | 
 | 1277 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 1278 | 	L3DelTimer(&pc->timer); | 
 | 1279 | 	L3AddTimer(&pc->timer, T303, CC_T303); | 
 | 1280 | 	newl3state(pc, 1); | 
 | 1281 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 1282 | } | 
 | 1283 |  | 
 | 1284 | static void | 
 | 1285 | l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg) | 
 | 1286 | { | 
 | 1287 | 	struct sk_buff *skb = arg; | 
 | 1288 | 	int id, ret; | 
 | 1289 |  | 
 | 1290 | 	if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { | 
 | 1291 | 		if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { | 
 | 1292 | 			if (pc->debug & L3_DEB_WARN) | 
 | 1293 | 				l3_debug(pc->st, "setup answer with wrong chid %x", id); | 
 | 1294 | 			pc->para.cause = 100; | 
 | 1295 | 			l3ni1_status_send(pc, pr, NULL); | 
 | 1296 | 			return; | 
 | 1297 | 		} | 
 | 1298 | 		pc->para.bchannel = id; | 
 | 1299 | 	} else if (1 == pc->state) { | 
 | 1300 | 		if (pc->debug & L3_DEB_WARN) | 
 | 1301 | 			l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); | 
 | 1302 | 		if (id == -1) | 
 | 1303 | 			pc->para.cause = 96; | 
 | 1304 | 		else | 
 | 1305 | 			pc->para.cause = 100; | 
 | 1306 | 		l3ni1_status_send(pc, pr, NULL); | 
 | 1307 | 		return; | 
 | 1308 | 	} | 
 | 1309 | 	/* Now we are on none mandatory IEs */ | 
 | 1310 | 	ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING); | 
 | 1311 | 	if (ERR_IE_COMPREHENSION == ret) { | 
 | 1312 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1313 | 		return; | 
 | 1314 | 	} | 
 | 1315 | 	L3DelTimer(&pc->timer); | 
 | 1316 | 	newl3state(pc, 3); | 
 | 1317 | 	L3AddTimer(&pc->timer, T310, CC_T310); | 
 | 1318 | 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */ | 
 | 1319 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1320 | 	pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); | 
 | 1321 | } | 
 | 1322 |  | 
 | 1323 | static void | 
 | 1324 | l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg) | 
 | 1325 | { | 
 | 1326 | 	struct sk_buff *skb = arg; | 
 | 1327 | 	int id, ret; | 
 | 1328 |  | 
 | 1329 | 	if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { | 
 | 1330 | 		if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { | 
 | 1331 | 			if (pc->debug & L3_DEB_WARN) | 
 | 1332 | 				l3_debug(pc->st, "setup answer with wrong chid %x", id); | 
 | 1333 | 			pc->para.cause = 100; | 
 | 1334 | 			l3ni1_status_send(pc, pr, NULL); | 
 | 1335 | 			return; | 
 | 1336 | 		} | 
 | 1337 | 		pc->para.bchannel = id; | 
 | 1338 | 	} else { | 
 | 1339 | 		if (pc->debug & L3_DEB_WARN) | 
 | 1340 | 			l3_debug(pc->st, "setup answer wrong chid (ret %d)", id); | 
 | 1341 | 		if (id == -1) | 
 | 1342 | 			pc->para.cause = 96; | 
 | 1343 | 		else | 
 | 1344 | 			pc->para.cause = 100; | 
 | 1345 | 		l3ni1_status_send(pc, pr, NULL); | 
 | 1346 | 		return; | 
 | 1347 | 	} | 
 | 1348 | 	/* Now we are on none mandatory IEs */ | 
 | 1349 | 	ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE); | 
 | 1350 | 	if (ERR_IE_COMPREHENSION == ret) { | 
 | 1351 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1352 | 		return; | 
 | 1353 | 	} | 
 | 1354 | 	L3DelTimer(&pc->timer); | 
 | 1355 | 	newl3state(pc, 2); | 
 | 1356 | 	L3AddTimer(&pc->timer, T304, CC_T304); | 
 | 1357 | 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */ | 
 | 1358 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1359 | 	pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); | 
 | 1360 | } | 
 | 1361 |  | 
 | 1362 | static void | 
 | 1363 | l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg) | 
 | 1364 | { | 
 | 1365 | 	struct sk_buff *skb = arg; | 
 | 1366 | 	u_char *p; | 
 | 1367 | 	int ret; | 
 | 1368 | 	u_char cause = 0; | 
 | 1369 |  | 
 | 1370 | 	StopAllL3Timer(pc); | 
 | 1371 | 	if ((ret = l3ni1_get_cause(pc, skb))) { | 
 | 1372 | 		if (pc->debug & L3_DEB_WARN) | 
 | 1373 | 			l3_debug(pc->st, "DISC get_cause ret(%d)", ret); | 
 | 1374 | 		if (ret < 0) | 
 | 1375 | 			cause = 96; | 
 | 1376 | 		else if (ret > 0) | 
 | 1377 | 			cause = 100; | 
 | 1378 | 	}  | 
 | 1379 | 	if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) | 
 | 1380 | 		l3ni1_parse_facility(pc->st, pc, pc->callref, p); | 
 | 1381 | 	ret = check_infoelements(pc, skb, ie_DISCONNECT); | 
 | 1382 | 	if (ERR_IE_COMPREHENSION == ret) | 
 | 1383 | 		cause = 96; | 
 | 1384 | 	else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret)) | 
 | 1385 | 		cause = 99; | 
 | 1386 | 	ret = pc->state; | 
 | 1387 | 	newl3state(pc, 12); | 
 | 1388 | 	if (cause) | 
 | 1389 | 		newl3state(pc, 19); | 
 | 1390 |        	if (11 != ret) | 
 | 1391 | 		pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); | 
 | 1392 |        	else if (!cause) | 
 | 1393 | 		   l3ni1_release_req(pc, pr, NULL); | 
 | 1394 | 	if (cause) { | 
 | 1395 | 		l3ni1_message_cause(pc, MT_RELEASE, cause); | 
 | 1396 | 		L3AddTimer(&pc->timer, T308, CC_T308_1); | 
 | 1397 | 	} | 
 | 1398 | } | 
 | 1399 |  | 
 | 1400 | static void | 
 | 1401 | l3ni1_connect(struct l3_process *pc, u_char pr, void *arg) | 
 | 1402 | { | 
 | 1403 | 	struct sk_buff *skb = arg; | 
 | 1404 | 	int ret; | 
 | 1405 |  | 
 | 1406 | 	ret = check_infoelements(pc, skb, ie_CONNECT); | 
 | 1407 | 	if (ERR_IE_COMPREHENSION == ret) { | 
 | 1408 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1409 | 		return; | 
 | 1410 | 	} | 
 | 1411 | 	L3DelTimer(&pc->timer);	/* T310 */ | 
 | 1412 | 	newl3state(pc, 10); | 
 | 1413 | 	pc->para.chargeinfo = 0; | 
 | 1414 | 	/* here should inserted COLP handling KKe */ | 
 | 1415 | 	if (ret) | 
 | 1416 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1417 | 	pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); | 
 | 1418 | } | 
 | 1419 |  | 
 | 1420 | static void | 
 | 1421 | l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg) | 
 | 1422 | { | 
 | 1423 | 	struct sk_buff *skb = arg; | 
 | 1424 | 	int ret; | 
 | 1425 |  | 
 | 1426 | 	ret = check_infoelements(pc, skb, ie_ALERTING); | 
 | 1427 | 	if (ERR_IE_COMPREHENSION == ret) { | 
 | 1428 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1429 | 		return; | 
 | 1430 | 	} | 
 | 1431 | 	L3DelTimer(&pc->timer);	/* T304 */ | 
 | 1432 | 	newl3state(pc, 4); | 
 | 1433 | 	if (ret) | 
 | 1434 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1435 | 	pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); | 
 | 1436 | } | 
 | 1437 |  | 
 | 1438 | static void | 
 | 1439 | l3ni1_setup(struct l3_process *pc, u_char pr, void *arg) | 
 | 1440 | { | 
 | 1441 | 	u_char *p; | 
 | 1442 | 	int bcfound = 0; | 
 | 1443 | 	char tmp[80]; | 
 | 1444 | 	struct sk_buff *skb = arg; | 
 | 1445 | 	int id; | 
 | 1446 | 	int err = 0; | 
 | 1447 |  | 
 | 1448 | 	/* | 
 | 1449 | 	 * Bearer Capabilities | 
 | 1450 | 	 */ | 
 | 1451 | 	p = skb->data; | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 1452 | 	/* only the first occurrence 'll be detected ! */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1453 | 	if ((p = findie(p, skb->len, 0x04, 0))) { | 
 | 1454 | 		if ((p[1] < 2) || (p[1] > 11)) | 
 | 1455 | 			err = 1; | 
 | 1456 | 		else { | 
 | 1457 | 			pc->para.setup.si2 = 0; | 
 | 1458 | 			switch (p[2] & 0x7f) { | 
 | 1459 | 				case 0x00: /* Speech */ | 
 | 1460 | 				case 0x10: /* 3.1 Khz audio */ | 
 | 1461 | 					pc->para.setup.si1 = 1; | 
 | 1462 | 					break; | 
 | 1463 | 				case 0x08: /* Unrestricted digital information */ | 
 | 1464 | 					pc->para.setup.si1 = 7; | 
 | 1465 | /* JIM, 05.11.97 I wanna set service indicator 2 */ | 
 | 1466 | #if EXT_BEARER_CAPS | 
 | 1467 | 					pc->para.setup.si2 = DecodeSI2(skb); | 
 | 1468 | #endif | 
 | 1469 | 					break; | 
 | 1470 | 				case 0x09: /* Restricted digital information */ | 
 | 1471 | 					pc->para.setup.si1 = 2; | 
 | 1472 | 					break; | 
 | 1473 | 				case 0x11: | 
 | 1474 | 					/* Unrestr. digital information  with  | 
 | 1475 | 					 * tones/announcements ( or 7 kHz audio | 
 | 1476 | 					 */ | 
 | 1477 | 					pc->para.setup.si1 = 3; | 
 | 1478 | 					break; | 
 | 1479 | 				case 0x18: /* Video */ | 
 | 1480 | 					pc->para.setup.si1 = 4; | 
 | 1481 | 					break; | 
 | 1482 | 				default: | 
 | 1483 | 					err = 2; | 
 | 1484 | 					break; | 
 | 1485 | 			} | 
 | 1486 | 			switch (p[3] & 0x7f) { | 
 | 1487 | 				case 0x40: /* packed mode */ | 
 | 1488 | 					pc->para.setup.si1 = 8; | 
 | 1489 | 					break; | 
 | 1490 | 				case 0x10: /* 64 kbit */ | 
 | 1491 | 				case 0x11: /* 2*64 kbit */ | 
 | 1492 | 				case 0x13: /* 384 kbit */ | 
 | 1493 | 				case 0x15: /* 1536 kbit */ | 
 | 1494 | 				case 0x17: /* 1920 kbit */ | 
 | 1495 | 					pc->para.moderate = p[3] & 0x7f; | 
 | 1496 | 					break; | 
 | 1497 | 				default: | 
 | 1498 | 					err = 3; | 
 | 1499 | 					break; | 
 | 1500 | 			} | 
 | 1501 | 		} | 
 | 1502 | 		if (pc->debug & L3_DEB_SI) | 
 | 1503 | 			l3_debug(pc->st, "SI=%d, AI=%d", | 
 | 1504 | 				pc->para.setup.si1, pc->para.setup.si2); | 
 | 1505 | 		if (err) { | 
 | 1506 | 			if (pc->debug & L3_DEB_WARN) | 
 | 1507 | 				l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)", | 
 | 1508 | 					p[1], p[2], p[3]); | 
 | 1509 | 			pc->para.cause = 100; | 
 | 1510 | 			l3ni1_msg_without_setup(pc, pr, NULL); | 
 | 1511 | 			return; | 
 | 1512 | 		} | 
 | 1513 | 	} else { | 
 | 1514 | 		if (pc->debug & L3_DEB_WARN) | 
 | 1515 | 			l3_debug(pc->st, "setup without bearer capabilities"); | 
 | 1516 | 		/* ETS 300-104 1.3.3 */ | 
 | 1517 | 		pc->para.cause = 96; | 
 | 1518 | 		l3ni1_msg_without_setup(pc, pr, NULL); | 
 | 1519 | 		return; | 
 | 1520 | 	} | 
 | 1521 | 	/* | 
 | 1522 | 	 * Channel Identification | 
 | 1523 | 	 */ | 
 | 1524 | 	if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) { | 
 | 1525 | 		if ((pc->para.bchannel = id)) { | 
 | 1526 | 			if ((3 == id) && (0x10 == pc->para.moderate)) { | 
 | 1527 | 				if (pc->debug & L3_DEB_WARN) | 
 | 1528 | 					l3_debug(pc->st, "setup with wrong chid %x", | 
 | 1529 | 						id); | 
 | 1530 | 				pc->para.cause = 100; | 
 | 1531 | 				l3ni1_msg_without_setup(pc, pr, NULL); | 
 | 1532 | 				return; | 
 | 1533 | 			} | 
 | 1534 | 			bcfound++; | 
 | 1535 | 		} else  | 
 | 1536 |                    { if (pc->debug & L3_DEB_WARN) | 
 | 1537 | 			 l3_debug(pc->st, "setup without bchannel, call waiting"); | 
 | 1538 |                      bcfound++; | 
 | 1539 |                    }  | 
 | 1540 | 	} else { | 
 | 1541 | 		if (pc->debug & L3_DEB_WARN) | 
 | 1542 | 			l3_debug(pc->st, "setup with wrong chid ret %d", id); | 
 | 1543 | 		if (id == -1) | 
 | 1544 | 			pc->para.cause = 96; | 
 | 1545 | 		else | 
 | 1546 | 			pc->para.cause = 100; | 
 | 1547 | 		l3ni1_msg_without_setup(pc, pr, NULL); | 
 | 1548 | 		return; | 
 | 1549 | 	} | 
 | 1550 | 	/* Now we are on none mandatory IEs */ | 
 | 1551 | 	err = check_infoelements(pc, skb, ie_SETUP); | 
 | 1552 | 	if (ERR_IE_COMPREHENSION == err) { | 
 | 1553 | 		pc->para.cause = 96; | 
 | 1554 | 		l3ni1_msg_without_setup(pc, pr, NULL); | 
 | 1555 | 		return; | 
 | 1556 | 	} | 
 | 1557 | 	p = skb->data; | 
 | 1558 | 	if ((p = findie(p, skb->len, 0x70, 0))) | 
 | 1559 | 		iecpy(pc->para.setup.eazmsn, p, 1); | 
 | 1560 | 	else | 
 | 1561 | 		pc->para.setup.eazmsn[0] = 0; | 
 | 1562 |  | 
 | 1563 | 	p = skb->data; | 
 | 1564 | 	if ((p = findie(p, skb->len, 0x71, 0))) { | 
 | 1565 | 		/* Called party subaddress */ | 
 | 1566 | 		if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { | 
 | 1567 | 			tmp[0] = '.'; | 
 | 1568 | 			iecpy(&tmp[1], p, 2); | 
 | 1569 | 			strcat(pc->para.setup.eazmsn, tmp); | 
 | 1570 | 		} else if (pc->debug & L3_DEB_WARN) | 
 | 1571 | 			l3_debug(pc->st, "wrong called subaddress"); | 
 | 1572 | 	} | 
 | 1573 | 	p = skb->data; | 
 | 1574 | 	if ((p = findie(p, skb->len, 0x6c, 0))) { | 
 | 1575 | 		pc->para.setup.plan = p[2]; | 
 | 1576 | 		if (p[2] & 0x80) { | 
 | 1577 | 			iecpy(pc->para.setup.phone, p, 1); | 
 | 1578 | 			pc->para.setup.screen = 0; | 
 | 1579 | 		} else { | 
 | 1580 | 			iecpy(pc->para.setup.phone, p, 2); | 
 | 1581 | 			pc->para.setup.screen = p[3]; | 
 | 1582 | 		} | 
 | 1583 | 	} else { | 
 | 1584 | 		pc->para.setup.phone[0] = 0; | 
 | 1585 | 		pc->para.setup.plan = 0; | 
 | 1586 | 		pc->para.setup.screen = 0; | 
 | 1587 | 	} | 
 | 1588 | 	p = skb->data; | 
 | 1589 | 	if ((p = findie(p, skb->len, 0x6d, 0))) { | 
 | 1590 | 		/* Calling party subaddress */ | 
 | 1591 | 		if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) { | 
 | 1592 | 			tmp[0] = '.'; | 
 | 1593 | 			iecpy(&tmp[1], p, 2); | 
 | 1594 | 			strcat(pc->para.setup.phone, tmp); | 
 | 1595 | 		} else if (pc->debug & L3_DEB_WARN) | 
 | 1596 | 			l3_debug(pc->st, "wrong calling subaddress"); | 
 | 1597 | 	} | 
 | 1598 | 	newl3state(pc, 6); | 
 | 1599 | 	if (err) /* STATUS for none mandatory IE errors after actions are taken */ | 
 | 1600 | 		l3ni1_std_ie_err(pc, err); | 
 | 1601 | 	pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); | 
 | 1602 | } | 
 | 1603 |  | 
 | 1604 | static void | 
 | 1605 | l3ni1_reset(struct l3_process *pc, u_char pr, void *arg) | 
 | 1606 | { | 
 | 1607 | 	ni1_release_l3_process(pc); | 
 | 1608 | } | 
 | 1609 |  | 
 | 1610 | static void | 
 | 1611 | l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg) | 
 | 1612 | { | 
 | 1613 | 	struct sk_buff *skb; | 
 | 1614 | 	u_char tmp[16+40]; | 
 | 1615 | 	u_char *p = tmp; | 
 | 1616 | 	int l; | 
 | 1617 | 	u_char cause = 16; | 
 | 1618 |  | 
 | 1619 | 	if (pc->para.cause != NO_CAUSE) | 
 | 1620 | 		cause = pc->para.cause; | 
 | 1621 |  | 
 | 1622 | 	StopAllL3Timer(pc); | 
 | 1623 |  | 
 | 1624 | 	MsgHead(p, pc->callref, MT_DISCONNECT); | 
 | 1625 |  | 
 | 1626 | 	*p++ = IE_CAUSE; | 
 | 1627 | 	*p++ = 0x2; | 
 | 1628 | 	*p++ = 0x80; | 
 | 1629 | 	*p++ = cause | 0x80; | 
 | 1630 |  | 
 | 1631 |         if (pc->prot.ni1.uus1_data[0]) | 
 | 1632 | 	 { *p++ = IE_USER_USER; /* UUS info element */ | 
 | 1633 |            *p++ = strlen(pc->prot.ni1.uus1_data) + 1; | 
 | 1634 |            *p++ = 0x04; /* IA5 chars */ | 
 | 1635 |            strcpy(p,pc->prot.ni1.uus1_data); | 
 | 1636 |            p += strlen(pc->prot.ni1.uus1_data); | 
 | 1637 |            pc->prot.ni1.uus1_data[0] = '\0';    | 
 | 1638 |          }  | 
 | 1639 |  | 
 | 1640 | 	l = p - tmp; | 
 | 1641 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 1642 | 		return; | 
 | 1643 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 1644 | 	newl3state(pc, 11); | 
 | 1645 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 1646 | 	L3AddTimer(&pc->timer, T305, CC_T305); | 
 | 1647 | } | 
 | 1648 |  | 
 | 1649 | static void | 
 | 1650 | l3ni1_setup_rsp(struct l3_process *pc, u_char pr, | 
 | 1651 | 		 void *arg) | 
 | 1652 | { | 
 | 1653 |         if (!pc->para.bchannel)  | 
 | 1654 | 	 { if (pc->debug & L3_DEB_WARN) | 
 | 1655 | 	       l3_debug(pc->st, "D-chan connect for waiting call"); | 
 | 1656 |            l3ni1_disconnect_req(pc, pr, arg); | 
 | 1657 |            return; | 
 | 1658 |          } | 
 | 1659 | 	newl3state(pc, 8); | 
 | 1660 | 	if (pc->debug & L3_DEB_WARN) | 
 | 1661 | 		l3_debug(pc->st, "D-chan connect for waiting call"); | 
 | 1662 | 	l3ni1_message_plus_chid(pc, MT_CONNECT); /* GE 05/09/00 */  | 
 | 1663 | 	L3DelTimer(&pc->timer); | 
 | 1664 | 	L3AddTimer(&pc->timer, T313, CC_T313); | 
 | 1665 | } | 
 | 1666 |  | 
 | 1667 | static void | 
 | 1668 | l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg) | 
 | 1669 | { | 
 | 1670 | 	struct sk_buff *skb = arg; | 
 | 1671 | 	int ret; | 
 | 1672 |  | 
 | 1673 | 	ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE); | 
 | 1674 | 	if (ERR_IE_COMPREHENSION == ret) { | 
 | 1675 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1676 | 		return; | 
 | 1677 | 	} | 
 | 1678 | 	newl3state(pc, 10); | 
 | 1679 | 	L3DelTimer(&pc->timer); | 
 | 1680 | 	if (ret) | 
 | 1681 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1682 | 	pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); | 
 | 1683 | } | 
 | 1684 |  | 
 | 1685 | static void | 
 | 1686 | l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg) | 
 | 1687 | { | 
 | 1688 | 	struct sk_buff *skb; | 
 | 1689 | 	u_char tmp[16]; | 
 | 1690 | 	u_char *p = tmp; | 
 | 1691 | 	int l; | 
 | 1692 | 	u_char cause = 21; | 
 | 1693 |  | 
 | 1694 | 	if (pc->para.cause != NO_CAUSE) | 
 | 1695 | 		cause = pc->para.cause; | 
 | 1696 |  | 
 | 1697 | 	MsgHead(p, pc->callref, MT_RELEASE_COMPLETE); | 
 | 1698 |  | 
 | 1699 | 	*p++ = IE_CAUSE; | 
 | 1700 | 	*p++ = 0x2; | 
 | 1701 | 	*p++ = 0x80; | 
 | 1702 | 	*p++ = cause | 0x80; | 
 | 1703 |  | 
 | 1704 | 	l = p - tmp; | 
 | 1705 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 1706 | 		return; | 
 | 1707 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 1708 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 1709 | 	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); | 
 | 1710 | 	newl3state(pc, 0); | 
 | 1711 | 	ni1_release_l3_process(pc); | 
 | 1712 | } | 
 | 1713 |  | 
 | 1714 | static void | 
 | 1715 | l3ni1_release(struct l3_process *pc, u_char pr, void *arg) | 
 | 1716 | { | 
 | 1717 | 	struct sk_buff *skb = arg; | 
 | 1718 | 	u_char *p; | 
 | 1719 | 	int ret, cause=0; | 
 | 1720 |  | 
 | 1721 | 	StopAllL3Timer(pc); | 
 | 1722 | 	if ((ret = l3ni1_get_cause(pc, skb))>0) { | 
 | 1723 | 		if (pc->debug & L3_DEB_WARN) | 
 | 1724 | 			l3_debug(pc->st, "REL get_cause ret(%d)", ret); | 
 | 1725 | 	} else if (ret<0) | 
 | 1726 | 		pc->para.cause = NO_CAUSE; | 
 | 1727 | 	if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { | 
 | 1728 | 		l3ni1_parse_facility(pc->st, pc, pc->callref, p); | 
 | 1729 | 	} | 
 | 1730 | 	if ((ret<0) && (pc->state != 11)) | 
 | 1731 | 		cause = 96; | 
 | 1732 | 	else if (ret>0) | 
 | 1733 | 		cause = 100; | 
 | 1734 | 	ret = check_infoelements(pc, skb, ie_RELEASE); | 
 | 1735 | 	if (ERR_IE_COMPREHENSION == ret) | 
 | 1736 | 		cause = 96; | 
 | 1737 | 	else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause)) | 
 | 1738 | 		cause = 99;   | 
 | 1739 | 	if (cause) | 
 | 1740 | 		l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause); | 
 | 1741 | 	else | 
 | 1742 | 		l3ni1_message(pc, MT_RELEASE_COMPLETE); | 
 | 1743 | 	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); | 
 | 1744 | 	newl3state(pc, 0); | 
 | 1745 | 	ni1_release_l3_process(pc); | 
 | 1746 | } | 
 | 1747 |  | 
 | 1748 | static void | 
 | 1749 | l3ni1_alert_req(struct l3_process *pc, u_char pr, | 
 | 1750 | 		 void *arg) | 
 | 1751 | { | 
 | 1752 | 	newl3state(pc, 7); | 
 | 1753 | 	if (!pc->prot.ni1.uus1_data[0])  | 
 | 1754 | 		l3ni1_message(pc, MT_ALERTING); | 
 | 1755 | 	else | 
 | 1756 | 		l3ni1_msg_with_uus(pc, MT_ALERTING);  | 
 | 1757 | } | 
 | 1758 |  | 
 | 1759 | static void | 
 | 1760 | l3ni1_proceed_req(struct l3_process *pc, u_char pr, | 
 | 1761 | 		   void *arg) | 
 | 1762 | { | 
 | 1763 | 	newl3state(pc, 9); | 
 | 1764 | 	l3ni1_message(pc, MT_CALL_PROCEEDING); | 
 | 1765 | 	pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);  | 
 | 1766 | } | 
 | 1767 |  | 
 | 1768 | static void | 
 | 1769 | l3ni1_setup_ack_req(struct l3_process *pc, u_char pr, | 
 | 1770 | 		   void *arg) | 
 | 1771 | { | 
 | 1772 | 	newl3state(pc, 25); | 
 | 1773 | 	L3DelTimer(&pc->timer); | 
 | 1774 | 	L3AddTimer(&pc->timer, T302, CC_T302); | 
 | 1775 | 	l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE); | 
 | 1776 | } | 
 | 1777 |  | 
 | 1778 | /********************************************/ | 
 | 1779 | /* deliver a incoming display message to HL */ | 
 | 1780 | /********************************************/ | 
 | 1781 | static void | 
 | 1782 | l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp) | 
 | 1783 | {       u_char len; | 
 | 1784 |         isdn_ctrl ic;  | 
 | 1785 | 	struct IsdnCardState *cs; | 
 | 1786 |         char *p;  | 
 | 1787 |  | 
 | 1788 |         if (*infp++ != IE_DISPLAY) return; | 
 | 1789 |         if ((len = *infp++) > 80) return; /* total length <= 82 */ | 
 | 1790 | 	if (!pc->chan) return; | 
 | 1791 |  | 
 | 1792 | 	p = ic.parm.display;  | 
 | 1793 |         while (len--) | 
 | 1794 | 	  *p++ = *infp++; | 
 | 1795 | 	*p = '\0'; | 
 | 1796 | 	ic.command = ISDN_STAT_DISPLAY; | 
 | 1797 | 	cs = pc->st->l1.hardware; | 
 | 1798 | 	ic.driver = cs->myid; | 
 | 1799 | 	ic.arg = pc->chan->chan;  | 
 | 1800 | 	cs->iif.statcallb(&ic); | 
 | 1801 | } /* l3ni1_deliver_display */ | 
 | 1802 |  | 
 | 1803 |  | 
 | 1804 | static void | 
 | 1805 | l3ni1_progress(struct l3_process *pc, u_char pr, void *arg) | 
 | 1806 | { | 
 | 1807 | 	struct sk_buff *skb = arg; | 
 | 1808 | 	int err = 0; | 
 | 1809 | 	u_char *p; | 
 | 1810 |  | 
 | 1811 | 	if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) { | 
 | 1812 | 		if (p[1] != 2) { | 
 | 1813 | 			err = 1; | 
 | 1814 | 			pc->para.cause = 100; | 
 | 1815 | 		} else if (!(p[2] & 0x70)) { | 
 | 1816 | 			switch (p[2]) { | 
 | 1817 | 				case 0x80: | 
 | 1818 | 				case 0x81: | 
 | 1819 | 				case 0x82: | 
 | 1820 | 				case 0x84: | 
 | 1821 | 				case 0x85: | 
 | 1822 | 				case 0x87: | 
 | 1823 | 				case 0x8a: | 
 | 1824 | 					switch (p[3]) { | 
 | 1825 | 						case 0x81: | 
 | 1826 | 						case 0x82: | 
 | 1827 | 						case 0x83: | 
 | 1828 | 						case 0x84: | 
 | 1829 | 						case 0x88: | 
 | 1830 | 							break; | 
 | 1831 | 						default: | 
 | 1832 | 							err = 2; | 
 | 1833 | 							pc->para.cause = 100; | 
 | 1834 | 							break; | 
 | 1835 | 					} | 
 | 1836 | 					break; | 
 | 1837 | 				default: | 
 | 1838 | 					err = 3; | 
 | 1839 | 					pc->para.cause = 100; | 
 | 1840 | 					break; | 
 | 1841 | 			} | 
 | 1842 | 		} | 
 | 1843 | 	} else { | 
 | 1844 | 		pc->para.cause = 96; | 
 | 1845 | 		err = 4; | 
 | 1846 | 	} | 
 | 1847 | 	if (err) {	 | 
 | 1848 | 		if (pc->debug & L3_DEB_WARN) | 
 | 1849 | 			l3_debug(pc->st, "progress error %d", err); | 
 | 1850 | 		l3ni1_status_send(pc, pr, NULL); | 
 | 1851 | 		return; | 
 | 1852 | 	} | 
 | 1853 | 	/* Now we are on none mandatory IEs */ | 
 | 1854 | 	err = check_infoelements(pc, skb, ie_PROGRESS); | 
 | 1855 | 	if (err) | 
 | 1856 | 		l3ni1_std_ie_err(pc, err); | 
 | 1857 | 	if (ERR_IE_COMPREHENSION != err) | 
 | 1858 | 		pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc); | 
 | 1859 | } | 
 | 1860 |  | 
 | 1861 | static void | 
 | 1862 | l3ni1_notify(struct l3_process *pc, u_char pr, void *arg) | 
 | 1863 | { | 
 | 1864 | 	struct sk_buff *skb = arg; | 
 | 1865 | 	int err = 0; | 
 | 1866 | 	u_char *p; | 
 | 1867 |  | 
 | 1868 | 	if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) { | 
 | 1869 | 		if (p[1] != 1) { | 
 | 1870 | 			err = 1; | 
 | 1871 | 			pc->para.cause = 100; | 
 | 1872 | 		} else { | 
 | 1873 | 			switch (p[2]) { | 
 | 1874 | 				case 0x80: | 
 | 1875 | 				case 0x81: | 
 | 1876 | 				case 0x82: | 
 | 1877 | 					break; | 
 | 1878 | 				default: | 
 | 1879 | 					pc->para.cause = 100; | 
 | 1880 | 					err = 2; | 
 | 1881 | 					break; | 
 | 1882 | 			} | 
 | 1883 | 		} | 
 | 1884 | 	} else { | 
 | 1885 | 		pc->para.cause = 96; | 
 | 1886 | 		err = 3; | 
 | 1887 | 	} | 
 | 1888 | 	if (err) {	 | 
 | 1889 | 		if (pc->debug & L3_DEB_WARN) | 
 | 1890 | 			l3_debug(pc->st, "notify error %d", err); | 
 | 1891 | 		l3ni1_status_send(pc, pr, NULL); | 
 | 1892 | 		return; | 
 | 1893 | 	} | 
 | 1894 | 	/* Now we are on none mandatory IEs */ | 
 | 1895 | 	err = check_infoelements(pc, skb, ie_NOTIFY); | 
 | 1896 | 	if (err) | 
 | 1897 | 		l3ni1_std_ie_err(pc, err); | 
 | 1898 | 	if (ERR_IE_COMPREHENSION != err) | 
 | 1899 | 		pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc); | 
 | 1900 | } | 
 | 1901 |  | 
 | 1902 | static void | 
 | 1903 | l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg) | 
 | 1904 | { | 
 | 1905 | 	int ret; | 
 | 1906 | 	struct sk_buff *skb = arg; | 
 | 1907 |  | 
 | 1908 | 	ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY); | 
 | 1909 | 	l3ni1_std_ie_err(pc, ret); | 
 | 1910 | 	pc->para.cause = 30; /* response to STATUS_ENQUIRY */ | 
 | 1911 |         l3ni1_status_send(pc, pr, NULL); | 
 | 1912 | } | 
 | 1913 |  | 
 | 1914 | static void | 
 | 1915 | l3ni1_information(struct l3_process *pc, u_char pr, void *arg) | 
 | 1916 | { | 
 | 1917 | 	int ret; | 
 | 1918 | 	struct sk_buff *skb = arg; | 
 | 1919 | 	u_char *p; | 
 | 1920 | 	char tmp[32]; | 
 | 1921 |  | 
 | 1922 | 	ret = check_infoelements(pc, skb, ie_INFORMATION); | 
 | 1923 | 	if (ret) | 
 | 1924 | 		l3ni1_std_ie_err(pc, ret); | 
 | 1925 | 	if (pc->state == 25) { /* overlap receiving */ | 
 | 1926 | 		L3DelTimer(&pc->timer); | 
 | 1927 | 		p = skb->data; | 
 | 1928 | 		if ((p = findie(p, skb->len, 0x70, 0))) { | 
 | 1929 | 			iecpy(tmp, p, 1); | 
 | 1930 | 			strcat(pc->para.setup.eazmsn, tmp); | 
 | 1931 | 			pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); | 
 | 1932 | 		} | 
 | 1933 | 		L3AddTimer(&pc->timer, T302, CC_T302); | 
 | 1934 | 	} | 
 | 1935 | } | 
 | 1936 |  | 
 | 1937 | /******************************/ | 
 | 1938 | /* handle deflection requests */ | 
 | 1939 | /******************************/ | 
 | 1940 | static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg) | 
 | 1941 | { | 
 | 1942 | 	struct sk_buff *skb; | 
 | 1943 | 	u_char tmp[128]; | 
 | 1944 | 	u_char *p = tmp; | 
 | 1945 |         u_char *subp; | 
 | 1946 |         u_char len_phone = 0; | 
 | 1947 |         u_char len_sub = 0; | 
 | 1948 | 	int l;  | 
 | 1949 |  | 
 | 1950 |  | 
 | 1951 |         strcpy(pc->prot.ni1.uus1_data,pc->chan->setup.eazmsn); /* copy uus element if available */ | 
 | 1952 |         if (!pc->chan->setup.phone[0]) | 
 | 1953 |           { pc->para.cause = -1; | 
 | 1954 |             l3ni1_disconnect_req(pc,pr,arg); /* disconnect immediately */ | 
 | 1955 |             return; | 
 | 1956 |           } /* only uus */ | 
 | 1957 |   | 
 | 1958 |         if (pc->prot.ni1.invoke_id)  | 
 | 1959 |           free_invoke_id(pc->st,pc->prot.ni1.invoke_id); | 
 | 1960 |   | 
 | 1961 |         if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st)))  | 
 | 1962 |           return; | 
 | 1963 |  | 
 | 1964 |         MsgHead(p, pc->callref, MT_FACILITY); | 
 | 1965 |  | 
 | 1966 |         for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */ | 
 | 1967 |         if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */  | 
 | 1968 |  | 
 | 1969 | 	*p++ = 0x1c;   /* Facility info element */ | 
 | 1970 |         *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */ | 
 | 1971 |         *p++ = 0x91;  /* remote operations protocol */ | 
 | 1972 |         *p++ = 0xa1;  /* invoke component */ | 
 | 1973 | 	   | 
 | 1974 |         *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */ | 
 | 1975 |         *p++ = 0x02;  /* invoke id tag, integer */ | 
 | 1976 | 	*p++ = 0x01;  /* length */ | 
 | 1977 |         *p++ = pc->prot.ni1.invoke_id;  /* invoke id */  | 
 | 1978 |         *p++ = 0x02;  /* operation value tag, integer */ | 
 | 1979 | 	*p++ = 0x01;  /* length */ | 
 | 1980 |         *p++ = 0x0D;  /* Call Deflect */ | 
 | 1981 | 	   | 
 | 1982 |         *p++ = 0x30;  /* sequence phone number */ | 
 | 1983 |         *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */ | 
 | 1984 | 	   | 
 | 1985 |         *p++ = 0x30;  /* Deflected to UserNumber */ | 
 | 1986 |         *p++ = len_phone+2+len_sub; /* length */ | 
 | 1987 |         *p++ = 0x80; /* NumberDigits */ | 
 | 1988 | 	*p++ = len_phone; /* length */ | 
 | 1989 |         for (l = 0; l < len_phone; l++) | 
 | 1990 | 	 *p++ = pc->chan->setup.phone[l]; | 
 | 1991 |  | 
 | 1992 |         if (len_sub) | 
 | 1993 | 	  { *p++ = 0x04; /* called party subaddress */ | 
 | 1994 |             *p++ = len_sub - 2; | 
 | 1995 |             while (*subp) *p++ = *subp++; | 
 | 1996 |           } | 
 | 1997 |  | 
 | 1998 |         *p++ = 0x01; /* screening identifier */ | 
 | 1999 |         *p++ = 0x01; | 
 | 2000 |         *p++ = pc->chan->setup.screen; | 
 | 2001 |  | 
 | 2002 | 	l = p - tmp; | 
 | 2003 | 	if (!(skb = l3_alloc_skb(l))) return; | 
 | 2004 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 2005 |  | 
 | 2006 |         l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 2007 | } /* l3ni1_redir_req */ | 
 | 2008 |  | 
 | 2009 | /********************************************/ | 
 | 2010 | /* handle deflection request in early state */ | 
 | 2011 | /********************************************/ | 
 | 2012 | static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg) | 
 | 2013 | { | 
 | 2014 |   l3ni1_proceed_req(pc,pr,arg); | 
 | 2015 |   l3ni1_redir_req(pc,pr,arg); | 
 | 2016 | } /* l3ni1_redir_req_early */ | 
 | 2017 |  | 
 | 2018 | /***********************************************/ | 
 | 2019 | /* handle special commands for this protocol.  */ | 
| Lucas De Marchi | 25985ed | 2011-03-30 22:57:33 -0300 | [diff] [blame] | 2020 | /* Examples are call independent services like */ | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2021 | /* remote operations with dummy  callref.      */ | 
 | 2022 | /***********************************************/ | 
 | 2023 | static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic) | 
 | 2024 | { u_char id; | 
 | 2025 |   u_char temp[265]; | 
 | 2026 |   u_char *p = temp; | 
 | 2027 |   int i, l, proc_len;  | 
 | 2028 |   struct sk_buff *skb; | 
 | 2029 |   struct l3_process *pc = NULL; | 
 | 2030 |  | 
 | 2031 |   switch (ic->arg) | 
 | 2032 |    { case NI1_CMD_INVOKE: | 
 | 2033 |        if (ic->parm.ni1_io.datalen < 0) return(-2); /* invalid parameter */  | 
 | 2034 |  | 
 | 2035 |        for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++)  | 
 | 2036 |          i = i >> 8; /* add one byte */     | 
 | 2037 |        l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */ | 
 | 2038 |        if (l > 255)  | 
 | 2039 |          return(-2); /* too long */ | 
 | 2040 |  | 
 | 2041 |        if (!(id = new_invoke_id(st)))  | 
 | 2042 |          return(0); /* first get a invoke id -> return if no available */ | 
 | 2043 |         | 
 | 2044 |        i = -1;  | 
 | 2045 |        MsgHead(p, i, MT_FACILITY); /* build message head */ | 
 | 2046 |        *p++ = 0x1C; /* Facility IE */ | 
 | 2047 |        *p++ = l; /* length of ie */ | 
 | 2048 |        *p++ = 0x91; /* remote operations */ | 
 | 2049 |        *p++ = 0xA1; /* invoke */ | 
 | 2050 |        *p++ = l - 3; /* length of invoke */ | 
 | 2051 |        *p++ = 0x02; /* invoke id tag */ | 
 | 2052 |        *p++ = 0x01; /* length is 1 */ | 
 | 2053 |        *p++ = id; /* invoke id */ | 
 | 2054 |        *p++ = 0x02; /* operation */ | 
 | 2055 |        *p++ = proc_len; /* length of operation */ | 
 | 2056 |         | 
 | 2057 |        for (i = proc_len; i; i--) | 
 | 2058 |          *p++ = (ic->parm.ni1_io.proc >> (i-1)) & 0xFF; | 
 | 2059 |        memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */ | 
 | 2060 |        l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */          | 
 | 2061 |  | 
 | 2062 |        if (ic->parm.ni1_io.timeout > 0) | 
 | 2063 |         if (!(pc = ni1_new_l3_process(st, -1))) | 
 | 2064 |           { free_invoke_id(st, id); | 
 | 2065 |             return(-2); | 
 | 2066 |           }  | 
 | 2067 |        pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id; /* remember id */  | 
 | 2068 |        pc->prot.ni1.proc = ic->parm.ni1_io.proc; /* and procedure */ | 
 | 2069 |  | 
 | 2070 |        if (!(skb = l3_alloc_skb(l)))  | 
 | 2071 |          { free_invoke_id(st, id); | 
 | 2072 |            if (pc) ni1_release_l3_process(pc); | 
 | 2073 |            return(-2); | 
 | 2074 |          } | 
 | 2075 |        memcpy(skb_put(skb, l), temp, l); | 
 | 2076 |         | 
 | 2077 |        if (pc) | 
 | 2078 |         { pc->prot.ni1.invoke_id = id; /* remember id */ | 
 | 2079 |           L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST); | 
 | 2080 |         } | 
 | 2081 |         | 
 | 2082 |        l3_msg(st, DL_DATA | REQUEST, skb); | 
 | 2083 |        ic->parm.ni1_io.hl_id = id; /* return id */ | 
 | 2084 |        return(0); | 
 | 2085 |  | 
 | 2086 |      case NI1_CMD_INVOKE_ABORT: | 
 | 2087 |        if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id))) | 
 | 2088 | 	{ L3DelTimer(&pc->timer); /* remove timer */ | 
 | 2089 |           ni1_release_l3_process(pc); | 
 | 2090 |           return(0);  | 
 | 2091 |         }  | 
 | 2092 |        else | 
 | 2093 | 	{ l3_debug(st, "l3ni1_cmd_global abort unknown id"); | 
 | 2094 |           return(-2); | 
 | 2095 |         }  | 
 | 2096 |        break; | 
 | 2097 |      | 
 | 2098 |      default:  | 
 | 2099 |        l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg); | 
 | 2100 |        return(-1);   | 
 | 2101 |    } /* switch ic-> arg */ | 
 | 2102 |   return(-1); | 
 | 2103 | } /* l3ni1_cmd_global */ | 
 | 2104 |  | 
 | 2105 | static void  | 
 | 2106 | l3ni1_io_timer(struct l3_process *pc) | 
 | 2107 | { isdn_ctrl ic; | 
 | 2108 |   struct IsdnCardState *cs = pc->st->l1.hardware; | 
 | 2109 |  | 
 | 2110 |   L3DelTimer(&pc->timer); /* remove timer */ | 
 | 2111 |  | 
 | 2112 |   ic.driver = cs->myid; | 
 | 2113 |   ic.command = ISDN_STAT_PROT; | 
 | 2114 |   ic.arg = NI1_STAT_INVOKE_ERR; | 
 | 2115 |   ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id; | 
 | 2116 |   ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id; | 
 | 2117 |   ic.parm.ni1_io.proc = pc->prot.ni1.proc; | 
 | 2118 |   ic.parm.ni1_io.timeout= -1; | 
 | 2119 |   ic.parm.ni1_io.datalen = 0; | 
 | 2120 |   ic.parm.ni1_io.data = NULL; | 
 | 2121 |   free_invoke_id(pc->st, pc->prot.ni1.invoke_id); | 
 | 2122 |   pc->prot.ni1.invoke_id = 0; /* reset id */ | 
 | 2123 |  | 
 | 2124 |   cs->iif.statcallb(&ic); | 
 | 2125 |  | 
 | 2126 |   ni1_release_l3_process(pc);  | 
 | 2127 | } /* l3ni1_io_timer */ | 
 | 2128 |  | 
 | 2129 | static void | 
 | 2130 | l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg) | 
 | 2131 | { | 
 | 2132 | 	u_char *p; | 
 | 2133 | 	struct sk_buff *skb = arg; | 
 | 2134 | 	int callState = 0; | 
 | 2135 | 	p = skb->data; | 
 | 2136 |  | 
 | 2137 | 	if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) { | 
 | 2138 | 		p++; | 
 | 2139 | 		if (1 == *p++) | 
 | 2140 | 			callState = *p; | 
 | 2141 | 	} | 
 | 2142 | 	if (callState == 0) { | 
 | 2143 | 		/* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1 | 
 | 2144 | 		 * set down layer 3 without sending any message | 
 | 2145 | 		 */ | 
 | 2146 | 		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); | 
 | 2147 | 		newl3state(pc, 0); | 
 | 2148 | 		ni1_release_l3_process(pc); | 
 | 2149 | 	} else { | 
 | 2150 | 		pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc); | 
 | 2151 | 	} | 
 | 2152 | } | 
 | 2153 |  | 
 | 2154 | static void | 
 | 2155 | l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg) | 
 | 2156 | { | 
 | 2157 | } | 
 | 2158 |  | 
 | 2159 | static void | 
 | 2160 | l3ni1_t302(struct l3_process *pc, u_char pr, void *arg) | 
 | 2161 | { | 
 | 2162 | 	L3DelTimer(&pc->timer); | 
 | 2163 | 	pc->para.loc = 0; | 
 | 2164 | 	pc->para.cause = 28; /* invalid number */ | 
 | 2165 | 	l3ni1_disconnect_req(pc, pr, NULL); | 
 | 2166 | 	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); | 
 | 2167 | } | 
 | 2168 |  | 
 | 2169 | static void | 
 | 2170 | l3ni1_t303(struct l3_process *pc, u_char pr, void *arg) | 
 | 2171 | { | 
 | 2172 | 	if (pc->N303 > 0) { | 
 | 2173 | 		pc->N303--; | 
 | 2174 | 		L3DelTimer(&pc->timer); | 
 | 2175 | 		l3ni1_setup_req(pc, pr, arg); | 
 | 2176 | 	} else { | 
 | 2177 | 		L3DelTimer(&pc->timer); | 
 | 2178 | 		l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102); | 
 | 2179 | 		pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc); | 
 | 2180 | 		ni1_release_l3_process(pc); | 
 | 2181 | 	} | 
 | 2182 | } | 
 | 2183 |  | 
 | 2184 | static void | 
 | 2185 | l3ni1_t304(struct l3_process *pc, u_char pr, void *arg) | 
 | 2186 | { | 
 | 2187 | 	L3DelTimer(&pc->timer); | 
 | 2188 | 	pc->para.loc = 0; | 
 | 2189 | 	pc->para.cause = 102; | 
 | 2190 | 	l3ni1_disconnect_req(pc, pr, NULL); | 
 | 2191 | 	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); | 
 | 2192 |  | 
 | 2193 | } | 
 | 2194 |  | 
 | 2195 | static void | 
 | 2196 | l3ni1_t305(struct l3_process *pc, u_char pr, void *arg) | 
 | 2197 | { | 
 | 2198 | 	u_char tmp[16]; | 
 | 2199 | 	u_char *p = tmp; | 
 | 2200 | 	int l; | 
 | 2201 | 	struct sk_buff *skb; | 
 | 2202 | 	u_char cause = 16; | 
 | 2203 |  | 
 | 2204 | 	L3DelTimer(&pc->timer); | 
 | 2205 | 	if (pc->para.cause != NO_CAUSE) | 
 | 2206 | 		cause = pc->para.cause; | 
 | 2207 |  | 
 | 2208 | 	MsgHead(p, pc->callref, MT_RELEASE); | 
 | 2209 |  | 
 | 2210 | 	*p++ = IE_CAUSE; | 
 | 2211 | 	*p++ = 0x2; | 
 | 2212 | 	*p++ = 0x80; | 
 | 2213 | 	*p++ = cause | 0x80; | 
 | 2214 |  | 
 | 2215 | 	l = p - tmp; | 
 | 2216 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 2217 | 		return; | 
 | 2218 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 2219 | 	newl3state(pc, 19); | 
 | 2220 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 2221 | 	L3AddTimer(&pc->timer, T308, CC_T308_1); | 
 | 2222 | } | 
 | 2223 |  | 
 | 2224 | static void | 
 | 2225 | l3ni1_t310(struct l3_process *pc, u_char pr, void *arg) | 
 | 2226 | { | 
 | 2227 | 	L3DelTimer(&pc->timer); | 
 | 2228 | 	pc->para.loc = 0; | 
 | 2229 | 	pc->para.cause = 102; | 
 | 2230 | 	l3ni1_disconnect_req(pc, pr, NULL); | 
 | 2231 | 	pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); | 
 | 2232 | } | 
 | 2233 |  | 
 | 2234 | static void | 
 | 2235 | l3ni1_t313(struct l3_process *pc, u_char pr, void *arg) | 
 | 2236 | { | 
 | 2237 | 	L3DelTimer(&pc->timer); | 
 | 2238 | 	pc->para.loc = 0; | 
 | 2239 | 	pc->para.cause = 102; | 
 | 2240 | 	l3ni1_disconnect_req(pc, pr, NULL); | 
 | 2241 | 	pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); | 
 | 2242 | } | 
 | 2243 |  | 
 | 2244 | static void | 
 | 2245 | l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg) | 
 | 2246 | { | 
 | 2247 | 	newl3state(pc, 19); | 
 | 2248 | 	L3DelTimer(&pc->timer); | 
 | 2249 | 	l3ni1_message(pc, MT_RELEASE); | 
 | 2250 | 	L3AddTimer(&pc->timer, T308, CC_T308_2); | 
 | 2251 | } | 
 | 2252 |  | 
 | 2253 | static void | 
 | 2254 | l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg) | 
 | 2255 | { | 
 | 2256 | 	L3DelTimer(&pc->timer); | 
 | 2257 | 	pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); | 
 | 2258 | 	ni1_release_l3_process(pc); | 
 | 2259 | } | 
 | 2260 |  | 
 | 2261 | static void | 
 | 2262 | l3ni1_t318(struct l3_process *pc, u_char pr, void *arg) | 
 | 2263 | { | 
 | 2264 | 	L3DelTimer(&pc->timer); | 
 | 2265 | 	pc->para.cause = 102;	/* Timer expiry */ | 
 | 2266 | 	pc->para.loc = 0;	/* local */ | 
 | 2267 | 	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); | 
 | 2268 | 	newl3state(pc, 19); | 
 | 2269 | 	l3ni1_message(pc, MT_RELEASE); | 
 | 2270 | 	L3AddTimer(&pc->timer, T308, CC_T308_1); | 
 | 2271 | } | 
 | 2272 |  | 
 | 2273 | static void | 
 | 2274 | l3ni1_t319(struct l3_process *pc, u_char pr, void *arg) | 
 | 2275 | { | 
 | 2276 | 	L3DelTimer(&pc->timer); | 
 | 2277 | 	pc->para.cause = 102;	/* Timer expiry */ | 
 | 2278 | 	pc->para.loc = 0;	/* local */ | 
 | 2279 | 	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); | 
 | 2280 | 	newl3state(pc, 10); | 
 | 2281 | } | 
 | 2282 |  | 
 | 2283 | static void | 
 | 2284 | l3ni1_restart(struct l3_process *pc, u_char pr, void *arg) | 
 | 2285 | { | 
 | 2286 | 	L3DelTimer(&pc->timer); | 
 | 2287 | 	pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); | 
 | 2288 | 	ni1_release_l3_process(pc); | 
 | 2289 | } | 
 | 2290 |  | 
 | 2291 | static void | 
 | 2292 | l3ni1_status(struct l3_process *pc, u_char pr, void *arg) | 
 | 2293 | { | 
 | 2294 | 	u_char *p; | 
 | 2295 | 	struct sk_buff *skb = arg; | 
 | 2296 | 	int ret;  | 
 | 2297 | 	u_char cause = 0, callState = 0; | 
 | 2298 | 	 | 
 | 2299 | 	if ((ret = l3ni1_get_cause(pc, skb))) { | 
 | 2300 | 		if (pc->debug & L3_DEB_WARN) | 
 | 2301 | 			l3_debug(pc->st, "STATUS get_cause ret(%d)",ret); | 
 | 2302 | 		if (ret < 0) | 
 | 2303 | 			cause = 96; | 
 | 2304 | 		else if (ret > 0) | 
 | 2305 | 			cause = 100; | 
 | 2306 | 	} | 
 | 2307 | 	if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) { | 
 | 2308 | 		p++; | 
 | 2309 | 		if (1 == *p++) { | 
 | 2310 | 			callState = *p; | 
 | 2311 | 			if (!ie_in_set(pc, *p, l3_valid_states)) | 
 | 2312 | 				cause = 100; | 
 | 2313 | 		} else | 
 | 2314 | 			cause = 100; | 
 | 2315 | 	} else | 
 | 2316 | 		cause = 96; | 
 | 2317 | 	if (!cause) { /*  no error before */ | 
 | 2318 | 		ret = check_infoelements(pc, skb, ie_STATUS); | 
 | 2319 | 		if (ERR_IE_COMPREHENSION == ret) | 
 | 2320 | 			cause = 96; | 
 | 2321 | 		else if (ERR_IE_UNRECOGNIZED == ret) | 
 | 2322 | 			cause = 99; | 
 | 2323 | 	} | 
 | 2324 | 	if (cause) { | 
 | 2325 | 		u_char tmp; | 
 | 2326 | 		 | 
 | 2327 | 		if (pc->debug & L3_DEB_WARN) | 
 | 2328 | 			l3_debug(pc->st, "STATUS error(%d/%d)",ret,cause); | 
 | 2329 | 		tmp = pc->para.cause; | 
 | 2330 | 		pc->para.cause = cause; | 
 | 2331 | 		l3ni1_status_send(pc, 0, NULL); | 
 | 2332 | 		if (cause == 99) | 
 | 2333 | 			pc->para.cause = tmp; | 
 | 2334 | 		else | 
 | 2335 | 			return; | 
 | 2336 | 	} | 
 | 2337 | 	cause = pc->para.cause; | 
 | 2338 | 	if (((cause & 0x7f) == 111) && (callState == 0)) { | 
 | 2339 | 		/* ETS 300-104 7.6.1, 8.6.1, 10.6.1... | 
 | 2340 | 		 * if received MT_STATUS with cause == 111 and call | 
 | 2341 | 		 * state == 0, then we must set down layer 3 | 
 | 2342 | 		 */ | 
 | 2343 | 		pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); | 
 | 2344 | 		newl3state(pc, 0); | 
 | 2345 | 		ni1_release_l3_process(pc); | 
 | 2346 | 	} | 
 | 2347 | } | 
 | 2348 |  | 
 | 2349 | static void | 
 | 2350 | l3ni1_facility(struct l3_process *pc, u_char pr, void *arg) | 
 | 2351 | { | 
 | 2352 | 	struct sk_buff *skb = arg; | 
 | 2353 | 	int ret; | 
 | 2354 | 	 | 
 | 2355 | 	ret = check_infoelements(pc, skb, ie_FACILITY); | 
 | 2356 | 	l3ni1_std_ie_err(pc, ret); | 
 | 2357 |  	  { | 
 | 2358 | 		u_char *p; | 
 | 2359 | 		if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) | 
 | 2360 | 			l3ni1_parse_facility(pc->st, pc, pc->callref, p); | 
 | 2361 | 	} | 
 | 2362 | } | 
 | 2363 |  | 
 | 2364 | static void | 
 | 2365 | l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg) | 
 | 2366 | { | 
 | 2367 | 	struct sk_buff *skb; | 
 | 2368 | 	u_char tmp[32]; | 
 | 2369 | 	u_char *p = tmp; | 
 | 2370 | 	u_char i, l; | 
 | 2371 | 	u_char *msg = pc->chan->setup.phone; | 
 | 2372 |  | 
 | 2373 | 	MsgHead(p, pc->callref, MT_SUSPEND); | 
 | 2374 | 	l = *msg++; | 
 | 2375 | 	if (l && (l <= 10)) {	/* Max length 10 octets */ | 
 | 2376 | 		*p++ = IE_CALL_ID; | 
 | 2377 | 		*p++ = l; | 
 | 2378 | 		for (i = 0; i < l; i++) | 
 | 2379 | 			*p++ = *msg++; | 
 | 2380 | 	} else if (l) { | 
 | 2381 | 		l3_debug(pc->st, "SUS wrong CALL_ID len %d", l); | 
 | 2382 | 		return; | 
 | 2383 | 	} | 
 | 2384 | 	l = p - tmp; | 
 | 2385 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 2386 | 		return; | 
 | 2387 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 2388 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 2389 | 	newl3state(pc, 15); | 
 | 2390 | 	L3AddTimer(&pc->timer, T319, CC_T319); | 
 | 2391 | } | 
 | 2392 |  | 
 | 2393 | static void | 
 | 2394 | l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg) | 
 | 2395 | { | 
 | 2396 | 	struct sk_buff *skb = arg; | 
 | 2397 | 	int ret; | 
 | 2398 |  | 
 | 2399 | 	L3DelTimer(&pc->timer); | 
 | 2400 | 	newl3state(pc, 0); | 
 | 2401 | 	pc->para.cause = NO_CAUSE; | 
 | 2402 | 	pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc); | 
 | 2403 | 	/* We don't handle suspend_ack for IE errors now */ | 
 | 2404 | 	if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE))) | 
 | 2405 | 		if (pc->debug & L3_DEB_WARN) | 
 | 2406 | 			l3_debug(pc->st, "SUSPACK check ie(%d)",ret); | 
 | 2407 | 	ni1_release_l3_process(pc); | 
 | 2408 | } | 
 | 2409 |  | 
 | 2410 | static void | 
 | 2411 | l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg) | 
 | 2412 | { | 
 | 2413 | 	struct sk_buff *skb = arg; | 
 | 2414 | 	int ret; | 
 | 2415 |  | 
 | 2416 | 	if ((ret = l3ni1_get_cause(pc, skb))) { | 
 | 2417 | 		if (pc->debug & L3_DEB_WARN) | 
 | 2418 | 			l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)",ret); | 
 | 2419 | 		if (ret < 0)  | 
 | 2420 | 			pc->para.cause = 96; | 
 | 2421 | 		else | 
 | 2422 | 			pc->para.cause = 100; | 
 | 2423 | 		l3ni1_status_send(pc, pr, NULL); | 
 | 2424 | 		return; | 
 | 2425 | 	} | 
 | 2426 | 	ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT); | 
 | 2427 | 	if (ERR_IE_COMPREHENSION == ret) { | 
 | 2428 | 		l3ni1_std_ie_err(pc, ret); | 
 | 2429 | 		return; | 
 | 2430 | 	} | 
 | 2431 | 	L3DelTimer(&pc->timer); | 
 | 2432 | 	pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc); | 
 | 2433 | 	newl3state(pc, 10); | 
 | 2434 | 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */ | 
 | 2435 | 		l3ni1_std_ie_err(pc, ret); | 
 | 2436 | } | 
 | 2437 |  | 
 | 2438 | static void | 
 | 2439 | l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg) | 
 | 2440 | { | 
 | 2441 | 	struct sk_buff *skb; | 
 | 2442 | 	u_char tmp[32]; | 
 | 2443 | 	u_char *p = tmp; | 
 | 2444 | 	u_char i, l; | 
 | 2445 | 	u_char *msg = pc->para.setup.phone; | 
 | 2446 |  | 
 | 2447 | 	MsgHead(p, pc->callref, MT_RESUME); | 
 | 2448 |  | 
 | 2449 | 	l = *msg++; | 
 | 2450 | 	if (l && (l <= 10)) {	/* Max length 10 octets */ | 
 | 2451 | 		*p++ = IE_CALL_ID; | 
 | 2452 | 		*p++ = l; | 
 | 2453 | 		for (i = 0; i < l; i++) | 
 | 2454 | 			*p++ = *msg++; | 
 | 2455 | 	} else if (l) { | 
 | 2456 | 		l3_debug(pc->st, "RES wrong CALL_ID len %d", l); | 
 | 2457 | 		return; | 
 | 2458 | 	} | 
 | 2459 | 	l = p - tmp; | 
 | 2460 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 2461 | 		return; | 
 | 2462 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 2463 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 2464 | 	newl3state(pc, 17); | 
 | 2465 | 	L3AddTimer(&pc->timer, T318, CC_T318); | 
 | 2466 | } | 
 | 2467 |  | 
 | 2468 | static void | 
 | 2469 | l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg) | 
 | 2470 | { | 
 | 2471 | 	struct sk_buff *skb = arg; | 
 | 2472 | 	int id, ret; | 
 | 2473 |  | 
 | 2474 | 	if ((id = l3ni1_get_channel_id(pc, skb)) > 0) { | 
 | 2475 | 		if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) { | 
 | 2476 | 			if (pc->debug & L3_DEB_WARN) | 
 | 2477 | 				l3_debug(pc->st, "resume ack with wrong chid %x", id); | 
 | 2478 | 			pc->para.cause = 100; | 
 | 2479 | 			l3ni1_status_send(pc, pr, NULL); | 
 | 2480 | 			return; | 
 | 2481 | 		} | 
 | 2482 | 		pc->para.bchannel = id; | 
 | 2483 | 	} else if (1 == pc->state) { | 
 | 2484 | 		if (pc->debug & L3_DEB_WARN) | 
 | 2485 | 			l3_debug(pc->st, "resume ack without chid (ret %d)", id); | 
 | 2486 | 		pc->para.cause = 96; | 
 | 2487 | 		l3ni1_status_send(pc, pr, NULL); | 
 | 2488 | 		return; | 
 | 2489 | 	} | 
 | 2490 | 	ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE); | 
 | 2491 | 	if (ERR_IE_COMPREHENSION == ret) { | 
 | 2492 | 		l3ni1_std_ie_err(pc, ret); | 
 | 2493 | 		return; | 
 | 2494 | 	} | 
 | 2495 | 	L3DelTimer(&pc->timer); | 
 | 2496 | 	pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc); | 
 | 2497 | 	newl3state(pc, 10); | 
 | 2498 | 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */ | 
 | 2499 | 		l3ni1_std_ie_err(pc, ret); | 
 | 2500 | } | 
 | 2501 |  | 
 | 2502 | static void | 
 | 2503 | l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg) | 
 | 2504 | { | 
 | 2505 | 	struct sk_buff *skb = arg; | 
 | 2506 | 	int ret; | 
 | 2507 |  | 
 | 2508 | 	if ((ret = l3ni1_get_cause(pc, skb))) { | 
 | 2509 | 		if (pc->debug & L3_DEB_WARN) | 
 | 2510 | 			l3_debug(pc->st, "RES_REJ get_cause ret(%d)",ret); | 
 | 2511 | 		if (ret < 0)  | 
 | 2512 | 			pc->para.cause = 96; | 
 | 2513 | 		else | 
 | 2514 | 			pc->para.cause = 100; | 
 | 2515 | 		l3ni1_status_send(pc, pr, NULL); | 
 | 2516 | 		return; | 
 | 2517 | 	} | 
 | 2518 | 	ret = check_infoelements(pc, skb, ie_RESUME_REJECT); | 
 | 2519 | 	if (ERR_IE_COMPREHENSION == ret) { | 
 | 2520 | 		l3ni1_std_ie_err(pc, ret); | 
 | 2521 | 		return; | 
 | 2522 | 	} | 
 | 2523 | 	L3DelTimer(&pc->timer); | 
 | 2524 | 	pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc); | 
 | 2525 | 	newl3state(pc, 0); | 
 | 2526 | 	if (ret) /* STATUS for none mandatory IE errors after actions are taken */ | 
 | 2527 | 		l3ni1_std_ie_err(pc, ret); | 
 | 2528 | 	ni1_release_l3_process(pc); | 
 | 2529 | } | 
 | 2530 |  | 
 | 2531 | static void | 
 | 2532 | l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg) | 
 | 2533 | { | 
 | 2534 | 	u_char tmp[32]; | 
 | 2535 | 	u_char *p; | 
 | 2536 | 	u_char ri, ch = 0, chan = 0; | 
 | 2537 | 	int l; | 
 | 2538 | 	struct sk_buff *skb = arg; | 
 | 2539 | 	struct l3_process *up; | 
 | 2540 |  | 
 | 2541 | 	newl3state(pc, 2); | 
 | 2542 | 	L3DelTimer(&pc->timer); | 
 | 2543 | 	p = skb->data; | 
 | 2544 | 	if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) { | 
 | 2545 | 		ri = p[2]; | 
 | 2546 | 		l3_debug(pc->st, "Restart %x", ri); | 
 | 2547 | 	} else { | 
 | 2548 | 		l3_debug(pc->st, "Restart without restart IE"); | 
 | 2549 | 		ri = 0x86; | 
 | 2550 | 	} | 
 | 2551 | 	p = skb->data; | 
 | 2552 | 	if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) { | 
 | 2553 | 		chan = p[2] & 3; | 
 | 2554 | 		ch = p[2]; | 
 | 2555 | 		if (pc->st->l3.debug) | 
 | 2556 | 			l3_debug(pc->st, "Restart for channel %d", chan); | 
 | 2557 | 	} | 
 | 2558 | 	newl3state(pc, 2); | 
 | 2559 | 	up = pc->st->l3.proc; | 
 | 2560 | 	while (up) { | 
 | 2561 | 		if ((ri & 7) == 7) | 
 | 2562 | 			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); | 
 | 2563 | 		else if (up->para.bchannel == chan) | 
 | 2564 | 			up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up); | 
 | 2565 | 		 | 
 | 2566 | 		up = up->next; | 
 | 2567 | 	} | 
 | 2568 | 	p = tmp; | 
 | 2569 | 	MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE); | 
 | 2570 | 	if (chan) { | 
 | 2571 | 		*p++ = IE_CHANNEL_ID; | 
 | 2572 | 		*p++ = 1; | 
 | 2573 | 		*p++ = ch | 0x80; | 
 | 2574 | 	} | 
 | 2575 | 	*p++ = 0x79;		/* RESTART Ind */ | 
 | 2576 | 	*p++ = 1; | 
 | 2577 | 	*p++ = ri; | 
 | 2578 | 	l = p - tmp; | 
 | 2579 | 	if (!(skb = l3_alloc_skb(l))) | 
 | 2580 | 		return; | 
 | 2581 | 	memcpy(skb_put(skb, l), tmp, l); | 
 | 2582 | 	newl3state(pc, 0); | 
 | 2583 | 	l3_msg(pc->st, DL_DATA | REQUEST, skb); | 
 | 2584 | } | 
 | 2585 |  | 
 | 2586 | static void | 
 | 2587 | l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg) | 
 | 2588 | { | 
 | 2589 |         pc->para.cause = 0x29;          /* Temporary failure */ | 
 | 2590 |         pc->para.loc = 0; | 
 | 2591 |         l3ni1_disconnect_req(pc, pr, NULL); | 
 | 2592 |         pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); | 
 | 2593 | } | 
 | 2594 |  | 
 | 2595 | static void | 
 | 2596 | l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg) | 
 | 2597 | { | 
 | 2598 |         newl3state(pc, 0); | 
 | 2599 |         pc->para.cause = 0x1b;          /* Destination out of order */ | 
 | 2600 |         pc->para.loc = 0; | 
 | 2601 |         pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); | 
 | 2602 |         release_l3_process(pc); | 
 | 2603 | } | 
 | 2604 |  | 
 | 2605 | static void | 
 | 2606 | l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg) | 
 | 2607 | { | 
 | 2608 |         L3DelTimer(&pc->timer); | 
 | 2609 |         L3AddTimer(&pc->timer, T309, CC_T309); | 
 | 2610 |         l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL); | 
 | 2611 | } | 
 | 2612 |   | 
 | 2613 | static void | 
 | 2614 | l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg) | 
 | 2615 | { | 
 | 2616 | 	L3DelTimer(&pc->timer); | 
 | 2617 |   | 
 | 2618 |  	pc->para.cause = 0x1F; /* normal, unspecified */ | 
 | 2619 | 	l3ni1_status_send(pc, 0, NULL); | 
 | 2620 | } | 
 | 2621 |  | 
 | 2622 | static void l3ni1_SendSpid( struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState ) | 
 | 2623 | { | 
 | 2624 | 	u_char         * p; | 
 | 2625 | 	char           * pSPID; | 
 | 2626 | 	struct Channel * pChan = pc->st->lli.userdata; | 
 | 2627 | 	int              l; | 
 | 2628 |  | 
 | 2629 | 	if ( skb ) | 
 | 2630 | 		dev_kfree_skb( skb); | 
 | 2631 |  | 
 | 2632 | 	if ( !( pSPID = strchr( pChan->setup.eazmsn, ':' ) ) ) | 
 | 2633 | 	{ | 
 | 2634 | 		printk( KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn ); | 
 | 2635 | 		newl3state( pc, 0 ); | 
 | 2636 | 		pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); | 
 | 2637 | 		return; | 
 | 2638 | 	} | 
 | 2639 |  | 
 | 2640 | 	l = strlen( ++pSPID ); | 
 | 2641 | 	if ( !( skb = l3_alloc_skb( 5+l ) ) ) | 
 | 2642 | 	{ | 
 | 2643 | 		printk( KERN_ERR "HiSax can't get memory to send SPID\n" ); | 
 | 2644 | 		return; | 
 | 2645 | 	} | 
 | 2646 |  | 
 | 2647 | 	p = skb_put( skb, 5 ); | 
 | 2648 | 	*p++ = PROTO_DIS_EURO; | 
 | 2649 | 	*p++ = 0; | 
 | 2650 | 	*p++ = MT_INFORMATION; | 
 | 2651 | 	*p++ = IE_SPID; | 
 | 2652 | 	*p++ = l; | 
 | 2653 |  | 
 | 2654 | 	memcpy( skb_put( skb, l ), pSPID, l ); | 
 | 2655 |  | 
 | 2656 | 	newl3state( pc, iNewState ); | 
 | 2657 |  | 
 | 2658 | 	L3DelTimer( &pc->timer ); | 
 | 2659 | 	L3AddTimer( &pc->timer, TSPID, CC_TSPID ); | 
 | 2660 |  | 
 | 2661 | 	pc->st->l3.l3l2( pc->st, DL_DATA | REQUEST, skb ); | 
 | 2662 | } | 
 | 2663 |  | 
 | 2664 | static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg ) | 
 | 2665 | { | 
 | 2666 | 	l3ni1_SendSpid( pc, pr, arg, 20 ); | 
 | 2667 | } | 
 | 2668 |  | 
| Adrian Bunk | 672c3fd | 2005-06-25 14:59:18 -0700 | [diff] [blame] | 2669 | static void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg ) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2670 | { | 
 | 2671 | 	struct sk_buff *skb = arg; | 
 | 2672 |  | 
 | 2673 | 	if ( skb->data[ 1 ] == 0 ) | 
 | 2674 | 		if ( skb->data[ 3 ] == IE_ENDPOINT_ID ) | 
 | 2675 | 		{ | 
 | 2676 | 			L3DelTimer( &pc->timer ); | 
 | 2677 | 			newl3state( pc, 0 ); | 
 | 2678 | 			l3_msg( pc->st, DL_ESTABLISH | CONFIRM, NULL ); | 
 | 2679 | 		} | 
 | 2680 | 	dev_kfree_skb( skb); | 
 | 2681 | } | 
 | 2682 |  | 
 | 2683 | static void l3ni1_spid_tout( struct l3_process *pc, u_char pr, void *arg ) | 
 | 2684 | { | 
 | 2685 | 	if ( pc->state < 22 ) | 
 | 2686 | 		l3ni1_SendSpid( pc, pr, arg, pc->state+1 ); | 
 | 2687 | 	else | 
 | 2688 | 	{ | 
 | 2689 | 		L3DelTimer( &pc->timer ); | 
 | 2690 | 		dev_kfree_skb( arg); | 
 | 2691 |  | 
 | 2692 | 		printk( KERN_ERR "SPID not accepted\n" ); | 
 | 2693 | 		newl3state( pc, 0 ); | 
 | 2694 | 		pc->st->l3.l3l2( pc->st, DL_RELEASE | REQUEST, NULL ); | 
 | 2695 | 	} | 
 | 2696 | } | 
 | 2697 |  | 
 | 2698 | /* *INDENT-OFF* */ | 
 | 2699 | static struct stateentry downstatelist[] = | 
 | 2700 | { | 
 | 2701 | 	{SBIT(0), | 
 | 2702 | 	 CC_SETUP | REQUEST, l3ni1_setup_req}, | 
 | 2703 | 	{SBIT(0), | 
 | 2704 | 	 CC_RESUME | REQUEST, l3ni1_resume_req}, | 
 | 2705 | 	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25), | 
 | 2706 | 	 CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, | 
 | 2707 | 	{SBIT(12), | 
 | 2708 | 	 CC_RELEASE | REQUEST, l3ni1_release_req}, | 
 | 2709 | 	{ALL_STATES, | 
 | 2710 | 	 CC_RESTART | REQUEST, l3ni1_restart}, | 
 | 2711 | 	{SBIT(6) | SBIT(25), | 
 | 2712 | 	 CC_IGNORE | REQUEST, l3ni1_reset}, | 
 | 2713 | 	{SBIT(6) | SBIT(25), | 
 | 2714 | 	 CC_REJECT | REQUEST, l3ni1_reject_req}, | 
 | 2715 | 	{SBIT(6) | SBIT(25), | 
 | 2716 | 	 CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req}, | 
 | 2717 | 	{SBIT(6), | 
 | 2718 | 	 CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req}, | 
 | 2719 | 	{SBIT(25), | 
 | 2720 | 	 CC_MORE_INFO | REQUEST, l3ni1_dummy}, | 
 | 2721 | 	{SBIT(6) | SBIT(9) | SBIT(25), | 
 | 2722 | 	 CC_ALERTING | REQUEST, l3ni1_alert_req}, | 
 | 2723 | 	{SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25), | 
 | 2724 | 	 CC_SETUP | RESPONSE, l3ni1_setup_rsp}, | 
 | 2725 | 	{SBIT(10), | 
 | 2726 | 	 CC_SUSPEND | REQUEST, l3ni1_suspend_req}, | 
 | 2727 |         {SBIT(7) | SBIT(9) | SBIT(25), | 
 | 2728 |          CC_REDIR | REQUEST, l3ni1_redir_req}, | 
 | 2729 |         {SBIT(6), | 
 | 2730 |          CC_REDIR | REQUEST, l3ni1_redir_req_early}, | 
 | 2731 |         {SBIT(9) | SBIT(25), | 
 | 2732 |          CC_DISCONNECT | REQUEST, l3ni1_disconnect_req}, | 
 | 2733 | 	{SBIT(25), | 
 | 2734 | 	 CC_T302, l3ni1_t302}, | 
 | 2735 | 	{SBIT(1), | 
 | 2736 | 	 CC_T303, l3ni1_t303}, | 
 | 2737 | 	{SBIT(2), | 
 | 2738 | 	 CC_T304, l3ni1_t304}, | 
 | 2739 | 	{SBIT(3), | 
 | 2740 | 	 CC_T310, l3ni1_t310}, | 
 | 2741 | 	{SBIT(8), | 
 | 2742 | 	 CC_T313, l3ni1_t313}, | 
 | 2743 | 	{SBIT(11), | 
 | 2744 | 	 CC_T305, l3ni1_t305}, | 
 | 2745 | 	{SBIT(15), | 
 | 2746 | 	 CC_T319, l3ni1_t319}, | 
 | 2747 | 	{SBIT(17), | 
 | 2748 | 	 CC_T318, l3ni1_t318}, | 
 | 2749 | 	{SBIT(19), | 
 | 2750 | 	 CC_T308_1, l3ni1_t308_1}, | 
 | 2751 | 	{SBIT(19), | 
 | 2752 | 	 CC_T308_2, l3ni1_t308_2}, | 
 | 2753 | 	{SBIT(10), | 
 | 2754 | 	 CC_T309, l3ni1_dl_release}, | 
 | 2755 | 	{ SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), | 
 | 2756 | 	 CC_TSPID, l3ni1_spid_tout }, | 
 | 2757 | }; | 
 | 2758 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2759 | static struct stateentry datastatelist[] = | 
 | 2760 | { | 
 | 2761 | 	{ALL_STATES, | 
 | 2762 | 	 MT_STATUS_ENQUIRY, l3ni1_status_enq}, | 
 | 2763 | 	{ALL_STATES, | 
 | 2764 | 	 MT_FACILITY, l3ni1_facility}, | 
 | 2765 | 	{SBIT(19), | 
 | 2766 | 	 MT_STATUS, l3ni1_release_ind}, | 
 | 2767 | 	{ALL_STATES, | 
 | 2768 | 	 MT_STATUS, l3ni1_status}, | 
 | 2769 | 	{SBIT(0), | 
 | 2770 | 	 MT_SETUP, l3ni1_setup}, | 
 | 2771 | 	{SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | | 
 | 2772 | 	 SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), | 
 | 2773 | 	 MT_SETUP, l3ni1_dummy}, | 
 | 2774 | 	{SBIT(1) | SBIT(2), | 
 | 2775 | 	 MT_CALL_PROCEEDING, l3ni1_call_proc}, | 
 | 2776 | 	{SBIT(1), | 
 | 2777 | 	 MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack}, | 
 | 2778 | 	{SBIT(2) | SBIT(3), | 
 | 2779 | 	 MT_ALERTING, l3ni1_alerting}, | 
 | 2780 | 	{SBIT(2) | SBIT(3), | 
 | 2781 | 	 MT_PROGRESS, l3ni1_progress}, | 
 | 2782 | 	{SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | | 
 | 2783 | 	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), | 
 | 2784 | 	 MT_INFORMATION, l3ni1_information}, | 
 | 2785 | 	{SBIT(10) | SBIT(11) | SBIT(15), | 
 | 2786 | 	 MT_NOTIFY, l3ni1_notify}, | 
 | 2787 | 	{SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) | | 
 | 2788 | 	 SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25), | 
 | 2789 | 	 MT_RELEASE_COMPLETE, l3ni1_release_cmpl}, | 
 | 2790 | 	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(25), | 
 | 2791 | 	 MT_RELEASE, l3ni1_release}, | 
 | 2792 | 	{SBIT(19),  MT_RELEASE, l3ni1_release_ind}, | 
 | 2793 | 	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25), | 
 | 2794 | 	 MT_DISCONNECT, l3ni1_disconnect}, | 
 | 2795 | 	{SBIT(19), | 
 | 2796 | 	 MT_DISCONNECT, l3ni1_dummy}, | 
 | 2797 | 	{SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4), | 
 | 2798 | 	 MT_CONNECT, l3ni1_connect}, | 
 | 2799 | 	{SBIT(8), | 
 | 2800 | 	 MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack}, | 
 | 2801 | 	{SBIT(15), | 
 | 2802 | 	 MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack}, | 
 | 2803 | 	{SBIT(15), | 
 | 2804 | 	 MT_SUSPEND_REJECT, l3ni1_suspend_rej}, | 
 | 2805 | 	{SBIT(17), | 
 | 2806 | 	 MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack}, | 
 | 2807 | 	{SBIT(17), | 
 | 2808 | 	 MT_RESUME_REJECT, l3ni1_resume_rej}, | 
 | 2809 | }; | 
 | 2810 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2811 | static struct stateentry globalmes_list[] = | 
 | 2812 | { | 
 | 2813 | 	{ALL_STATES, | 
 | 2814 | 	 MT_STATUS, l3ni1_status}, | 
 | 2815 | 	{SBIT(0), | 
 | 2816 | 	 MT_RESTART, l3ni1_global_restart}, | 
 | 2817 | /*	{SBIT(1), | 
 | 2818 | 	 MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack}, | 
 | 2819 | */ | 
 | 2820 | 	{ SBIT( 0 ), MT_DL_ESTABLISHED, l3ni1_spid_send }, | 
 | 2821 | 	{ SBIT( 20 ) | SBIT( 21 ) | SBIT( 22 ), MT_INFORMATION, l3ni1_spid_epid }, | 
 | 2822 | }; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2823 |  | 
 | 2824 | static struct stateentry manstatelist[] = | 
 | 2825 | { | 
 | 2826 |         {SBIT(2), | 
 | 2827 |          DL_ESTABLISH | INDICATION, l3ni1_dl_reset}, | 
 | 2828 |         {SBIT(10), | 
 | 2829 |          DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status}, | 
 | 2830 |         {SBIT(10), | 
 | 2831 |          DL_RELEASE | INDICATION, l3ni1_dl_reestablish}, | 
 | 2832 |         {ALL_STATES, | 
 | 2833 |          DL_RELEASE | INDICATION, l3ni1_dl_release}, | 
 | 2834 | }; | 
 | 2835 |  | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2836 | /* *INDENT-ON* */ | 
 | 2837 |  | 
 | 2838 |  | 
 | 2839 | static void | 
 | 2840 | global_handler(struct PStack *st, int mt, struct sk_buff *skb) | 
 | 2841 | { | 
 | 2842 | 	u_char tmp[16]; | 
 | 2843 | 	u_char *p = tmp; | 
 | 2844 | 	int l; | 
 | 2845 | 	int i; | 
 | 2846 | 	struct l3_process *proc = st->l3.global; | 
 | 2847 |  | 
 | 2848 | 	if ( skb )	 | 
 | 2849 | 		proc->callref = skb->data[2]; /* cr flag */ | 
 | 2850 | 	else | 
 | 2851 | 		proc->callref = 0; | 
| Karsten Keil | ba2d6cc | 2009-07-24 18:26:08 +0200 | [diff] [blame] | 2852 | 	for (i = 0; i < ARRAY_SIZE(globalmes_list); i++) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2853 | 		if ((mt == globalmes_list[i].primitive) && | 
 | 2854 | 		    ((1 << proc->state) & globalmes_list[i].state)) | 
 | 2855 | 			break; | 
| Karsten Keil | ba2d6cc | 2009-07-24 18:26:08 +0200 | [diff] [blame] | 2856 | 	if (i == ARRAY_SIZE(globalmes_list)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2857 | 		if (st->l3.debug & L3_DEB_STATE) { | 
 | 2858 | 			l3_debug(st, "ni1 global state %d mt %x unhandled", | 
 | 2859 | 				proc->state, mt); | 
 | 2860 | 		} | 
 | 2861 | 		MsgHead(p, proc->callref, MT_STATUS); | 
 | 2862 | 		*p++ = IE_CAUSE; | 
 | 2863 | 		*p++ = 0x2; | 
 | 2864 | 		*p++ = 0x80; | 
 | 2865 | 		*p++ = 81 |0x80;	/* invalid cr */ | 
 | 2866 | 		*p++ = 0x14;		/* CallState */ | 
 | 2867 | 		*p++ = 0x1; | 
 | 2868 | 		*p++ = proc->state & 0x3f; | 
 | 2869 | 		l = p - tmp; | 
 | 2870 | 		if (!(skb = l3_alloc_skb(l))) | 
 | 2871 | 			return; | 
 | 2872 | 		memcpy(skb_put(skb, l), tmp, l); | 
 | 2873 | 		l3_msg(proc->st, DL_DATA | REQUEST, skb); | 
 | 2874 | 	} else { | 
 | 2875 | 		if (st->l3.debug & L3_DEB_STATE) { | 
 | 2876 | 			l3_debug(st, "ni1 global %d mt %x", | 
 | 2877 | 				proc->state, mt); | 
 | 2878 | 		} | 
 | 2879 | 		globalmes_list[i].rout(proc, mt, skb); | 
 | 2880 | 	} | 
 | 2881 | } | 
 | 2882 |  | 
 | 2883 | static void | 
 | 2884 | ni1up(struct PStack *st, int pr, void *arg) | 
 | 2885 | { | 
| David S. Miller | 1397c5d | 2011-04-17 16:43:20 -0700 | [diff] [blame] | 2886 | 	int i, mt, cr, callState; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2887 | 	char *ptr; | 
 | 2888 | 	u_char *p; | 
 | 2889 | 	struct sk_buff *skb = arg; | 
 | 2890 | 	struct l3_process *proc; | 
 | 2891 |  | 
 | 2892 | 	switch (pr) { | 
 | 2893 | 		case (DL_DATA | INDICATION): | 
 | 2894 | 		case (DL_UNIT_DATA | INDICATION): | 
 | 2895 | 			break; | 
 | 2896 | 		case (DL_ESTABLISH | INDICATION): | 
 | 2897 | 		case (DL_RELEASE | INDICATION): | 
 | 2898 | 		case (DL_RELEASE | CONFIRM): | 
 | 2899 | 			l3_msg(st, pr, arg); | 
 | 2900 | 			return; | 
 | 2901 | 			break; | 
 | 2902 |  | 
 | 2903 | 		case (DL_ESTABLISH | CONFIRM): | 
 | 2904 | 			global_handler( st, MT_DL_ESTABLISHED, NULL ); | 
 | 2905 | 			return; | 
 | 2906 |  | 
 | 2907 | 		default: | 
 | 2908 | 			printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr); | 
 | 2909 | 			return; | 
 | 2910 | 	} | 
 | 2911 | 	if (skb->len < 3) { | 
 | 2912 | 		l3_debug(st, "ni1up frame too short(%d)", skb->len); | 
 | 2913 | 		dev_kfree_skb(skb); | 
 | 2914 | 		return; | 
 | 2915 | 	} | 
 | 2916 |  | 
 | 2917 | 	if (skb->data[0] != PROTO_DIS_EURO) { | 
 | 2918 | 		if (st->l3.debug & L3_DEB_PROTERR) { | 
 | 2919 | 			l3_debug(st, "ni1up%sunexpected discriminator %x message len %d", | 
 | 2920 | 				 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", | 
 | 2921 | 				 skb->data[0], skb->len); | 
 | 2922 | 		} | 
 | 2923 | 		dev_kfree_skb(skb); | 
 | 2924 | 		return; | 
 | 2925 | 	} | 
 | 2926 | 	cr = getcallref(skb->data); | 
 | 2927 | 	if (skb->len < ((skb->data[1] & 0x0f) + 3)) { | 
 | 2928 | 		l3_debug(st, "ni1up frame too short(%d)", skb->len); | 
 | 2929 | 		dev_kfree_skb(skb); | 
 | 2930 | 		return; | 
 | 2931 | 	} | 
 | 2932 | 	mt = skb->data[skb->data[1] + 2]; | 
 | 2933 | 	if (st->l3.debug & L3_DEB_STATE) | 
 | 2934 | 		l3_debug(st, "ni1up cr %d", cr); | 
 | 2935 | 	if (cr == -2) {  /* wrong Callref */ | 
 | 2936 | 		if (st->l3.debug & L3_DEB_WARN) | 
 | 2937 | 			l3_debug(st, "ni1up wrong Callref"); | 
 | 2938 | 		dev_kfree_skb(skb); | 
 | 2939 | 		return; | 
 | 2940 | 	} else if (cr == -1) {	/* Dummy Callref */ | 
 | 2941 | 		if (mt == MT_FACILITY) | 
 | 2942 | 		{ | 
 | 2943 | 			if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) { | 
 | 2944 | 				l3ni1_parse_facility(st, NULL,  | 
 | 2945 | 					(pr == (DL_DATA | INDICATION)) ? -1 : -2, p);  | 
 | 2946 | 				dev_kfree_skb(skb); | 
 | 2947 | 				return;   | 
 | 2948 | 			} | 
 | 2949 | 		} | 
 | 2950 | 		else | 
 | 2951 | 		{ | 
 | 2952 | 			global_handler(st, mt, skb); | 
 | 2953 | 			return; | 
 | 2954 | 		} | 
 | 2955 | 				 | 
 | 2956 | 		if (st->l3.debug & L3_DEB_WARN) | 
 | 2957 | 			l3_debug(st, "ni1up dummy Callref (no facility msg or ie)"); | 
 | 2958 | 		dev_kfree_skb(skb); | 
 | 2959 | 		return; | 
 | 2960 | 	} else if ((((skb->data[1] & 0x0f) == 1) && (0==(cr & 0x7f))) || | 
 | 2961 | 		(((skb->data[1] & 0x0f) == 2) && (0==(cr & 0x7fff)))) {	/* Global CallRef */ | 
 | 2962 | 		if (st->l3.debug & L3_DEB_STATE) | 
 | 2963 | 			l3_debug(st, "ni1up Global CallRef"); | 
 | 2964 | 		global_handler(st, mt, skb); | 
 | 2965 | 		dev_kfree_skb(skb); | 
 | 2966 | 		return; | 
 | 2967 | 	} else if (!(proc = getl3proc(st, cr))) { | 
 | 2968 | 		/* No transaction process exist, that means no call with | 
 | 2969 | 		 * this callreference is active | 
 | 2970 | 		 */ | 
 | 2971 | 		if (mt == MT_SETUP) { | 
 | 2972 | 			/* Setup creates a new transaction process */ | 
 | 2973 | 			if (skb->data[2] & 0x80) { | 
 | 2974 | 				/* Setup with wrong CREF flag */ | 
 | 2975 | 				if (st->l3.debug & L3_DEB_STATE) | 
 | 2976 | 					l3_debug(st, "ni1up wrong CRef flag"); | 
 | 2977 | 				dev_kfree_skb(skb); | 
 | 2978 | 				return; | 
 | 2979 | 			} | 
 | 2980 | 			if (!(proc = ni1_new_l3_process(st, cr))) { | 
 | 2981 | 				/* May be to answer with RELEASE_COMPLETE and | 
 | 2982 | 				 * CAUSE 0x2f "Resource unavailable", but this | 
 | 2983 | 				 * need a new_l3_process too ... arghh | 
 | 2984 | 				 */ | 
 | 2985 | 				dev_kfree_skb(skb); | 
 | 2986 | 				return; | 
 | 2987 | 			} | 
 | 2988 | 		} else if (mt == MT_STATUS) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2989 | 			if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) { | 
 | 2990 | 				ptr++; | 
 | 2991 | 				if (*ptr++ == 2) | 
 | 2992 | 					ptr++; | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 2993 | 			} | 
 | 2994 | 			callState = 0; | 
 | 2995 | 			if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) { | 
 | 2996 | 				ptr++; | 
 | 2997 | 				if (*ptr++ == 2) | 
 | 2998 | 					ptr++; | 
 | 2999 | 				callState = *ptr; | 
 | 3000 | 			} | 
 | 3001 | 			/* ETS 300-104 part 2.4.1 | 
 | 3002 | 			 * if setup has not been made and a message type | 
 | 3003 | 			 * MT_STATUS is received with call state == 0, | 
 | 3004 | 			 * we must send nothing | 
 | 3005 | 			 */ | 
 | 3006 | 			if (callState != 0) { | 
 | 3007 | 				/* ETS 300-104 part 2.4.2 | 
 | 3008 | 				 * if setup has not been made and a message type | 
 | 3009 | 				 * MT_STATUS is received with call state != 0, | 
 | 3010 | 				 * we must send MT_RELEASE_COMPLETE cause 101 | 
 | 3011 | 				 */ | 
 | 3012 | 				if ((proc = ni1_new_l3_process(st, cr))) { | 
 | 3013 | 					proc->para.cause = 101; | 
 | 3014 | 					l3ni1_msg_without_setup(proc, 0, NULL); | 
 | 3015 | 				} | 
 | 3016 | 			} | 
 | 3017 | 			dev_kfree_skb(skb); | 
 | 3018 | 			return; | 
 | 3019 | 		} else if (mt == MT_RELEASE_COMPLETE) { | 
 | 3020 | 			dev_kfree_skb(skb); | 
 | 3021 | 			return; | 
 | 3022 | 		} else { | 
 | 3023 | 			/* ETS 300-104 part 2 | 
 | 3024 | 			 * if setup has not been made and a message type | 
 | 3025 | 			 * (except MT_SETUP and RELEASE_COMPLETE) is received, | 
 | 3026 | 			 * we must send MT_RELEASE_COMPLETE cause 81 */ | 
 | 3027 | 			dev_kfree_skb(skb); | 
 | 3028 | 			if ((proc = ni1_new_l3_process(st, cr))) { | 
 | 3029 | 				proc->para.cause = 81; | 
 | 3030 | 				l3ni1_msg_without_setup(proc, 0, NULL); | 
 | 3031 | 			} | 
 | 3032 | 			return; | 
 | 3033 | 		} | 
 | 3034 | 	} | 
 | 3035 | 	if (l3ni1_check_messagetype_validity(proc, mt, skb)) { | 
 | 3036 | 		dev_kfree_skb(skb); | 
 | 3037 | 		return; | 
 | 3038 | 	} | 
 | 3039 | 	if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)  | 
 | 3040 | 	  l3ni1_deliver_display(proc, pr, p); /* Display IE included */ | 
| Karsten Keil | ba2d6cc | 2009-07-24 18:26:08 +0200 | [diff] [blame] | 3041 | 	for (i = 0; i < ARRAY_SIZE(datastatelist); i++) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3042 | 		if ((mt == datastatelist[i].primitive) && | 
 | 3043 | 		    ((1 << proc->state) & datastatelist[i].state)) | 
 | 3044 | 			break; | 
| Karsten Keil | ba2d6cc | 2009-07-24 18:26:08 +0200 | [diff] [blame] | 3045 | 	if (i == ARRAY_SIZE(datastatelist)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3046 | 		if (st->l3.debug & L3_DEB_STATE) { | 
 | 3047 | 			l3_debug(st, "ni1up%sstate %d mt %#x unhandled", | 
 | 3048 | 				(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", | 
 | 3049 | 				proc->state, mt); | 
 | 3050 | 		} | 
 | 3051 | 		if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) { | 
 | 3052 | 			proc->para.cause = 101; | 
 | 3053 | 			l3ni1_status_send(proc, pr, skb); | 
 | 3054 | 		} | 
 | 3055 | 	} else { | 
 | 3056 | 		if (st->l3.debug & L3_DEB_STATE) { | 
 | 3057 | 			l3_debug(st, "ni1up%sstate %d mt %x", | 
 | 3058 | 				(pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", | 
 | 3059 | 				proc->state, mt); | 
 | 3060 | 		} | 
 | 3061 | 		datastatelist[i].rout(proc, pr, skb); | 
 | 3062 | 	} | 
 | 3063 | 	dev_kfree_skb(skb); | 
 | 3064 | 	return; | 
 | 3065 | } | 
 | 3066 |  | 
 | 3067 | static void | 
 | 3068 | ni1down(struct PStack *st, int pr, void *arg) | 
 | 3069 | { | 
 | 3070 | 	int i, cr; | 
 | 3071 | 	struct l3_process *proc; | 
 | 3072 | 	struct Channel *chan; | 
 | 3073 |  | 
 | 3074 | 	if ((DL_ESTABLISH | REQUEST) == pr) { | 
 | 3075 | 		l3_msg(st, pr, NULL); | 
 | 3076 | 		return; | 
 | 3077 | 	} else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) { | 
 | 3078 | 		chan = arg; | 
 | 3079 | 		cr = newcallref(); | 
 | 3080 | 		cr |= 0x80; | 
 | 3081 | 		if ((proc = ni1_new_l3_process(st, cr))) { | 
 | 3082 | 			proc->chan = chan; | 
 | 3083 | 			chan->proc = proc; | 
 | 3084 | 			memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); | 
 | 3085 | 			proc->callref = cr; | 
 | 3086 | 		} | 
 | 3087 | 	} else { | 
 | 3088 | 		proc = arg; | 
 | 3089 | 	} | 
 | 3090 | 	if (!proc) { | 
 | 3091 | 		printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr); | 
 | 3092 | 		return; | 
 | 3093 | 	} | 
 | 3094 |  | 
 | 3095 | 	if ( pr == (CC_TNI1_IO | REQUEST)) { | 
 | 3096 | 		l3ni1_io_timer(proc); /* timer expires */  | 
 | 3097 | 		return; | 
 | 3098 | 	}   | 
 | 3099 |  | 
| Karsten Keil | ba2d6cc | 2009-07-24 18:26:08 +0200 | [diff] [blame] | 3100 | 	for (i = 0; i < ARRAY_SIZE(downstatelist); i++) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3101 | 		if ((pr == downstatelist[i].primitive) && | 
 | 3102 | 		    ((1 << proc->state) & downstatelist[i].state)) | 
 | 3103 | 			break; | 
| Karsten Keil | ba2d6cc | 2009-07-24 18:26:08 +0200 | [diff] [blame] | 3104 | 	if (i == ARRAY_SIZE(downstatelist)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3105 | 		if (st->l3.debug & L3_DEB_STATE) { | 
 | 3106 | 			l3_debug(st, "ni1down state %d prim %#x unhandled", | 
 | 3107 | 				proc->state, pr); | 
 | 3108 | 		} | 
 | 3109 | 	} else { | 
 | 3110 | 		if (st->l3.debug & L3_DEB_STATE) { | 
 | 3111 | 			l3_debug(st, "ni1down state %d prim %#x", | 
 | 3112 | 				proc->state, pr); | 
 | 3113 | 		} | 
 | 3114 | 		downstatelist[i].rout(proc, pr, arg); | 
 | 3115 | 	} | 
 | 3116 | } | 
 | 3117 |  | 
 | 3118 | static void | 
 | 3119 | ni1man(struct PStack *st, int pr, void *arg) | 
 | 3120 | { | 
 | 3121 |         int i; | 
 | 3122 |         struct l3_process *proc = arg; | 
 | 3123 |  | 
 | 3124 |         if (!proc) { | 
 | 3125 |                 printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr); | 
 | 3126 |                 return; | 
 | 3127 |         } | 
| Karsten Keil | ba2d6cc | 2009-07-24 18:26:08 +0200 | [diff] [blame] | 3128 |         for (i = 0; i < ARRAY_SIZE(manstatelist); i++) | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3129 |                 if ((pr == manstatelist[i].primitive) && | 
 | 3130 |                     ((1 << proc->state) & manstatelist[i].state)) | 
 | 3131 |                         break; | 
| Karsten Keil | ba2d6cc | 2009-07-24 18:26:08 +0200 | [diff] [blame] | 3132 |         if (i == ARRAY_SIZE(manstatelist)) { | 
| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 3133 |                 if (st->l3.debug & L3_DEB_STATE) { | 
 | 3134 |                         l3_debug(st, "cr %d ni1man state %d prim %#x unhandled", | 
 | 3135 |                                 proc->callref & 0x7f, proc->state, pr); | 
 | 3136 |                 } | 
 | 3137 |         } else { | 
 | 3138 |                 if (st->l3.debug & L3_DEB_STATE) { | 
 | 3139 |                         l3_debug(st, "cr %d ni1man state %d prim %#x", | 
 | 3140 |                                 proc->callref & 0x7f, proc->state, pr); | 
 | 3141 |                 } | 
 | 3142 |                 manstatelist[i].rout(proc, pr, arg); | 
 | 3143 |         } | 
 | 3144 | } | 
 | 3145 |   | 
 | 3146 | void | 
 | 3147 | setstack_ni1(struct PStack *st) | 
 | 3148 | { | 
 | 3149 | 	char tmp[64]; | 
 | 3150 | 	int i; | 
 | 3151 |  | 
 | 3152 | 	st->lli.l4l3 = ni1down; | 
 | 3153 | 	st->lli.l4l3_proto = l3ni1_cmd_global; | 
 | 3154 | 	st->l2.l2l3 = ni1up; | 
 | 3155 | 	st->l3.l3ml3 = ni1man; | 
 | 3156 | 	st->l3.N303 = 1; | 
 | 3157 | 	st->prot.ni1.last_invoke_id = 0; | 
 | 3158 | 	st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */ | 
 | 3159 | 	i = 1; | 
 | 3160 | 	while (i < 32)  | 
 | 3161 | 		st->prot.ni1.invoke_used[i++] = 0;    | 
 | 3162 |  | 
 | 3163 | 	if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) { | 
 | 3164 | 		printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n"); | 
 | 3165 | 	} else { | 
 | 3166 | 		st->l3.global->state = 0; | 
 | 3167 | 		st->l3.global->callref = 0; | 
 | 3168 | 		st->l3.global->next = NULL; | 
 | 3169 | 		st->l3.global->debug = L3_DEB_WARN; | 
 | 3170 | 		st->l3.global->st = st; | 
 | 3171 | 		st->l3.global->N303 = 1; | 
 | 3172 | 		st->l3.global->prot.ni1.invoke_id = 0;  | 
 | 3173 |  | 
 | 3174 | 		L3InitTimer(st->l3.global, &st->l3.global->timer); | 
 | 3175 | 	} | 
 | 3176 | 	strcpy(tmp, ni1_revision); | 
 | 3177 | 	printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp)); | 
 | 3178 | } |