diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/isdn/hisax/l3_1tr6.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/isdn/hisax/l3_1tr6.c')
-rw-r--r-- | drivers/isdn/hisax/l3_1tr6.c | 955 |
1 files changed, 955 insertions, 0 deletions
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c new file mode 100644 index 000000000000..d6c1c8f8329d --- /dev/null +++ b/drivers/isdn/hisax/l3_1tr6.c | |||
@@ -0,0 +1,955 @@ | |||
1 | /* $Id: l3_1tr6.c,v 2.15.2.3 2004/01/13 14:31:25 keil Exp $ | ||
2 | * | ||
3 | * German 1TR6 D-channel protocol | ||
4 | * | ||
5 | * Author Karsten Keil | ||
6 | * Copyright by Karsten Keil <keil@isdn4linux.de> | ||
7 | * | ||
8 | * This software may be used and distributed according to the terms | ||
9 | * of the GNU General Public License, incorporated herein by reference. | ||
10 | * | ||
11 | * For changes and modifications please read | ||
12 | * Documentation/isdn/HiSax.cert | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include "hisax.h" | ||
17 | #include "l3_1tr6.h" | ||
18 | #include "isdnl3.h" | ||
19 | #include <linux/ctype.h> | ||
20 | |||
21 | extern char *HiSax_getrev(const char *revision); | ||
22 | const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $"; | ||
23 | |||
24 | #define MsgHead(ptr, cref, mty, dis) \ | ||
25 | *ptr++ = dis; \ | ||
26 | *ptr++ = 0x1; \ | ||
27 | *ptr++ = cref ^ 0x80; \ | ||
28 | *ptr++ = mty | ||
29 | |||
30 | static void | ||
31 | l3_1TR6_message(struct l3_process *pc, u_char mt, u_char pd) | ||
32 | { | ||
33 | struct sk_buff *skb; | ||
34 | u_char *p; | ||
35 | |||
36 | if (!(skb = l3_alloc_skb(4))) | ||
37 | return; | ||
38 | p = skb_put(skb, 4); | ||
39 | MsgHead(p, pc->callref, mt, pd); | ||
40 | l3_msg(pc->st, DL_DATA | REQUEST, skb); | ||
41 | } | ||
42 | |||
43 | static void | ||
44 | l3_1tr6_release_req(struct l3_process *pc, u_char pr, void *arg) | ||
45 | { | ||
46 | StopAllL3Timer(pc); | ||
47 | newl3state(pc, 19); | ||
48 | l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); | ||
49 | L3AddTimer(&pc->timer, T308, CC_T308_1); | ||
50 | } | ||
51 | |||
52 | static void | ||
53 | l3_1tr6_invalid(struct l3_process *pc, u_char pr, void *arg) | ||
54 | { | ||
55 | struct sk_buff *skb = arg; | ||
56 | |||
57 | dev_kfree_skb(skb); | ||
58 | l3_1tr6_release_req(pc, 0, NULL); | ||
59 | } | ||
60 | |||
61 | static void | ||
62 | l3_1tr6_error(struct l3_process *pc, u_char *msg, struct sk_buff *skb) | ||
63 | { | ||
64 | dev_kfree_skb(skb); | ||
65 | if (pc->st->l3.debug & L3_DEB_WARN) | ||
66 | l3_debug(pc->st, msg); | ||
67 | l3_1tr6_release_req(pc, 0, NULL); | ||
68 | } | ||
69 | |||
70 | static void | ||
71 | l3_1tr6_setup_req(struct l3_process *pc, u_char pr, void *arg) | ||
72 | { | ||
73 | struct sk_buff *skb; | ||
74 | u_char tmp[128]; | ||
75 | u_char *p = tmp; | ||
76 | u_char *teln; | ||
77 | u_char *eaz; | ||
78 | u_char channel = 0; | ||
79 | int l; | ||
80 | |||
81 | MsgHead(p, pc->callref, MT_N1_SETUP, PROTO_DIS_N1); | ||
82 | teln = pc->para.setup.phone; | ||
83 | pc->para.spv = 0; | ||
84 | if (!isdigit(*teln)) { | ||
85 | switch (0x5f & *teln) { | ||
86 | case 'S': | ||
87 | pc->para.spv = 1; | ||
88 | break; | ||
89 | case 'C': | ||
90 | channel = 0x08; | ||
91 | case 'P': | ||
92 | channel |= 0x80; | ||
93 | teln++; | ||
94 | if (*teln == '1') | ||
95 | channel |= 0x01; | ||
96 | else | ||
97 | channel |= 0x02; | ||
98 | break; | ||
99 | default: | ||
100 | if (pc->st->l3.debug & L3_DEB_WARN) | ||
101 | l3_debug(pc->st, "Wrong MSN Code"); | ||
102 | break; | ||
103 | } | ||
104 | teln++; | ||
105 | } | ||
106 | if (channel) { | ||
107 | *p++ = 0x18; /* channel indicator */ | ||
108 | *p++ = 1; | ||
109 | *p++ = channel; | ||
110 | } | ||
111 | if (pc->para.spv) { /* SPV ? */ | ||
112 | /* NSF SPV */ | ||
113 | *p++ = WE0_netSpecFac; | ||
114 | *p++ = 4; /* Laenge */ | ||
115 | *p++ = 0; | ||
116 | *p++ = FAC_SPV; /* SPV */ | ||
117 | *p++ = pc->para.setup.si1; /* 0 for all Services */ | ||
118 | *p++ = pc->para.setup.si2; /* 0 for all Services */ | ||
119 | *p++ = WE0_netSpecFac; | ||
120 | *p++ = 4; /* Laenge */ | ||
121 | *p++ = 0; | ||
122 | *p++ = FAC_Activate; /* aktiviere SPV (default) */ | ||
123 | *p++ = pc->para.setup.si1; /* 0 for all Services */ | ||
124 | *p++ = pc->para.setup.si2; /* 0 for all Services */ | ||
125 | } | ||
126 | eaz = pc->para.setup.eazmsn; | ||
127 | if (*eaz) { | ||
128 | *p++ = WE0_origAddr; | ||
129 | *p++ = strlen(eaz) + 1; | ||
130 | /* Classify as AnyPref. */ | ||
131 | *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ | ||
132 | while (*eaz) | ||
133 | *p++ = *eaz++ & 0x7f; | ||
134 | } | ||
135 | *p++ = WE0_destAddr; | ||
136 | *p++ = strlen(teln) + 1; | ||
137 | /* Classify as AnyPref. */ | ||
138 | *p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */ | ||
139 | while (*teln) | ||
140 | *p++ = *teln++ & 0x7f; | ||
141 | |||
142 | *p++ = WE_Shift_F6; | ||
143 | /* Codesatz 6 fuer Service */ | ||
144 | *p++ = WE6_serviceInd; | ||
145 | *p++ = 2; /* len=2 info,info2 */ | ||
146 | *p++ = pc->para.setup.si1; | ||
147 | *p++ = pc->para.setup.si2; | ||
148 | |||
149 | l = p - tmp; | ||
150 | if (!(skb = l3_alloc_skb(l))) | ||
151 | return; | ||
152 | memcpy(skb_put(skb, l), tmp, l); | ||
153 | L3DelTimer(&pc->timer); | ||
154 | L3AddTimer(&pc->timer, T303, CC_T303); | ||
155 | newl3state(pc, 1); | ||
156 | l3_msg(pc->st, DL_DATA | REQUEST, skb); | ||
157 | } | ||
158 | |||
159 | static void | ||
160 | l3_1tr6_setup(struct l3_process *pc, u_char pr, void *arg) | ||
161 | { | ||
162 | u_char *p; | ||
163 | int bcfound = 0; | ||
164 | char tmp[80]; | ||
165 | struct sk_buff *skb = arg; | ||
166 | |||
167 | p = skb->data; | ||
168 | |||
169 | /* Channel Identification */ | ||
170 | p = skb->data; | ||
171 | if ((p = findie(p, skb->len, WE0_chanID, 0))) { | ||
172 | if (p[1] != 1) { | ||
173 | l3_1tr6_error(pc, "setup wrong chanID len", skb); | ||
174 | return; | ||
175 | } | ||
176 | if ((p[2] & 0xf4) != 0x80) { | ||
177 | l3_1tr6_error(pc, "setup wrong WE0_chanID", skb); | ||
178 | return; | ||
179 | } | ||
180 | if ((pc->para.bchannel = p[2] & 0x3)) | ||
181 | bcfound++; | ||
182 | } else { | ||
183 | l3_1tr6_error(pc, "missing setup chanID", skb); | ||
184 | return; | ||
185 | } | ||
186 | |||
187 | p = skb->data; | ||
188 | if ((p = findie(p, skb->len, WE6_serviceInd, 6))) { | ||
189 | pc->para.setup.si1 = p[2]; | ||
190 | pc->para.setup.si2 = p[3]; | ||
191 | } else { | ||
192 | l3_1tr6_error(pc, "missing setup SI", skb); | ||
193 | return; | ||
194 | } | ||
195 | |||
196 | p = skb->data; | ||
197 | if ((p = findie(p, skb->len, WE0_destAddr, 0))) | ||
198 | iecpy(pc->para.setup.eazmsn, p, 1); | ||
199 | else | ||
200 | pc->para.setup.eazmsn[0] = 0; | ||
201 | |||
202 | p = skb->data; | ||
203 | if ((p = findie(p, skb->len, WE0_origAddr, 0))) { | ||
204 | iecpy(pc->para.setup.phone, p, 1); | ||
205 | } else | ||
206 | pc->para.setup.phone[0] = 0; | ||
207 | |||
208 | p = skb->data; | ||
209 | pc->para.spv = 0; | ||
210 | if ((p = findie(p, skb->len, WE0_netSpecFac, 0))) { | ||
211 | if ((FAC_SPV == p[3]) || (FAC_Activate == p[3])) | ||
212 | pc->para.spv = 1; | ||
213 | } | ||
214 | dev_kfree_skb(skb); | ||
215 | |||
216 | /* Signal all services, linklevel takes care of Service-Indicator */ | ||
217 | if (bcfound) { | ||
218 | if ((pc->para.setup.si1 != 7) && (pc->st->l3.debug & L3_DEB_WARN)) { | ||
219 | sprintf(tmp, "non-digital call: %s -> %s", | ||
220 | pc->para.setup.phone, | ||
221 | pc->para.setup.eazmsn); | ||
222 | l3_debug(pc->st, tmp); | ||
223 | } | ||
224 | newl3state(pc, 6); | ||
225 | pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc); | ||
226 | } else | ||
227 | release_l3_process(pc); | ||
228 | } | ||
229 | |||
230 | static void | ||
231 | l3_1tr6_setup_ack(struct l3_process *pc, u_char pr, void *arg) | ||
232 | { | ||
233 | u_char *p; | ||
234 | struct sk_buff *skb = arg; | ||
235 | |||
236 | L3DelTimer(&pc->timer); | ||
237 | p = skb->data; | ||
238 | newl3state(pc, 2); | ||
239 | if ((p = findie(p, skb->len, WE0_chanID, 0))) { | ||
240 | if (p[1] != 1) { | ||
241 | l3_1tr6_error(pc, "setup_ack wrong chanID len", skb); | ||
242 | return; | ||
243 | } | ||
244 | if ((p[2] & 0xf4) != 0x80) { | ||
245 | l3_1tr6_error(pc, "setup_ack wrong WE0_chanID", skb); | ||
246 | return; | ||
247 | } | ||
248 | pc->para.bchannel = p[2] & 0x3; | ||
249 | } else { | ||
250 | l3_1tr6_error(pc, "missing setup_ack WE0_chanID", skb); | ||
251 | return; | ||
252 | } | ||
253 | dev_kfree_skb(skb); | ||
254 | L3AddTimer(&pc->timer, T304, CC_T304); | ||
255 | pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc); | ||
256 | } | ||
257 | |||
258 | static void | ||
259 | l3_1tr6_call_sent(struct l3_process *pc, u_char pr, void *arg) | ||
260 | { | ||
261 | u_char *p; | ||
262 | struct sk_buff *skb = arg; | ||
263 | |||
264 | L3DelTimer(&pc->timer); | ||
265 | p = skb->data; | ||
266 | if ((p = findie(p, skb->len, WE0_chanID, 0))) { | ||
267 | if (p[1] != 1) { | ||
268 | l3_1tr6_error(pc, "call sent wrong chanID len", skb); | ||
269 | return; | ||
270 | } | ||
271 | if ((p[2] & 0xf4) != 0x80) { | ||
272 | l3_1tr6_error(pc, "call sent wrong WE0_chanID", skb); | ||
273 | return; | ||
274 | } | ||
275 | if ((pc->state == 2) && (pc->para.bchannel != (p[2] & 0x3))) { | ||
276 | l3_1tr6_error(pc, "call sent wrong chanID value", skb); | ||
277 | return; | ||
278 | } | ||
279 | pc->para.bchannel = p[2] & 0x3; | ||
280 | } else { | ||
281 | l3_1tr6_error(pc, "missing call sent WE0_chanID", skb); | ||
282 | return; | ||
283 | } | ||
284 | dev_kfree_skb(skb); | ||
285 | L3AddTimer(&pc->timer, T310, CC_T310); | ||
286 | newl3state(pc, 3); | ||
287 | pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc); | ||
288 | } | ||
289 | |||
290 | static void | ||
291 | l3_1tr6_alert(struct l3_process *pc, u_char pr, void *arg) | ||
292 | { | ||
293 | struct sk_buff *skb = arg; | ||
294 | |||
295 | dev_kfree_skb(skb); | ||
296 | L3DelTimer(&pc->timer); /* T304 */ | ||
297 | newl3state(pc, 4); | ||
298 | pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc); | ||
299 | } | ||
300 | |||
301 | static void | ||
302 | l3_1tr6_info(struct l3_process *pc, u_char pr, void *arg) | ||
303 | { | ||
304 | u_char *p; | ||
305 | int i, tmpcharge = 0; | ||
306 | char a_charge[8], tmp[32]; | ||
307 | struct sk_buff *skb = arg; | ||
308 | |||
309 | p = skb->data; | ||
310 | if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) { | ||
311 | iecpy(a_charge, p, 1); | ||
312 | for (i = 0; i < strlen(a_charge); i++) { | ||
313 | tmpcharge *= 10; | ||
314 | tmpcharge += a_charge[i] & 0xf; | ||
315 | } | ||
316 | if (tmpcharge > pc->para.chargeinfo) { | ||
317 | pc->para.chargeinfo = tmpcharge; | ||
318 | pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); | ||
319 | } | ||
320 | if (pc->st->l3.debug & L3_DEB_CHARGE) { | ||
321 | sprintf(tmp, "charging info %d", pc->para.chargeinfo); | ||
322 | l3_debug(pc->st, tmp); | ||
323 | } | ||
324 | } else if (pc->st->l3.debug & L3_DEB_CHARGE) | ||
325 | l3_debug(pc->st, "charging info not found"); | ||
326 | dev_kfree_skb(skb); | ||
327 | |||
328 | } | ||
329 | |||
330 | static void | ||
331 | l3_1tr6_info_s2(struct l3_process *pc, u_char pr, void *arg) | ||
332 | { | ||
333 | struct sk_buff *skb = arg; | ||
334 | |||
335 | dev_kfree_skb(skb); | ||
336 | } | ||
337 | |||
338 | static void | ||
339 | l3_1tr6_connect(struct l3_process *pc, u_char pr, void *arg) | ||
340 | { | ||
341 | struct sk_buff *skb = arg; | ||
342 | |||
343 | L3DelTimer(&pc->timer); /* T310 */ | ||
344 | if (!findie(skb->data, skb->len, WE6_date, 6)) { | ||
345 | l3_1tr6_error(pc, "missing connect date", skb); | ||
346 | return; | ||
347 | } | ||
348 | newl3state(pc, 10); | ||
349 | dev_kfree_skb(skb); | ||
350 | pc->para.chargeinfo = 0; | ||
351 | pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc); | ||
352 | } | ||
353 | |||
354 | static void | ||
355 | l3_1tr6_rel(struct l3_process *pc, u_char pr, void *arg) | ||
356 | { | ||
357 | struct sk_buff *skb = arg; | ||
358 | u_char *p; | ||
359 | |||
360 | p = skb->data; | ||
361 | if ((p = findie(p, skb->len, WE0_cause, 0))) { | ||
362 | if (p[1] > 0) { | ||
363 | pc->para.cause = p[2]; | ||
364 | if (p[1] > 1) | ||
365 | pc->para.loc = p[3]; | ||
366 | else | ||
367 | pc->para.loc = 0; | ||
368 | } else { | ||
369 | pc->para.cause = 0; | ||
370 | pc->para.loc = 0; | ||
371 | } | ||
372 | } else { | ||
373 | pc->para.cause = NO_CAUSE; | ||
374 | l3_1tr6_error(pc, "missing REL cause", skb); | ||
375 | return; | ||
376 | } | ||
377 | dev_kfree_skb(skb); | ||
378 | StopAllL3Timer(pc); | ||
379 | newl3state(pc, 0); | ||
380 | l3_1TR6_message(pc, MT_N1_REL_ACK, PROTO_DIS_N1); | ||
381 | pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); | ||
382 | release_l3_process(pc); | ||
383 | } | ||
384 | |||
385 | static void | ||
386 | l3_1tr6_rel_ack(struct l3_process *pc, u_char pr, void *arg) | ||
387 | { | ||
388 | struct sk_buff *skb = arg; | ||
389 | |||
390 | dev_kfree_skb(skb); | ||
391 | StopAllL3Timer(pc); | ||
392 | newl3state(pc, 0); | ||
393 | pc->para.cause = NO_CAUSE; | ||
394 | pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc); | ||
395 | release_l3_process(pc); | ||
396 | } | ||
397 | |||
398 | static void | ||
399 | l3_1tr6_disc(struct l3_process *pc, u_char pr, void *arg) | ||
400 | { | ||
401 | struct sk_buff *skb = arg; | ||
402 | u_char *p; | ||
403 | int i, tmpcharge = 0; | ||
404 | char a_charge[8], tmp[32]; | ||
405 | |||
406 | StopAllL3Timer(pc); | ||
407 | p = skb->data; | ||
408 | if ((p = findie(p, skb->len, WE6_chargingInfo, 6))) { | ||
409 | iecpy(a_charge, p, 1); | ||
410 | for (i = 0; i < strlen(a_charge); i++) { | ||
411 | tmpcharge *= 10; | ||
412 | tmpcharge += a_charge[i] & 0xf; | ||
413 | } | ||
414 | if (tmpcharge > pc->para.chargeinfo) { | ||
415 | pc->para.chargeinfo = tmpcharge; | ||
416 | pc->st->l3.l3l4(pc->st, CC_CHARGE | INDICATION, pc); | ||
417 | } | ||
418 | if (pc->st->l3.debug & L3_DEB_CHARGE) { | ||
419 | sprintf(tmp, "charging info %d", pc->para.chargeinfo); | ||
420 | l3_debug(pc->st, tmp); | ||
421 | } | ||
422 | } else if (pc->st->l3.debug & L3_DEB_CHARGE) | ||
423 | l3_debug(pc->st, "charging info not found"); | ||
424 | |||
425 | |||
426 | p = skb->data; | ||
427 | if ((p = findie(p, skb->len, WE0_cause, 0))) { | ||
428 | if (p[1] > 0) { | ||
429 | pc->para.cause = p[2]; | ||
430 | if (p[1] > 1) | ||
431 | pc->para.loc = p[3]; | ||
432 | else | ||
433 | pc->para.loc = 0; | ||
434 | } else { | ||
435 | pc->para.cause = 0; | ||
436 | pc->para.loc = 0; | ||
437 | } | ||
438 | } else { | ||
439 | if (pc->st->l3.debug & L3_DEB_WARN) | ||
440 | l3_debug(pc->st, "cause not found"); | ||
441 | pc->para.cause = NO_CAUSE; | ||
442 | } | ||
443 | if (!findie(skb->data, skb->len, WE6_date, 6)) { | ||
444 | l3_1tr6_error(pc, "missing connack date", skb); | ||
445 | return; | ||
446 | } | ||
447 | dev_kfree_skb(skb); | ||
448 | newl3state(pc, 12); | ||
449 | pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc); | ||
450 | } | ||
451 | |||
452 | |||
453 | static void | ||
454 | l3_1tr6_connect_ack(struct l3_process *pc, u_char pr, void *arg) | ||
455 | { | ||
456 | struct sk_buff *skb = arg; | ||
457 | |||
458 | if (!findie(skb->data, skb->len, WE6_date, 6)) { | ||
459 | l3_1tr6_error(pc, "missing connack date", skb); | ||
460 | return; | ||
461 | } | ||
462 | dev_kfree_skb(skb); | ||
463 | newl3state(pc, 10); | ||
464 | pc->para.chargeinfo = 0; | ||
465 | L3DelTimer(&pc->timer); | ||
466 | pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc); | ||
467 | } | ||
468 | |||
469 | static void | ||
470 | l3_1tr6_alert_req(struct l3_process *pc, u_char pr, void *arg) | ||
471 | { | ||
472 | newl3state(pc, 7); | ||
473 | l3_1TR6_message(pc, MT_N1_ALERT, PROTO_DIS_N1); | ||
474 | } | ||
475 | |||
476 | static void | ||
477 | l3_1tr6_setup_rsp(struct l3_process *pc, u_char pr, void *arg) | ||
478 | { | ||
479 | struct sk_buff *skb; | ||
480 | u_char tmp[24]; | ||
481 | u_char *p = tmp; | ||
482 | int l; | ||
483 | |||
484 | MsgHead(p, pc->callref, MT_N1_CONN, PROTO_DIS_N1); | ||
485 | if (pc->para.spv) { /* SPV ? */ | ||
486 | /* NSF SPV */ | ||
487 | *p++ = WE0_netSpecFac; | ||
488 | *p++ = 4; /* Laenge */ | ||
489 | *p++ = 0; | ||
490 | *p++ = FAC_SPV; /* SPV */ | ||
491 | *p++ = pc->para.setup.si1; | ||
492 | *p++ = pc->para.setup.si2; | ||
493 | *p++ = WE0_netSpecFac; | ||
494 | *p++ = 4; /* Laenge */ | ||
495 | *p++ = 0; | ||
496 | *p++ = FAC_Activate; /* aktiviere SPV */ | ||
497 | *p++ = pc->para.setup.si1; | ||
498 | *p++ = pc->para.setup.si2; | ||
499 | } | ||
500 | newl3state(pc, 8); | ||
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 | L3DelTimer(&pc->timer); | ||
507 | L3AddTimer(&pc->timer, T313, CC_T313); | ||
508 | } | ||
509 | |||
510 | static void | ||
511 | l3_1tr6_reset(struct l3_process *pc, u_char pr, void *arg) | ||
512 | { | ||
513 | release_l3_process(pc); | ||
514 | } | ||
515 | |||
516 | static void | ||
517 | l3_1tr6_disconnect_req(struct l3_process *pc, u_char pr, void *arg) | ||
518 | { | ||
519 | struct sk_buff *skb; | ||
520 | u_char tmp[16]; | ||
521 | u_char *p = tmp; | ||
522 | int l; | ||
523 | u_char cause = 0x10; | ||
524 | u_char clen = 1; | ||
525 | |||
526 | if (pc->para.cause > 0) | ||
527 | cause = pc->para.cause; | ||
528 | /* Map DSS1 causes */ | ||
529 | switch (cause & 0x7f) { | ||
530 | case 0x10: | ||
531 | clen = 0; | ||
532 | break; | ||
533 | case 0x11: | ||
534 | cause = CAUSE_UserBusy; | ||
535 | break; | ||
536 | case 0x15: | ||
537 | cause = CAUSE_CallRejected; | ||
538 | break; | ||
539 | } | ||
540 | StopAllL3Timer(pc); | ||
541 | MsgHead(p, pc->callref, MT_N1_DISC, PROTO_DIS_N1); | ||
542 | *p++ = WE0_cause; | ||
543 | *p++ = clen; /* Laenge */ | ||
544 | if (clen) | ||
545 | *p++ = cause | 0x80; | ||
546 | newl3state(pc, 11); | ||
547 | l = p - tmp; | ||
548 | if (!(skb = l3_alloc_skb(l))) | ||
549 | return; | ||
550 | memcpy(skb_put(skb, l), tmp, l); | ||
551 | l3_msg(pc->st, DL_DATA | REQUEST, skb); | ||
552 | L3AddTimer(&pc->timer, T305, CC_T305); | ||
553 | } | ||
554 | |||
555 | static void | ||
556 | l3_1tr6_t303(struct l3_process *pc, u_char pr, void *arg) | ||
557 | { | ||
558 | if (pc->N303 > 0) { | ||
559 | pc->N303--; | ||
560 | L3DelTimer(&pc->timer); | ||
561 | l3_1tr6_setup_req(pc, pr, arg); | ||
562 | } else { | ||
563 | L3DelTimer(&pc->timer); | ||
564 | pc->para.cause = 0; | ||
565 | l3_1tr6_disconnect_req(pc, 0, NULL); | ||
566 | } | ||
567 | } | ||
568 | |||
569 | static void | ||
570 | l3_1tr6_t304(struct l3_process *pc, u_char pr, void *arg) | ||
571 | { | ||
572 | L3DelTimer(&pc->timer); | ||
573 | pc->para.cause = 0xE6; | ||
574 | l3_1tr6_disconnect_req(pc, pr, NULL); | ||
575 | pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); | ||
576 | } | ||
577 | |||
578 | static void | ||
579 | l3_1tr6_t305(struct l3_process *pc, u_char pr, void *arg) | ||
580 | { | ||
581 | struct sk_buff *skb; | ||
582 | u_char tmp[16]; | ||
583 | u_char *p = tmp; | ||
584 | int l; | ||
585 | u_char cause = 0x90; | ||
586 | u_char clen = 1; | ||
587 | |||
588 | L3DelTimer(&pc->timer); | ||
589 | if (pc->para.cause != NO_CAUSE) | ||
590 | cause = pc->para.cause; | ||
591 | /* Map DSS1 causes */ | ||
592 | switch (cause & 0x7f) { | ||
593 | case 0x10: | ||
594 | clen = 0; | ||
595 | break; | ||
596 | case 0x15: | ||
597 | cause = CAUSE_CallRejected; | ||
598 | break; | ||
599 | } | ||
600 | MsgHead(p, pc->callref, MT_N1_REL, PROTO_DIS_N1); | ||
601 | *p++ = WE0_cause; | ||
602 | *p++ = clen; /* Laenge */ | ||
603 | if (clen) | ||
604 | *p++ = cause; | ||
605 | newl3state(pc, 19); | ||
606 | l = p - tmp; | ||
607 | if (!(skb = l3_alloc_skb(l))) | ||
608 | return; | ||
609 | memcpy(skb_put(skb, l), tmp, l); | ||
610 | l3_msg(pc->st, DL_DATA | REQUEST, skb); | ||
611 | L3AddTimer(&pc->timer, T308, CC_T308_1); | ||
612 | } | ||
613 | |||
614 | static void | ||
615 | l3_1tr6_t310(struct l3_process *pc, u_char pr, void *arg) | ||
616 | { | ||
617 | L3DelTimer(&pc->timer); | ||
618 | pc->para.cause = 0xE6; | ||
619 | l3_1tr6_disconnect_req(pc, pr, NULL); | ||
620 | pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); | ||
621 | } | ||
622 | |||
623 | static void | ||
624 | l3_1tr6_t313(struct l3_process *pc, u_char pr, void *arg) | ||
625 | { | ||
626 | L3DelTimer(&pc->timer); | ||
627 | pc->para.cause = 0xE6; | ||
628 | l3_1tr6_disconnect_req(pc, pr, NULL); | ||
629 | pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc); | ||
630 | } | ||
631 | |||
632 | static void | ||
633 | l3_1tr6_t308_1(struct l3_process *pc, u_char pr, void *arg) | ||
634 | { | ||
635 | L3DelTimer(&pc->timer); | ||
636 | l3_1TR6_message(pc, MT_N1_REL, PROTO_DIS_N1); | ||
637 | L3AddTimer(&pc->timer, T308, CC_T308_2); | ||
638 | newl3state(pc, 19); | ||
639 | } | ||
640 | |||
641 | static void | ||
642 | l3_1tr6_t308_2(struct l3_process *pc, u_char pr, void *arg) | ||
643 | { | ||
644 | L3DelTimer(&pc->timer); | ||
645 | pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc); | ||
646 | release_l3_process(pc); | ||
647 | } | ||
648 | |||
649 | static void | ||
650 | l3_1tr6_dl_reset(struct l3_process *pc, u_char pr, void *arg) | ||
651 | { | ||
652 | pc->para.cause = CAUSE_LocalProcErr; | ||
653 | l3_1tr6_disconnect_req(pc, pr, NULL); | ||
654 | pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc); | ||
655 | } | ||
656 | |||
657 | static void | ||
658 | l3_1tr6_dl_release(struct l3_process *pc, u_char pr, void *arg) | ||
659 | { | ||
660 | newl3state(pc, 0); | ||
661 | pc->para.cause = 0x1b; /* Destination out of order */ | ||
662 | pc->para.loc = 0; | ||
663 | pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc); | ||
664 | release_l3_process(pc); | ||
665 | } | ||
666 | |||
667 | /* *INDENT-OFF* */ | ||
668 | static struct stateentry downstl[] = | ||
669 | { | ||
670 | {SBIT(0), | ||
671 | CC_SETUP | REQUEST, l3_1tr6_setup_req}, | ||
672 | {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | | ||
673 | SBIT(10), | ||
674 | CC_DISCONNECT | REQUEST, l3_1tr6_disconnect_req}, | ||
675 | {SBIT(12), | ||
676 | CC_RELEASE | REQUEST, l3_1tr6_release_req}, | ||
677 | {SBIT(6), | ||
678 | CC_IGNORE | REQUEST, l3_1tr6_reset}, | ||
679 | {SBIT(6), | ||
680 | CC_REJECT | REQUEST, l3_1tr6_disconnect_req}, | ||
681 | {SBIT(6), | ||
682 | CC_ALERTING | REQUEST, l3_1tr6_alert_req}, | ||
683 | {SBIT(6) | SBIT(7), | ||
684 | CC_SETUP | RESPONSE, l3_1tr6_setup_rsp}, | ||
685 | {SBIT(1), | ||
686 | CC_T303, l3_1tr6_t303}, | ||
687 | {SBIT(2), | ||
688 | CC_T304, l3_1tr6_t304}, | ||
689 | {SBIT(3), | ||
690 | CC_T310, l3_1tr6_t310}, | ||
691 | {SBIT(8), | ||
692 | CC_T313, l3_1tr6_t313}, | ||
693 | {SBIT(11), | ||
694 | CC_T305, l3_1tr6_t305}, | ||
695 | {SBIT(19), | ||
696 | CC_T308_1, l3_1tr6_t308_1}, | ||
697 | {SBIT(19), | ||
698 | CC_T308_2, l3_1tr6_t308_2}, | ||
699 | }; | ||
700 | |||
701 | #define DOWNSTL_LEN \ | ||
702 | (sizeof(downstl) / sizeof(struct stateentry)) | ||
703 | |||
704 | static struct stateentry datastln1[] = | ||
705 | { | ||
706 | {SBIT(0), | ||
707 | MT_N1_INVALID, l3_1tr6_invalid}, | ||
708 | {SBIT(0), | ||
709 | MT_N1_SETUP, l3_1tr6_setup}, | ||
710 | {SBIT(1), | ||
711 | MT_N1_SETUP_ACK, l3_1tr6_setup_ack}, | ||
712 | {SBIT(1) | SBIT(2), | ||
713 | MT_N1_CALL_SENT, l3_1tr6_call_sent}, | ||
714 | {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10), | ||
715 | MT_N1_DISC, l3_1tr6_disc}, | ||
716 | {SBIT(2) | SBIT(3) | SBIT(4), | ||
717 | MT_N1_ALERT, l3_1tr6_alert}, | ||
718 | {SBIT(2) | SBIT(3) | SBIT(4), | ||
719 | MT_N1_CONN, l3_1tr6_connect}, | ||
720 | {SBIT(2), | ||
721 | MT_N1_INFO, l3_1tr6_info_s2}, | ||
722 | {SBIT(8), | ||
723 | MT_N1_CONN_ACK, l3_1tr6_connect_ack}, | ||
724 | {SBIT(10), | ||
725 | MT_N1_INFO, l3_1tr6_info}, | ||
726 | {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | | ||
727 | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17), | ||
728 | MT_N1_REL, l3_1tr6_rel}, | ||
729 | {SBIT(19), | ||
730 | MT_N1_REL, l3_1tr6_rel_ack}, | ||
731 | {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | | ||
732 | SBIT(10) | SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17), | ||
733 | MT_N1_REL_ACK, l3_1tr6_invalid}, | ||
734 | {SBIT(19), | ||
735 | MT_N1_REL_ACK, l3_1tr6_rel_ack} | ||
736 | }; | ||
737 | |||
738 | #define DATASTLN1_LEN \ | ||
739 | (sizeof(datastln1) / sizeof(struct stateentry)) | ||
740 | |||
741 | static struct stateentry manstatelist[] = | ||
742 | { | ||
743 | {SBIT(2), | ||
744 | DL_ESTABLISH | INDICATION, l3_1tr6_dl_reset}, | ||
745 | {ALL_STATES, | ||
746 | DL_RELEASE | INDICATION, l3_1tr6_dl_release}, | ||
747 | }; | ||
748 | |||
749 | #define MANSLLEN \ | ||
750 | (sizeof(manstatelist) / sizeof(struct stateentry)) | ||
751 | /* *INDENT-ON* */ | ||
752 | |||
753 | static void | ||
754 | up1tr6(struct PStack *st, int pr, void *arg) | ||
755 | { | ||
756 | int i, mt, cr; | ||
757 | struct l3_process *proc; | ||
758 | struct sk_buff *skb = arg; | ||
759 | char tmp[80]; | ||
760 | |||
761 | switch (pr) { | ||
762 | case (DL_DATA | INDICATION): | ||
763 | case (DL_UNIT_DATA | INDICATION): | ||
764 | break; | ||
765 | case (DL_ESTABLISH | CONFIRM): | ||
766 | case (DL_ESTABLISH | INDICATION): | ||
767 | case (DL_RELEASE | INDICATION): | ||
768 | case (DL_RELEASE | CONFIRM): | ||
769 | l3_msg(st, pr, arg); | ||
770 | return; | ||
771 | break; | ||
772 | } | ||
773 | if (skb->len < 4) { | ||
774 | if (st->l3.debug & L3_DEB_PROTERR) { | ||
775 | sprintf(tmp, "up1tr6 len only %d", skb->len); | ||
776 | l3_debug(st, tmp); | ||
777 | } | ||
778 | dev_kfree_skb(skb); | ||
779 | return; | ||
780 | } | ||
781 | if ((skb->data[0] & 0xfe) != PROTO_DIS_N0) { | ||
782 | if (st->l3.debug & L3_DEB_PROTERR) { | ||
783 | sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d", | ||
784 | (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", | ||
785 | skb->data[0], skb->len); | ||
786 | l3_debug(st, tmp); | ||
787 | } | ||
788 | dev_kfree_skb(skb); | ||
789 | return; | ||
790 | } | ||
791 | if (skb->data[1] != 1) { | ||
792 | if (st->l3.debug & L3_DEB_PROTERR) { | ||
793 | sprintf(tmp, "up1tr6 CR len not 1"); | ||
794 | l3_debug(st, tmp); | ||
795 | } | ||
796 | dev_kfree_skb(skb); | ||
797 | return; | ||
798 | } | ||
799 | cr = skb->data[2]; | ||
800 | mt = skb->data[3]; | ||
801 | if (skb->data[0] == PROTO_DIS_N0) { | ||
802 | dev_kfree_skb(skb); | ||
803 | if (st->l3.debug & L3_DEB_STATE) { | ||
804 | sprintf(tmp, "up1tr6%s N0 mt %x unhandled", | ||
805 | (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", mt); | ||
806 | l3_debug(st, tmp); | ||
807 | } | ||
808 | } else if (skb->data[0] == PROTO_DIS_N1) { | ||
809 | if (!(proc = getl3proc(st, cr))) { | ||
810 | if (mt == MT_N1_SETUP) { | ||
811 | if (cr < 128) { | ||
812 | if (!(proc = new_l3_process(st, cr))) { | ||
813 | if (st->l3.debug & L3_DEB_PROTERR) { | ||
814 | sprintf(tmp, "up1tr6 no roc mem"); | ||
815 | l3_debug(st, tmp); | ||
816 | } | ||
817 | dev_kfree_skb(skb); | ||
818 | return; | ||
819 | } | ||
820 | } else { | ||
821 | dev_kfree_skb(skb); | ||
822 | return; | ||
823 | } | ||
824 | } else if ((mt == MT_N1_REL) || (mt == MT_N1_REL_ACK) || | ||
825 | (mt == MT_N1_CANC_ACK) || (mt == MT_N1_CANC_REJ) || | ||
826 | (mt == MT_N1_REG_ACK) || (mt == MT_N1_REG_REJ) || | ||
827 | (mt == MT_N1_SUSP_ACK) || (mt == MT_N1_RES_REJ) || | ||
828 | (mt == MT_N1_INFO)) { | ||
829 | dev_kfree_skb(skb); | ||
830 | return; | ||
831 | } else { | ||
832 | if (!(proc = new_l3_process(st, cr))) { | ||
833 | if (st->l3.debug & L3_DEB_PROTERR) { | ||
834 | sprintf(tmp, "up1tr6 no roc mem"); | ||
835 | l3_debug(st, tmp); | ||
836 | } | ||
837 | dev_kfree_skb(skb); | ||
838 | return; | ||
839 | } | ||
840 | mt = MT_N1_INVALID; | ||
841 | } | ||
842 | } | ||
843 | for (i = 0; i < DATASTLN1_LEN; i++) | ||
844 | if ((mt == datastln1[i].primitive) && | ||
845 | ((1 << proc->state) & datastln1[i].state)) | ||
846 | break; | ||
847 | if (i == DATASTLN1_LEN) { | ||
848 | dev_kfree_skb(skb); | ||
849 | if (st->l3.debug & L3_DEB_STATE) { | ||
850 | sprintf(tmp, "up1tr6%sstate %d mt %x unhandled", | ||
851 | (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", | ||
852 | proc->state, mt); | ||
853 | l3_debug(st, tmp); | ||
854 | } | ||
855 | return; | ||
856 | } else { | ||
857 | if (st->l3.debug & L3_DEB_STATE) { | ||
858 | sprintf(tmp, "up1tr6%sstate %d mt %x", | ||
859 | (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ", | ||
860 | proc->state, mt); | ||
861 | l3_debug(st, tmp); | ||
862 | } | ||
863 | datastln1[i].rout(proc, pr, skb); | ||
864 | } | ||
865 | } | ||
866 | } | ||
867 | |||
868 | static void | ||
869 | down1tr6(struct PStack *st, int pr, void *arg) | ||
870 | { | ||
871 | int i, cr; | ||
872 | struct l3_process *proc; | ||
873 | struct Channel *chan; | ||
874 | char tmp[80]; | ||
875 | |||
876 | if ((DL_ESTABLISH | REQUEST)== pr) { | ||
877 | l3_msg(st, pr, NULL); | ||
878 | return; | ||
879 | } else if ((CC_SETUP | REQUEST) == pr) { | ||
880 | chan = arg; | ||
881 | cr = newcallref(); | ||
882 | cr |= 0x80; | ||
883 | if (!(proc = new_l3_process(st, cr))) { | ||
884 | return; | ||
885 | } else { | ||
886 | proc->chan = chan; | ||
887 | chan->proc = proc; | ||
888 | memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm)); | ||
889 | proc->callref = cr; | ||
890 | } | ||
891 | } else { | ||
892 | proc = arg; | ||
893 | } | ||
894 | |||
895 | for (i = 0; i < DOWNSTL_LEN; i++) | ||
896 | if ((pr == downstl[i].primitive) && | ||
897 | ((1 << proc->state) & downstl[i].state)) | ||
898 | break; | ||
899 | if (i == DOWNSTL_LEN) { | ||
900 | if (st->l3.debug & L3_DEB_STATE) { | ||
901 | sprintf(tmp, "down1tr6 state %d prim %d unhandled", | ||
902 | proc->state, pr); | ||
903 | l3_debug(st, tmp); | ||
904 | } | ||
905 | } else { | ||
906 | if (st->l3.debug & L3_DEB_STATE) { | ||
907 | sprintf(tmp, "down1tr6 state %d prim %d", | ||
908 | proc->state, pr); | ||
909 | l3_debug(st, tmp); | ||
910 | } | ||
911 | downstl[i].rout(proc, pr, arg); | ||
912 | } | ||
913 | } | ||
914 | |||
915 | static void | ||
916 | man1tr6(struct PStack *st, int pr, void *arg) | ||
917 | { | ||
918 | int i; | ||
919 | struct l3_process *proc = arg; | ||
920 | |||
921 | if (!proc) { | ||
922 | printk(KERN_ERR "HiSax man1tr6 without proc pr=%04x\n", pr); | ||
923 | return; | ||
924 | } | ||
925 | for (i = 0; i < MANSLLEN; i++) | ||
926 | if ((pr == manstatelist[i].primitive) && | ||
927 | ((1 << proc->state) & manstatelist[i].state)) | ||
928 | break; | ||
929 | if (i == MANSLLEN) { | ||
930 | if (st->l3.debug & L3_DEB_STATE) { | ||
931 | l3_debug(st, "cr %d man1tr6 state %d prim %d unhandled", | ||
932 | proc->callref & 0x7f, proc->state, pr); | ||
933 | } | ||
934 | } else { | ||
935 | if (st->l3.debug & L3_DEB_STATE) { | ||
936 | l3_debug(st, "cr %d man1tr6 state %d prim %d", | ||
937 | proc->callref & 0x7f, proc->state, pr); | ||
938 | } | ||
939 | manstatelist[i].rout(proc, pr, arg); | ||
940 | } | ||
941 | } | ||
942 | |||
943 | void | ||
944 | setstack_1tr6(struct PStack *st) | ||
945 | { | ||
946 | char tmp[64]; | ||
947 | |||
948 | st->lli.l4l3 = down1tr6; | ||
949 | st->l2.l2l3 = up1tr6; | ||
950 | st->l3.l3ml3 = man1tr6; | ||
951 | st->l3.N303 = 0; | ||
952 | |||
953 | strcpy(tmp, l3_1tr6_revision); | ||
954 | printk(KERN_INFO "HiSax: 1TR6 Rev. %s\n", HiSax_getrev(tmp)); | ||
955 | } | ||