blob: 0df6691d045c298906c95c1b29415ac93ef24878 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $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
Joe Perches475be4d2012-02-19 19:52:38 -08007 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
Joe Perches475be4d2012-02-19 19:52:38 -080011 * 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....
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 * 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 Heo5a0e3ad2010-03-24 17:04:11 +090025#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
27extern char *HiSax_getrev(const char *revision);
Adrian Bunk672c3fd2005-06-25 14:59:18 -070028static const char *ni1_revision = "$Revision: 2.8.2.3 $";
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
30#define EXT_BEARER_CAPS 1
31
Joe Perches475be4d2012-02-19 19:52:38 -080032#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 } \
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 *ptr++ = mty
41
42
43/**********************************************/
44/* get a new invoke id for remote operations. */
45/* Only a return value != 0 is valid */
46/**********************************************/
47static unsigned char new_invoke_id(struct PStack *p)
48{
49 unsigned char retval;
50 int i;
Joe Perches475be4d2012-02-19 19:52:38 -080051
Linus Torvalds1da177e2005-04-16 15:20:36 -070052 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--;
Joe Perches475be4d2012-02-19 19:52:38 -080058 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 if (i) {
60 while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7)))
Joe Perches475be4d2012-02-19 19:52:38 -080061 retval++;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062 } else
63 retval = 0;
64 p->prot.ni1.last_invoke_id = retval;
65 p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7));
Joe Perches475be4d2012-02-19 19:52:38 -080066 return (retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -070067} /* new_invoke_id */
68
69/*************************/
70/* free a used invoke id */
71/*************************/
72static void free_invoke_id(struct PStack *p, unsigned char id)
73{
74
Joe Perches475be4d2012-02-19 19:52:38 -080075 if (!id) return; /* 0 = invalid value */
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Joe Perches475be4d2012-02-19 19:52:38 -080077 p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7));
78} /* free_invoke_id */
Linus Torvalds1da177e2005-04-16 15:20:36 -070079
80
81/**********************************************************/
82/* create a new l3 process and fill in ni1 specific data */
83/**********************************************************/
84static struct l3_process
85*ni1_new_l3_process(struct PStack *st, int cr)
86{ struct l3_process *proc;
87
Joe Perches475be4d2012-02-19 19:52:38 -080088 if (!(proc = new_l3_process(st, cr)))
89 return (NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090
Joe Perches475be4d2012-02-19 19:52:38 -080091 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -070096} /* ni1_new_l3_process */
97
98/************************************************/
99/* free a l3 process and all ni1 specific data */
Joe Perches475be4d2012-02-19 19:52:38 -0800100/************************************************/
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101static void
102ni1_release_l3_process(struct l3_process *p)
103{
Joe Perches475be4d2012-02-19 19:52:38 -0800104 free_invoke_id(p->st, p->prot.ni1.invoke_id);
105 release_l3_process(p);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106} /* ni1_release_l3_process */
Joe Perches475be4d2012-02-19 19:52:38 -0800107
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108/********************************************************/
109/* search a process with invoke id id and dummy callref */
110/********************************************************/
111static struct l3_process *
112l3ni1_search_dummy_proc(struct PStack *st, int id)
113{ struct l3_process *pc = st->l3.proc; /* start of processes */
114
Joe Perches475be4d2012-02-19 19:52:38 -0800115 if (!id) return (NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116
Joe Perches475be4d2012-02-19 19:52:38 -0800117 while (pc)
118 { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id))
119 return (pc);
120 pc = pc->next;
121 }
122 return (NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123} /* 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. */
Joe Perches475be4d2012-02-19 19:52:38 -0800128/*******************************************************************/
129static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
131{ isdn_ctrl ic;
Joe Perches475be4d2012-02-19 19:52:38 -0800132 struct IsdnCardState *cs;
133 struct l3_process *pc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134
Joe Perches475be4d2012-02-19 19:52:38 -0800135 if ((pc = l3ni1_search_dummy_proc(st, id)))
136 { L3DelTimer(&pc->timer); /* remove timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137
Joe Perches475be4d2012-02-19 19:52:38 -0800138 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150
Joe Perches475be4d2012-02-19 19:52:38 -0800151 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156} /* 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. */
Joe Perches475be4d2012-02-19 19:52:38 -0800161/*******************************************************************/
162static void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163l3ni1_dummy_error_return(struct PStack *st, int id, ulong error)
164{ isdn_ctrl ic;
Joe Perches475be4d2012-02-19 19:52:38 -0800165 struct IsdnCardState *cs;
166 struct l3_process *pc = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167
Joe Perches475be4d2012-02-19 19:52:38 -0800168 if ((pc = l3ni1_search_dummy_proc(st, id)))
169 { L3DelTimer(&pc->timer); /* remove timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700170
Joe Perches475be4d2012-02-19 19:52:38 -0800171 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183
Joe Perches475be4d2012-02-19 19:52:38 -0800184 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189} /* 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. */
Joe Perches475be4d2012-02-19 19:52:38 -0800194/*******************************************************************/
195static void
196l3ni1_dummy_invoke(struct PStack *st, int cr, int id,
197 int ident, u_char *p, u_char nlen)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700198{ isdn_ctrl ic;
Joe Perches475be4d2012-02-19 19:52:38 -0800199 struct IsdnCardState *cs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200
Joe Perches475be4d2012-02-19 19:52:38 -0800201 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204
Joe Perches475be4d2012-02-19 19:52:38 -0800205 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215
Joe Perches475be4d2012-02-19 19:52:38 -0800216 cs->iif.statcallb(&ic);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217} /* l3ni1_dummy_invoke */
218
219static void
220l3ni1_parse_facility(struct PStack *st, struct l3_process *pc,
Joe Perches475be4d2012-02-19 19:52:38 -0800221 int cr, u_char *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222{
223 int qd_len = 0;
224 unsigned char nlen = 0, ilen, cp_tag;
225 int ident, id;
226 ulong err_ret;
227
Joe Perches475be4d2012-02-19 19:52:38 -0800228 if (pc)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
Joe Perches475be4d2012-02-19 19:52:38 -0800258 cp_tag = *p & 0x1F; /* remember tag value */
259
260 p++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 qd_len--;
Joe Perches475be4d2012-02-19 19:52:38 -0800262 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 qd_len -= nlen;
296
Joe Perches475be4d2012-02-19 19:52:38 -0800297 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 p++;
307 nlen--;
Joe Perches475be4d2012-02-19 19:52:38 -0800308 if (*p & 0x80)
309 { /* length format */
310 l3_debug(st, "invoke id length format 2");
311 return;
312 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313 ilen = *p++;
314 nlen--;
Joe Perches475be4d2012-02-19 19:52:38 -0800315 if (ilen > nlen || ilen == 0)
316 { l3_debug(st, "ilen > nlen || ilen == 0");
317 return;
318 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 nlen -= ilen;
320 id = 0;
Joe Perches475be4d2012-02-19 19:52:38 -0800321 while (ilen > 0)
322 { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */
323 ilen--;
324 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700325
326 switch (cp_tag) { /* component tag */
Joe Perches475be4d2012-02-19 19:52:38 -0800327 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350
Joe Perches475be4d2012-02-19 19:52:38 -0800351 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 }
425}
426
427static void
428l3ni1_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
440static void
441l3ni1_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
461static void
462l3ni1_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
482static void
483l3ni1_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
508static void
509l3ni1_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) {
Joe Perches475be4d2012-02-19 19:52:38 -0800521 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536 }
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
545static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
Joe Perches475be4d2012-02-19 19:52:38 -0800546 IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC,
547 IE_USER_USER, -1};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
Joe Perches475be4d2012-02-19 19:52:38 -0800549 IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
550static 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};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
554static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
Joe Perches475be4d2012-02-19 19:52:38 -0800555 IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
Joe Perches475be4d2012-02-19 19:52:38 -0800557 IE_CALLED_PN, -1};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
559static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
Joe Perches475be4d2012-02-19 19:52:38 -0800560 IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
Joe Perches475be4d2012-02-19 19:52:38 -0800562 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};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565*/
Joe Perches475be4d2012-02-19 19:52:38 -0800566static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
567 IE_DISPLAY, -1};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
569static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY,
Joe Perches475be4d2012-02-19 19:52:38 -0800570 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};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
Joe Perches475be4d2012-02-19 19:52:38 -0800575 IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
Joe Perches475be4d2012-02-19 19:52:38 -0800577 IE_MANDATORY, IE_DISPLAY, -1};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
579static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1};
580static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
Joe Perches475be4d2012-02-19 19:52:38 -0800581/* not used
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 * 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 */
588static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1};
Joe Perches475be4d2012-02-19 19:52:38 -0800589static int comp_required[] = {1, 2, 3, 5, 6, 7, 9, 10, 11, 14, 15, -1};
590static int l3_valid_states[] = {0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 17, 19, 25, -1};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700591
592struct ie_len {
593 int ie;
594 int len;
595};
596
597static
598struct 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},
Joe Perches475be4d2012-02-19 19:52:38 -0800631 {-1, 0},
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632};
633
634static int
635getmax_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)
Joe Perches475be4d2012-02-19 19:52:38 -0800639 return (max_ie_len[i].len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640 i++;
641 }
Joe Perches475be4d2012-02-19 19:52:38 -0800642 return (255);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643}
644
645static int
646ie_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)
Joe Perches475be4d2012-02-19 19:52:38 -0800652 return (-ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 else
Joe Perches475be4d2012-02-19 19:52:38 -0800654 return (ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655 }
656 ret++;
657 checklist++;
658 }
Joe Perches475be4d2012-02-19 19:52:38 -0800659 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660}
661
662static int
663check_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;
Joe Perches475be4d2012-02-19 19:52:38 -0800673
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 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",
Joe Perches475be4d2012-02-19 19:52:38 -0800691 codelock ? " locking " : " ", old_codeset, codeset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 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",
Joe Perches475be4d2012-02-19 19:52:38 -0800723 codeset, old_codeset);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 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",
Joe Perches475be4d2012-02-19 19:52:38 -0800731 mt, err_compr, err_ureg, err_len, err_seq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732 if (err_compr)
Joe Perches475be4d2012-02-19 19:52:38 -0800733 return (ERR_IE_COMPREHENSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 if (err_ureg)
Joe Perches475be4d2012-02-19 19:52:38 -0800735 return (ERR_IE_UNRECOGNIZED);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 if (err_len)
Joe Perches475be4d2012-02-19 19:52:38 -0800737 return (ERR_IE_LENGTH);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 if (err_seq)
Joe Perches475be4d2012-02-19 19:52:38 -0800739 return (ERR_IE_SEQUENCE);
740 }
741 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742}
743
744/* verify if a message type exists and contain no IE error */
745static int
746l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg)
747{
748 switch (mt) {
Joe Perches475be4d2012-02-19 19:52:38 -0800749 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 }
Joe Perches475be4d2012-02-19 19:52:38 -0800784 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700785}
786
787static void
788l3ni1_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);
Joe Perches475be4d2012-02-19 19:52:38 -0800792 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810 }
811}
812
813static int
814l3ni1_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 }
Joe Perches475be4d2012-02-19 19:52:38 -0800831 return (*p & 0x3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 } else
Joe Perches475be4d2012-02-19 19:52:38 -0800833 return (-1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834}
835
836static int
837l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
Joe Perches475be4d2012-02-19 19:52:38 -0800838 u_char l, i = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 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++;
Joe Perches475be4d2012-02-19 19:52:38 -0800847 if (l > 30)
848 return (1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700849 if (l) {
850 pc->para.loc = *p++;
851 l--;
852 } else {
Joe Perches475be4d2012-02-19 19:52:38 -0800853 return (2);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 }
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))
Joe Perches475be4d2012-02-19 19:52:38 -0800863 return (3);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 } else
Joe Perches475be4d2012-02-19 19:52:38 -0800865 return (4);
866 while (l && (i < 6)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 pc->para.diag[i++] = *p++;
868 l--;
869 }
870 } else
Joe Perches475be4d2012-02-19 19:52:38 -0800871 return (-1);
872 return (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873}
874
875static void
876l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd)
877{
878 struct sk_buff *skb;
Joe Perches475be4d2012-02-19 19:52:38 -0800879 u_char tmp[16 + 40];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 u_char *p = tmp;
881 int l;
882
883 MsgHead(p, pc->callref, cmd);
884
Joe Perches475be4d2012-02-19 19:52:38 -0800885 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893
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
901static void
902l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg)
903{
904 StopAllL3Timer(pc);
905 newl3state(pc, 19);
Joe Perches475be4d2012-02-19 19:52:38 -0800906 if (!pc->prot.ni1.uus1_data[0])
Linus Torvalds1da177e2005-04-16 15:20:36 -0700907 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
913static void
914l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
915{
916 struct sk_buff *skb = arg;
917 int ret;
918
Joe Perches475be4d2012-02-19 19:52:38 -0800919 if ((ret = l3ni1_get_cause(pc, skb)) > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 if (pc->debug & L3_DEB_WARN)
Joe Perches475be4d2012-02-19 19:52:38 -0800921 l3_debug(pc->st, "RELCMPL get_cause ret(%d)", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922 } 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
932static u_char *
Joe Perches475be4d2012-02-19 19:52:38 -0800933EncodeASyncParams(u_char *p, u_char si2)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700934{ // 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) {
Joe Perches475be4d2012-02-19 19:52:38 -0800961 case 0:
962 p[0] = 66; // 1200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963
Joe Perches475be4d2012-02-19 19:52:38 -0800964 break;
965 case 1:
966 p[0] = 88; // 1200/75 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967
Joe Perches475be4d2012-02-19 19:52:38 -0800968 break;
969 case 2:
970 p[0] = 87; // 75/1200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -0700971
Joe Perches475be4d2012-02-19 19:52:38 -0800972 break;
973 case 3:
974 p[0] = 67; // 2400 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -0700975
Joe Perches475be4d2012-02-19 19:52:38 -0800976 break;
977 case 4:
978 p[0] = 69; // 4800 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979
Joe Perches475be4d2012-02-19 19:52:38 -0800980 break;
981 case 5:
982 p[0] = 72; // 9600 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983
Joe Perches475be4d2012-02-19 19:52:38 -0800984 break;
985 case 6:
986 p[0] = 73; // 14400 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -0700987
Joe Perches475be4d2012-02-19 19:52:38 -0800988 break;
989 case 7:
990 p[0] = 75; // 19200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991
Joe Perches475be4d2012-02-19 19:52:38 -0800992 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993 }
994 return p + 3;
995}
996
997static u_char
998EncodeSyncParams(u_char si2, u_char ai)
999{
1000
1001 switch (si2) {
Joe Perches475be4d2012-02-19 19:52:38 -08001002 case 0:
1003 return ai + 2; // 1200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004
Joe Perches475be4d2012-02-19 19:52:38 -08001005 case 1:
1006 return ai + 24; // 1200/75 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
Joe Perches475be4d2012-02-19 19:52:38 -08001008 case 2:
1009 return ai + 23; // 75/1200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
Joe Perches475be4d2012-02-19 19:52:38 -08001011 case 3:
1012 return ai + 3; // 2400 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013
Joe Perches475be4d2012-02-19 19:52:38 -08001014 case 4:
1015 return ai + 5; // 4800 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016
Joe Perches475be4d2012-02-19 19:52:38 -08001017 case 5:
1018 return ai + 8; // 9600 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019
Joe Perches475be4d2012-02-19 19:52:38 -08001020 case 6:
1021 return ai + 9; // 14400 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022
Joe Perches475be4d2012-02-19 19:52:38 -08001023 case 7:
1024 return ai + 11; // 19200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001025
Joe Perches475be4d2012-02-19 19:52:38 -08001026 case 8:
1027 return ai + 14; // 48000 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028
Joe Perches475be4d2012-02-19 19:52:38 -08001029 case 9:
1030 return ai + 15; // 56000 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031
Joe Perches475be4d2012-02-19 19:52:38 -08001032 case 15:
1033 return ai + 40; // negotiate bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001034
Joe Perches475be4d2012-02-19 19:52:38 -08001035 default:
1036 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 }
1038 return ai;
1039}
1040
1041
1042static u_char
Joe Perches475be4d2012-02-19 19:52:38 -08001043DecodeASyncParams(u_char si2, u_char *p)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044{
1045 u_char info;
1046
1047 switch (p[5]) {
Joe Perches475be4d2012-02-19 19:52:38 -08001048 case 66: // 1200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049
Joe Perches475be4d2012-02-19 19:52:38 -08001050 break; // si2 don't change
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051
Joe Perches475be4d2012-02-19 19:52:38 -08001052 case 88: // 1200/75 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001053
Joe Perches475be4d2012-02-19 19:52:38 -08001054 si2 += 1;
1055 break;
1056 case 87: // 75/1200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057
Joe Perches475be4d2012-02-19 19:52:38 -08001058 si2 += 2;
1059 break;
1060 case 67: // 2400 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061
Joe Perches475be4d2012-02-19 19:52:38 -08001062 si2 += 3;
1063 break;
1064 case 69: // 4800 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001065
Joe Perches475be4d2012-02-19 19:52:38 -08001066 si2 += 4;
1067 break;
1068 case 72: // 9600 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Joe Perches475be4d2012-02-19 19:52:38 -08001070 si2 += 5;
1071 break;
1072 case 73: // 14400 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073
Joe Perches475be4d2012-02-19 19:52:38 -08001074 si2 += 6;
1075 break;
1076 case 75: // 19200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001077
Joe Perches475be4d2012-02-19 19:52:38 -08001078 si2 += 7;
1079 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 }
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
1099static u_char
1100DecodeSyncParams(u_char si2, u_char info)
1101{
1102 info &= 0x7f;
1103 switch (info) {
Joe Perches475be4d2012-02-19 19:52:38 -08001104 case 40: // bit/s negotiation failed ai := 165 not 175!
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105
Joe Perches475be4d2012-02-19 19:52:38 -08001106 return si2 + 15;
1107 case 15: // 56000 bit/s failed, ai := 0 not 169 !
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108
Joe Perches475be4d2012-02-19 19:52:38 -08001109 return si2 + 9;
1110 case 14: // 48000 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111
Joe Perches475be4d2012-02-19 19:52:38 -08001112 return si2 + 8;
1113 case 11: // 19200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001114
Joe Perches475be4d2012-02-19 19:52:38 -08001115 return si2 + 7;
1116 case 9: // 14400 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117
Joe Perches475be4d2012-02-19 19:52:38 -08001118 return si2 + 6;
1119 case 8: // 9600 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120
Joe Perches475be4d2012-02-19 19:52:38 -08001121 return si2 + 5;
1122 case 5: // 4800 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123
Joe Perches475be4d2012-02-19 19:52:38 -08001124 return si2 + 4;
1125 case 3: // 2400 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126
Joe Perches475be4d2012-02-19 19:52:38 -08001127 return si2 + 3;
1128 case 23: // 75/1200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129
Joe Perches475be4d2012-02-19 19:52:38 -08001130 return si2 + 2;
1131 case 24: // 1200/75 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001132
Joe Perches475be4d2012-02-19 19:52:38 -08001133 return si2 + 1;
1134 default: // 1200 bit/s
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135
Joe Perches475be4d2012-02-19 19:52:38 -08001136 return si2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001137 }
1138}
1139
1140static u_char
1141DecodeSI2(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) {
Joe Perches475be4d2012-02-19 19:52:38 -08001147 case 0x01:
1148 if (p[1] == 0x04) // sync. Bitratenadaption
Linus Torvalds1da177e2005-04-16 15:20:36 -07001149
Joe Perches475be4d2012-02-19 19:52:38 -08001150 return DecodeSyncParams(160, p[5]); // V.110/X.30
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Joe Perches475be4d2012-02-19 19:52:38 -08001152 else if (p[1] == 0x06) // async. Bitratenadaption
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153
Joe Perches475be4d2012-02-19 19:52:38 -08001154 return DecodeASyncParams(192, p); // V.110/X.30
Linus Torvalds1da177e2005-04-16 15:20:36 -07001155
Joe Perches475be4d2012-02-19 19:52:38 -08001156 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161 }
1162 }
1163 return 0;
1164}
1165
1166#endif
1167
1168
1169static void
1170l3ni1_setup_req(struct l3_process *pc, u_char pr,
Joe Perches475be4d2012-02-19 19:52:38 -08001171 void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172{
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 */
Joe Perches475be4d2012-02-19 19:52:38 -08001194 *p++ = 0x90; /* 3.1khz Audio */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195 *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 }
Joe Perches475be4d2012-02-19 19:52:38 -08001217
Linus Torvalds1da177e2005-04-16 15:20:36 -07001218 *p++ = IE_KEYPAD;
1219 *p++ = strlen(teln);
1220 while (*teln)
1221 *p++ = (*teln++) & 0x7F;
1222
1223 if (sub)
1224 *sub++ = '.';
Joe Perches475be4d2012-02-19 19:52:38 -08001225
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226#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 {
Joe Perches475be4d2012-02-19 19:52:38 -08001253 switch (pc->para.setup.si1) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254 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;
Joe Perches475be4d2012-02-19 19:52:38 -08001269 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001270 }
1271#endif
1272 l = p - tmp;
1273 if (!(skb = l3_alloc_skb(l)))
Joe Perches475be4d2012-02-19 19:52:38 -08001274 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 return;
Joe Perches475be4d2012-02-19 19:52:38 -08001276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 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
1284static void
1285l3ni1_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
1323static void
1324l3ni1_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
1362static void
1363l3ni1_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;
Joe Perches475be4d2012-02-19 19:52:38 -08001378 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 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);
Joe Perches475be4d2012-02-19 19:52:38 -08001390 if (11 != ret)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391 pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
Joe Perches475be4d2012-02-19 19:52:38 -08001392 else if (!cause)
1393 l3ni1_release_req(pc, pr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 if (cause) {
1395 l3ni1_message_cause(pc, MT_RELEASE, cause);
1396 L3AddTimer(&pc->timer, T308, CC_T308_1);
1397 }
1398}
1399
1400static void
1401l3ni1_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
1420static void
1421l3ni1_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
1438static void
1439l3ni1_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 Marchi25985ed2011-03-30 22:57:33 -03001452 /* only the first occurrence 'll be detected ! */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 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) {
Joe Perches475be4d2012-02-19 19:52:38 -08001459 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465/* JIM, 05.11.97 I wanna set service indicator 2 */
1466#if EXT_BEARER_CAPS
Joe Perches475be4d2012-02-19 19:52:38 -08001467 pc->para.setup.si2 = DecodeSI2(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468#endif
Joe Perches475be4d2012-02-19 19:52:38 -08001469 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 }
1486 switch (p[3] & 0x7f) {
Joe Perches475be4d2012-02-19 19:52:38 -08001487 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500 }
1501 }
1502 if (pc->debug & L3_DEB_SI)
1503 l3_debug(pc->st, "SI=%d, AI=%d",
Joe Perches475be4d2012-02-19 19:52:38 -08001504 pc->para.setup.si1, pc->para.setup.si2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 if (err) {
1506 if (pc->debug & L3_DEB_WARN)
1507 l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)",
Joe Perches475be4d2012-02-19 19:52:38 -08001508 p[1], p[2], p[3]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 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",
Joe Perches475be4d2012-02-19 19:52:38 -08001529 id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 pc->para.cause = 100;
1531 l3ni1_msg_without_setup(pc, pr, NULL);
1532 return;
1533 }
1534 bcfound++;
Joe Perches475be4d2012-02-19 19:52:38 -08001535 } else
1536 { if (pc->debug & L3_DEB_WARN)
1537 l3_debug(pc->st, "setup without bchannel, call waiting");
1538 bcfound++;
1539 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 } 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
1604static void
1605l3ni1_reset(struct l3_process *pc, u_char pr, void *arg)
1606{
1607 ni1_release_l3_process(pc);
1608}
1609
1610static void
1611l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
1612{
1613 struct sk_buff *skb;
Joe Perches475be4d2012-02-19 19:52:38 -08001614 u_char tmp[16 + 40];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001615 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
Joe Perches475be4d2012-02-19 19:52:38 -08001631 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639
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
1649static void
1650l3ni1_setup_rsp(struct l3_process *pc, u_char pr,
Joe Perches475be4d2012-02-19 19:52:38 -08001651 void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652{
Joe Perches475be4d2012-02-19 19:52:38 -08001653 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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 newl3state(pc, 8);
1660 if (pc->debug & L3_DEB_WARN)
1661 l3_debug(pc->st, "D-chan connect for waiting call");
Joe Perches475be4d2012-02-19 19:52:38 -08001662 l3ni1_message_plus_chid(pc, MT_CONNECT); /* GE 05/09/00 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 L3DelTimer(&pc->timer);
1664 L3AddTimer(&pc->timer, T313, CC_T313);
1665}
1666
1667static void
1668l3ni1_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
1685static void
1686l3ni1_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
1714static void
1715l3ni1_release(struct l3_process *pc, u_char pr, void *arg)
1716{
1717 struct sk_buff *skb = arg;
1718 u_char *p;
Joe Perches475be4d2012-02-19 19:52:38 -08001719 int ret, cause = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720
1721 StopAllL3Timer(pc);
Joe Perches475be4d2012-02-19 19:52:38 -08001722 if ((ret = l3ni1_get_cause(pc, skb)) > 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001723 if (pc->debug & L3_DEB_WARN)
1724 l3_debug(pc->st, "REL get_cause ret(%d)", ret);
Joe Perches475be4d2012-02-19 19:52:38 -08001725 } else if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001726 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 }
Joe Perches475be4d2012-02-19 19:52:38 -08001730 if ((ret < 0) && (pc->state != 11))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001731 cause = 96;
Joe Perches475be4d2012-02-19 19:52:38 -08001732 else if (ret > 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 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))
Joe Perches475be4d2012-02-19 19:52:38 -08001738 cause = 99;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 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
1748static void
1749l3ni1_alert_req(struct l3_process *pc, u_char pr,
Joe Perches475be4d2012-02-19 19:52:38 -08001750 void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001751{
1752 newl3state(pc, 7);
Joe Perches475be4d2012-02-19 19:52:38 -08001753 if (!pc->prot.ni1.uus1_data[0])
Linus Torvalds1da177e2005-04-16 15:20:36 -07001754 l3ni1_message(pc, MT_ALERTING);
1755 else
Joe Perches475be4d2012-02-19 19:52:38 -08001756 l3ni1_msg_with_uus(pc, MT_ALERTING);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757}
1758
1759static void
1760l3ni1_proceed_req(struct l3_process *pc, u_char pr,
Joe Perches475be4d2012-02-19 19:52:38 -08001761 void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762{
1763 newl3state(pc, 9);
1764 l3ni1_message(pc, MT_CALL_PROCEEDING);
Joe Perches475be4d2012-02-19 19:52:38 -08001765 pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766}
1767
1768static void
1769l3ni1_setup_ack_req(struct l3_process *pc, u_char pr,
Joe Perches475be4d2012-02-19 19:52:38 -08001770 void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771{
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/********************************************/
1781static void
1782l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
1783{ u_char len;
Joe Perches475be4d2012-02-19 19:52:38 -08001784 isdn_ctrl ic;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001785 struct IsdnCardState *cs;
Joe Perches475be4d2012-02-19 19:52:38 -08001786 char *p;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001787
Joe Perches475be4d2012-02-19 19:52:38 -08001788 if (*infp++ != IE_DISPLAY) return;
1789 if ((len = *infp++) > 80) return; /* total length <= 82 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001790 if (!pc->chan) return;
1791
Joe Perches475be4d2012-02-19 19:52:38 -08001792 p = ic.parm.display;
1793 while (len--)
1794 *p++ = *infp++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001795 *p = '\0';
1796 ic.command = ISDN_STAT_DISPLAY;
1797 cs = pc->st->l1.hardware;
1798 ic.driver = cs->myid;
Joe Perches475be4d2012-02-19 19:52:38 -08001799 ic.arg = pc->chan->chan;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 cs->iif.statcallb(&ic);
1801} /* l3ni1_deliver_display */
1802
1803
1804static void
1805l3ni1_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]) {
Joe Perches475be4d2012-02-19 19:52:38 -08001817 case 0x80:
1818 case 0x81:
1819 case 0x82:
1820 case 0x84:
1821 case 0x85:
1822 case 0x87:
1823 case 0x8a:
1824 switch (p[3]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 case 0x81:
1826 case 0x82:
Joe Perches475be4d2012-02-19 19:52:38 -08001827 case 0x83:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828 case 0x84:
Joe Perches475be4d2012-02-19 19:52:38 -08001829 case 0x88:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001830 break;
1831 default:
Joe Perches475be4d2012-02-19 19:52:38 -08001832 err = 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001833 pc->para.cause = 100;
1834 break;
Joe Perches475be4d2012-02-19 19:52:38 -08001835 }
1836 break;
1837 default:
1838 err = 3;
1839 pc->para.cause = 100;
1840 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001841 }
1842 }
1843 } else {
1844 pc->para.cause = 96;
1845 err = 4;
1846 }
Joe Perches475be4d2012-02-19 19:52:38 -08001847 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 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
1861static void
1862l3ni1_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]) {
Joe Perches475be4d2012-02-19 19:52:38 -08001874 case 0x80:
1875 case 0x81:
1876 case 0x82:
1877 break;
1878 default:
1879 pc->para.cause = 100;
1880 err = 2;
1881 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001882 }
1883 }
1884 } else {
1885 pc->para.cause = 96;
1886 err = 3;
1887 }
Joe Perches475be4d2012-02-19 19:52:38 -08001888 if (err) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001889 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
1902static void
1903l3ni1_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 */
Joe Perches475be4d2012-02-19 19:52:38 -08001911 l3ni1_status_send(pc, pr, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001912}
1913
1914static void
1915l3ni1_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/******************************/
1940static 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;
Joe Perches475be4d2012-02-19 19:52:38 -08001945 u_char *subp;
1946 u_char len_phone = 0;
1947 u_char len_sub = 0;
1948 int l;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949
1950
Joe Perches475be4d2012-02-19 19:52:38 -08001951 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001957
Joe Perches475be4d2012-02-19 19:52:38 -08001958 if (pc->prot.ni1.invoke_id)
1959 free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960
Joe Perches475be4d2012-02-19 19:52:38 -08001961 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001968
1969 *p++ = 0x1c; /* Facility info element */
Joe Perches475be4d2012-02-19 19:52:38 -08001970 *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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001976 *p++ = 0x01; /* length */
Joe Perches475be4d2012-02-19 19:52:38 -08001977 *p++ = pc->prot.ni1.invoke_id; /* invoke id */
1978 *p++ = 0x02; /* operation value tag, integer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001979 *p++ = 0x01; /* length */
Joe Perches475be4d2012-02-19 19:52:38 -08001980 *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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 *p++ = len_phone; /* length */
Joe Perches475be4d2012-02-19 19:52:38 -08001989 for (l = 0; l < len_phone; l++)
1990 *p++ = pc->chan->setup.phone[l];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001991
Joe Perches475be4d2012-02-19 19:52:38 -08001992 if (len_sub)
1993 { *p++ = 0x04; /* called party subaddress */
1994 *p++ = len_sub - 2;
1995 while (*subp) *p++ = *subp++;
1996 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997
Joe Perches475be4d2012-02-19 19:52:38 -08001998 *p++ = 0x01; /* screening identifier */
1999 *p++ = 0x01;
2000 *p++ = pc->chan->setup.screen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001
2002 l = p - tmp;
2003 if (!(skb = l3_alloc_skb(l))) return;
2004 memcpy(skb_put(skb, l), tmp, l);
2005
Joe Perches475be4d2012-02-19 19:52:38 -08002006 l3_msg(pc->st, DL_DATA | REQUEST, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007} /* l3ni1_redir_req */
2008
2009/********************************************/
2010/* handle deflection request in early state */
2011/********************************************/
2012static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
2013{
Joe Perches475be4d2012-02-19 19:52:38 -08002014 l3ni1_proceed_req(pc, pr, arg);
2015 l3ni1_redir_req(pc, pr, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002016} /* l3ni1_redir_req_early */
2017
2018/***********************************************/
2019/* handle special commands for this protocol. */
Lucas De Marchi25985ed2011-03-30 22:57:33 -03002020/* Examples are call independent services like */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021/* remote operations with dummy callref. */
2022/***********************************************/
2023static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic)
2024{ u_char id;
Joe Perches475be4d2012-02-19 19:52:38 -08002025 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
Joe Perches475be4d2012-02-19 19:52:38 -08002031 switch (ic->arg)
2032 { case NI1_CMD_INVOKE:
2033 if (ic->parm.ni1_io.datalen < 0) return (-2); /* invalid parameter */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002034
Joe Perches475be4d2012-02-19 19:52:38 -08002035 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002040
Joe Perches475be4d2012-02-19 19:52:38 -08002041 if (!(id = new_invoke_id(st)))
2042 return (0); /* first get a invoke id -> return if no available */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002043
Joe Perches475be4d2012-02-19 19:52:38 -08002044 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056
Joe Perches475be4d2012-02-19 19:52:38 -08002057 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002061
Joe Perches475be4d2012-02-19 19:52:38 -08002062 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103} /* l3ni1_cmd_global */
2104
Joe Perches475be4d2012-02-19 19:52:38 -08002105static void
Linus Torvalds1da177e2005-04-16 15:20:36 -07002106l3ni1_io_timer(struct l3_process *pc)
2107{ isdn_ctrl ic;
Joe Perches475be4d2012-02-19 19:52:38 -08002108 struct IsdnCardState *cs = pc->st->l1.hardware;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109
Joe Perches475be4d2012-02-19 19:52:38 -08002110 L3DelTimer(&pc->timer); /* remove timer */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002111
Joe Perches475be4d2012-02-19 19:52:38 -08002112 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 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002123
Joe Perches475be4d2012-02-19 19:52:38 -08002124 cs->iif.statcallb(&ic);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
Joe Perches475be4d2012-02-19 19:52:38 -08002126 ni1_release_l3_process(pc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127} /* l3ni1_io_timer */
2128
2129static void
2130l3ni1_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
2154static void
2155l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg)
2156{
2157}
2158
2159static void
2160l3ni1_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
2169static void
2170l3ni1_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
2184static void
2185l3ni1_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
2195static void
2196l3ni1_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
2224static void
2225l3ni1_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
2234static void
2235l3ni1_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
2244static void
2245l3ni1_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
2253static void
2254l3ni1_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
2261static void
2262l3ni1_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
2273static void
2274l3ni1_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
2283static void
2284l3ni1_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
2291static void
2292l3ni1_status(struct l3_process *pc, u_char pr, void *arg)
2293{
2294 u_char *p;
2295 struct sk_buff *skb = arg;
Joe Perches475be4d2012-02-19 19:52:38 -08002296 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002297 u_char cause = 0, callState = 0;
Joe Perches475be4d2012-02-19 19:52:38 -08002298
Linus Torvalds1da177e2005-04-16 15:20:36 -07002299 if ((ret = l3ni1_get_cause(pc, skb))) {
2300 if (pc->debug & L3_DEB_WARN)
Joe Perches475be4d2012-02-19 19:52:38 -08002301 l3_debug(pc->st, "STATUS get_cause ret(%d)", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302 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;
Joe Perches475be4d2012-02-19 19:52:38 -08002326
Linus Torvalds1da177e2005-04-16 15:20:36 -07002327 if (pc->debug & L3_DEB_WARN)
Joe Perches475be4d2012-02-19 19:52:38 -08002328 l3_debug(pc->st, "STATUS error(%d/%d)", ret, cause);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329 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
2349static void
2350l3ni1_facility(struct l3_process *pc, u_char pr, void *arg)
2351{
2352 struct sk_buff *skb = arg;
2353 int ret;
Joe Perches475be4d2012-02-19 19:52:38 -08002354
Linus Torvalds1da177e2005-04-16 15:20:36 -07002355 ret = check_infoelements(pc, skb, ie_FACILITY);
2356 l3ni1_std_ie_err(pc, ret);
Joe Perches475be4d2012-02-19 19:52:38 -08002357 {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002358 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
2364static void
2365l3ni1_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
2393static void
2394l3ni1_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)
Joe Perches475be4d2012-02-19 19:52:38 -08002406 l3_debug(pc->st, "SUSPACK check ie(%d)", ret);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002407 ni1_release_l3_process(pc);
2408}
2409
2410static void
2411l3ni1_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)
Joe Perches475be4d2012-02-19 19:52:38 -08002418 l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)", ret);
2419 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002420 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
2438static void
2439l3ni1_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
2468static void
2469l3ni1_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
2502static void
2503l3ni1_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)
Joe Perches475be4d2012-02-19 19:52:38 -08002510 l3_debug(pc->st, "RES_REJ get_cause ret(%d)", ret);
2511 if (ret < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002512 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
2531static void
2532l3ni1_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);
Joe Perches475be4d2012-02-19 19:52:38 -08002565
Linus Torvalds1da177e2005-04-16 15:20:36 -07002566 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
2586static void
2587l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
2588{
Joe Perches475be4d2012-02-19 19:52:38 -08002589 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593}
2594
2595static void
2596l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg)
2597{
Joe Perches475be4d2012-02-19 19:52:38 -08002598 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002603}
2604
2605static void
2606l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
2607{
Joe Perches475be4d2012-02-19 19:52:38 -08002608 L3DelTimer(&pc->timer);
2609 L3AddTimer(&pc->timer, T309, CC_T309);
2610 l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002611}
Joe Perches475be4d2012-02-19 19:52:38 -08002612
Linus Torvalds1da177e2005-04-16 15:20:36 -07002613static void
2614l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
2615{
2616 L3DelTimer(&pc->timer);
Joe Perches475be4d2012-02-19 19:52:38 -08002617
2618 pc->para.cause = 0x1F; /* normal, unspecified */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002619 l3ni1_status_send(pc, 0, NULL);
2620}
2621
Joe Perches475be4d2012-02-19 19:52:38 -08002622static void l3ni1_SendSpid(struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002623{
Joe Perches475be4d2012-02-19 19:52:38 -08002624 u_char *p;
2625 char *pSPID;
2626 struct Channel *pChan = pc->st->lli.userdata;
2627 int l;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628
Joe Perches475be4d2012-02-19 19:52:38 -08002629 if (skb)
2630 dev_kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002631
Joe Perches475be4d2012-02-19 19:52:38 -08002632 if (!(pSPID = strchr(pChan->setup.eazmsn, ':')))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633 {
Joe Perches475be4d2012-02-19 19:52:38 -08002634 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);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002637 return;
2638 }
2639
Joe Perches475be4d2012-02-19 19:52:38 -08002640 l = strlen(++pSPID);
2641 if (!(skb = l3_alloc_skb(5 + l)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002642 {
Joe Perches475be4d2012-02-19 19:52:38 -08002643 printk(KERN_ERR "HiSax can't get memory to send SPID\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002644 return;
2645 }
2646
Joe Perches475be4d2012-02-19 19:52:38 -08002647 p = skb_put(skb, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002648 *p++ = PROTO_DIS_EURO;
2649 *p++ = 0;
2650 *p++ = MT_INFORMATION;
2651 *p++ = IE_SPID;
2652 *p++ = l;
2653
Joe Perches475be4d2012-02-19 19:52:38 -08002654 memcpy(skb_put(skb, l), pSPID, l);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655
Joe Perches475be4d2012-02-19 19:52:38 -08002656 newl3state(pc, iNewState);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657
Joe Perches475be4d2012-02-19 19:52:38 -08002658 L3DelTimer(&pc->timer);
2659 L3AddTimer(&pc->timer, TSPID, CC_TSPID);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002660
Joe Perches475be4d2012-02-19 19:52:38 -08002661 pc->st->l3.l3l2(pc->st, DL_DATA | REQUEST, skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002662}
2663
Joe Perches475be4d2012-02-19 19:52:38 -08002664static void l3ni1_spid_send(struct l3_process *pc, u_char pr, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002665{
Joe Perches475be4d2012-02-19 19:52:38 -08002666 l3ni1_SendSpid(pc, pr, arg, 20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002667}
2668
Joe Perches475be4d2012-02-19 19:52:38 -08002669static void l3ni1_spid_epid(struct l3_process *pc, u_char pr, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002670{
2671 struct sk_buff *skb = arg;
2672
Joe Perches475be4d2012-02-19 19:52:38 -08002673 if (skb->data[1] == 0)
2674 if (skb->data[3] == IE_ENDPOINT_ID)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 {
Joe Perches475be4d2012-02-19 19:52:38 -08002676 L3DelTimer(&pc->timer);
2677 newl3state(pc, 0);
2678 l3_msg(pc->st, DL_ESTABLISH | CONFIRM, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002679 }
Joe Perches475be4d2012-02-19 19:52:38 -08002680 dev_kfree_skb(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681}
2682
Joe Perches475be4d2012-02-19 19:52:38 -08002683static void l3ni1_spid_tout(struct l3_process *pc, u_char pr, void *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002684{
Joe Perches475be4d2012-02-19 19:52:38 -08002685 if (pc->state < 22)
2686 l3ni1_SendSpid(pc, pr, arg, pc->state + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002687 else
2688 {
Joe Perches475be4d2012-02-19 19:52:38 -08002689 L3DelTimer(&pc->timer);
2690 dev_kfree_skb(arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002691
Joe Perches475be4d2012-02-19 19:52:38 -08002692 printk(KERN_ERR "SPID not accepted\n");
2693 newl3state(pc, 0);
2694 pc->st->l3.l3l2(pc->st, DL_RELEASE | REQUEST, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002695 }
2696}
2697
2698/* *INDENT-OFF* */
2699static 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},
Joe Perches475be4d2012-02-19 19:52:38 -08002727 {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},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002733 {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},
Joe Perches475be4d2012-02-19 19:52:38 -08002755 { SBIT(20) | SBIT(21) | SBIT(22),
2756 CC_TSPID, l3ni1_spid_tout },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002757};
2758
Linus Torvalds1da177e2005-04-16 15:20:36 -07002759static 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 Torvalds1da177e2005-04-16 15:20:36 -07002811static 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),
Joe Perches475be4d2012-02-19 19:52:38 -08002818 MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002819*/
Joe Perches475be4d2012-02-19 19:52:38 -08002820 { SBIT(0), MT_DL_ESTABLISHED, l3ni1_spid_send },
2821 { SBIT(20) | SBIT(21) | SBIT(22), MT_INFORMATION, l3ni1_spid_epid },
Linus Torvalds1da177e2005-04-16 15:20:36 -07002822};
Linus Torvalds1da177e2005-04-16 15:20:36 -07002823
2824static struct stateentry manstatelist[] =
2825{
Joe Perches475be4d2012-02-19 19:52:38 -08002826 {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},
Linus Torvalds1da177e2005-04-16 15:20:36 -07002834};
2835
Linus Torvalds1da177e2005-04-16 15:20:36 -07002836/* *INDENT-ON* */
2837
2838
2839static void
2840global_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
Joe Perches475be4d2012-02-19 19:52:38 -08002848 if (skb)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002849 proc->callref = skb->data[2]; /* cr flag */
2850 else
2851 proc->callref = 0;
Karsten Keilba2d6cc2009-07-24 18:26:08 +02002852 for (i = 0; i < ARRAY_SIZE(globalmes_list); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002853 if ((mt == globalmes_list[i].primitive) &&
2854 ((1 << proc->state) & globalmes_list[i].state))
2855 break;
Karsten Keilba2d6cc2009-07-24 18:26:08 +02002856 if (i == ARRAY_SIZE(globalmes_list)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002857 if (st->l3.debug & L3_DEB_STATE) {
2858 l3_debug(st, "ni1 global state %d mt %x unhandled",
Joe Perches475be4d2012-02-19 19:52:38 -08002859 proc->state, mt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002860 }
2861 MsgHead(p, proc->callref, MT_STATUS);
2862 *p++ = IE_CAUSE;
2863 *p++ = 0x2;
2864 *p++ = 0x80;
Joe Perches475be4d2012-02-19 19:52:38 -08002865 *p++ = 81 | 0x80; /* invalid cr */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002866 *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",
Joe Perches475be4d2012-02-19 19:52:38 -08002877 proc->state, mt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002878 }
2879 globalmes_list[i].rout(proc, mt, skb);
2880 }
2881}
2882
2883static void
2884ni1up(struct PStack *st, int pr, void *arg)
2885{
David S. Miller1397c5d2011-04-17 16:43:20 -07002886 int i, mt, cr, callState;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002887 char *ptr;
2888 u_char *p;
2889 struct sk_buff *skb = arg;
2890 struct l3_process *proc;
2891
2892 switch (pr) {
Joe Perches475be4d2012-02-19 19:52:38 -08002893 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;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002902
Joe Perches475be4d2012-02-19 19:52:38 -08002903 case (DL_ESTABLISH | CONFIRM):
2904 global_handler(st, MT_DL_ESTABLISHED, NULL);
2905 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906
Joe Perches475be4d2012-02-19 19:52:38 -08002907 default:
2908 printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr);
2909 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002910 }
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))) {
Joe Perches475be4d2012-02-19 19:52:38 -08002944 l3ni1_parse_facility(st, NULL,
2945 (pr == (DL_DATA | INDICATION)) ? -1 : -2, p);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002946 dev_kfree_skb(skb);
Joe Perches475be4d2012-02-19 19:52:38 -08002947 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002948 }
2949 }
2950 else
2951 {
2952 global_handler(st, mt, skb);
2953 return;
2954 }
Joe Perches475be4d2012-02-19 19:52:38 -08002955
Linus Torvalds1da177e2005-04-16 15:20:36 -07002956 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;
Joe Perches475be4d2012-02-19 19:52:38 -08002960 } else if ((((skb->data[1] & 0x0f) == 1) && (0 == (cr & 0x7f))) ||
2961 (((skb->data[1] & 0x0f) == 2) && (0 == (cr & 0x7fff)))) { /* Global CallRef */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002962 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 Torvalds1da177e2005-04-16 15:20:36 -07002989 if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
2990 ptr++;
2991 if (*ptr++ == 2)
2992 ptr++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002993 }
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 }
Joe Perches475be4d2012-02-19 19:52:38 -08003039 if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
3040 l3ni1_deliver_display(proc, pr, p); /* Display IE included */
Karsten Keilba2d6cc2009-07-24 18:26:08 +02003041 for (i = 0; i < ARRAY_SIZE(datastatelist); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003042 if ((mt == datastatelist[i].primitive) &&
3043 ((1 << proc->state) & datastatelist[i].state))
3044 break;
Karsten Keilba2d6cc2009-07-24 18:26:08 +02003045 if (i == ARRAY_SIZE(datastatelist)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 if (st->l3.debug & L3_DEB_STATE) {
3047 l3_debug(st, "ni1up%sstate %d mt %#x unhandled",
Joe Perches475be4d2012-02-19 19:52:38 -08003048 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
3049 proc->state, mt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003050 }
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",
Joe Perches475be4d2012-02-19 19:52:38 -08003058 (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
3059 proc->state, mt);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003060 }
3061 datastatelist[i].rout(proc, pr, skb);
3062 }
3063 dev_kfree_skb(skb);
3064 return;
3065}
3066
3067static void
3068ni1down(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
Joe Perches475be4d2012-02-19 19:52:38 -08003095 if (pr == (CC_TNI1_IO | REQUEST)) {
3096 l3ni1_io_timer(proc); /* timer expires */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003097 return;
Joe Perches475be4d2012-02-19 19:52:38 -08003098 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003099
Karsten Keilba2d6cc2009-07-24 18:26:08 +02003100 for (i = 0; i < ARRAY_SIZE(downstatelist); i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003101 if ((pr == downstatelist[i].primitive) &&
3102 ((1 << proc->state) & downstatelist[i].state))
3103 break;
Karsten Keilba2d6cc2009-07-24 18:26:08 +02003104 if (i == ARRAY_SIZE(downstatelist)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07003105 if (st->l3.debug & L3_DEB_STATE) {
3106 l3_debug(st, "ni1down state %d prim %#x unhandled",
Joe Perches475be4d2012-02-19 19:52:38 -08003107 proc->state, pr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003108 }
3109 } else {
3110 if (st->l3.debug & L3_DEB_STATE) {
3111 l3_debug(st, "ni1down state %d prim %#x",
Joe Perches475be4d2012-02-19 19:52:38 -08003112 proc->state, pr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003113 }
3114 downstatelist[i].rout(proc, pr, arg);
3115 }
3116}
3117
3118static void
3119ni1man(struct PStack *st, int pr, void *arg)
3120{
Joe Perches475be4d2012-02-19 19:52:38 -08003121 int i;
3122 struct l3_process *proc = arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003123
Joe Perches475be4d2012-02-19 19:52:38 -08003124 if (!proc) {
3125 printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr);
3126 return;
3127 }
3128 for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
3129 if ((pr == manstatelist[i].primitive) &&
3130 ((1 << proc->state) & manstatelist[i].state))
3131 break;
3132 if (i == ARRAY_SIZE(manstatelist)) {
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 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003144}
Joe Perches475be4d2012-02-19 19:52:38 -08003145
Linus Torvalds1da177e2005-04-16 15:20:36 -07003146void
3147setstack_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;
Joe Perches475be4d2012-02-19 19:52:38 -08003160 while (i < 32)
3161 st->prot.ni1.invoke_used[i++] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003162
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;
Joe Perches475be4d2012-02-19 19:52:38 -08003172 st->l3.global->prot.ni1.invoke_id = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003173
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}