isdn_divert.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. /* $Id: isdn_divert.c,v 1.6.6.3 2001/09/23 22:24:36 kai Exp $
  2. *
  3. * DSS1 main diversion supplementary handling for i4l.
  4. *
  5. * Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
  6. *
  7. * This software may be used and distributed according to the terms
  8. * of the GNU General Public License, incorporated herein by reference.
  9. *
  10. */
  11. #include <linux/proc_fs.h>
  12. #include "isdn_divert.h"
  13. /**********************************/
  14. /* structure keeping calling info */
  15. /**********************************/
  16. struct call_struc
  17. { isdn_ctrl ics; /* delivered setup + driver parameters */
  18. ulong divert_id; /* Id delivered to user */
  19. unsigned char akt_state; /* actual state */
  20. char deflect_dest[35]; /* deflection destination */
  21. struct timer_list timer; /* timer control structure */
  22. char info[90]; /* device info output */
  23. struct call_struc *next; /* pointer to next entry */
  24. struct call_struc *prev;
  25. };
  26. /********************************************/
  27. /* structure keeping deflection table entry */
  28. /********************************************/
  29. struct deflect_struc
  30. { struct deflect_struc *next,*prev;
  31. divert_rule rule; /* used rule */
  32. };
  33. /*****************************************/
  34. /* variables for main diversion services */
  35. /*****************************************/
  36. /* diversion/deflection processes */
  37. static struct call_struc *divert_head = NULL; /* head of remembered entrys */
  38. static ulong next_id = 1; /* next info id */
  39. static struct deflect_struc *table_head = NULL;
  40. static struct deflect_struc *table_tail = NULL;
  41. static unsigned char extern_wait_max = 4; /* maximum wait in s for external process */
  42. DEFINE_SPINLOCK(divert_lock);
  43. /***************************/
  44. /* timer callback function */
  45. /***************************/
  46. static void deflect_timer_expire(ulong arg)
  47. {
  48. unsigned long flags;
  49. struct call_struc *cs = (struct call_struc *) arg;
  50. spin_lock_irqsave(&divert_lock, flags);
  51. del_timer(&cs->timer); /* delete active timer */
  52. spin_unlock_irqrestore(&divert_lock, flags);
  53. switch(cs->akt_state)
  54. { case DEFLECT_PROCEED:
  55. cs->ics.command = ISDN_CMD_HANGUP; /* cancel action */
  56. divert_if.ll_cmd(&cs->ics);
  57. spin_lock_irqsave(&divert_lock, flags);
  58. cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
  59. cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
  60. add_timer(&cs->timer);
  61. spin_unlock_irqrestore(&divert_lock, flags);
  62. break;
  63. case DEFLECT_ALERT:
  64. cs->ics.command = ISDN_CMD_REDIR; /* protocol */
  65. strcpy(cs->ics.parm.setup.phone,cs->deflect_dest);
  66. strcpy(cs->ics.parm.setup.eazmsn,"Testtext delayed");
  67. divert_if.ll_cmd(&cs->ics);
  68. spin_lock_irqsave(&divert_lock, flags);
  69. cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
  70. cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
  71. add_timer(&cs->timer);
  72. spin_unlock_irqrestore(&divert_lock, flags);
  73. break;
  74. case DEFLECT_AUTODEL:
  75. default:
  76. spin_lock_irqsave(&divert_lock, flags);
  77. if (cs->prev)
  78. cs->prev->next = cs->next; /* forward link */
  79. else
  80. divert_head = cs->next;
  81. if (cs->next)
  82. cs->next->prev = cs->prev; /* back link */
  83. spin_unlock_irqrestore(&divert_lock, flags);
  84. kfree(cs);
  85. return;
  86. } /* switch */
  87. } /* deflect_timer_func */
  88. /*****************************************/
  89. /* handle call forwarding de/activations */
  90. /* 0 = deact, 1 = act, 2 = interrogate */
  91. /*****************************************/
  92. int cf_command(int drvid, int mode,
  93. u_char proc, char *msn,
  94. u_char service, char *fwd_nr, ulong *procid)
  95. { unsigned long flags;
  96. int retval,msnlen;
  97. int fwd_len;
  98. char *p,*ielenp,tmp[60];
  99. struct call_struc *cs;
  100. if (strchr(msn,'.')) return(-EINVAL); /* subaddress not allowed in msn */
  101. if ((proc & 0x7F) > 2) return(-EINVAL);
  102. proc &= 3;
  103. p = tmp;
  104. *p++ = 0x30; /* enumeration */
  105. ielenp = p++; /* remember total length position */
  106. *p++ = 0xa; /* proc tag */
  107. *p++ = 1; /* length */
  108. *p++ = proc & 0x7F; /* procedure to de/activate/interrogate */
  109. *p++ = 0xa; /* service tag */
  110. *p++ = 1; /* length */
  111. *p++ = service; /* service to handle */
  112. if (mode == 1)
  113. { if (!*fwd_nr) return(-EINVAL); /* destination missing */
  114. if (strchr(fwd_nr,'.')) return(-EINVAL); /* subaddress not allowed */
  115. fwd_len = strlen(fwd_nr);
  116. *p++ = 0x30; /* number enumeration */
  117. *p++ = fwd_len + 2; /* complete forward to len */
  118. *p++ = 0x80; /* fwd to nr */
  119. *p++ = fwd_len; /* length of number */
  120. strcpy(p,fwd_nr); /* copy number */
  121. p += fwd_len; /* pointer beyond fwd */
  122. } /* activate */
  123. msnlen = strlen(msn);
  124. *p++ = 0x80; /* msn number */
  125. if (msnlen > 1)
  126. { *p++ = msnlen; /* length */
  127. strcpy(p,msn);
  128. p += msnlen;
  129. }
  130. else *p++ = 0;
  131. *ielenp = p - ielenp - 1; /* set total IE length */
  132. /* allocate mem for information struct */
  133. if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
  134. return(-ENOMEM); /* no memory */
  135. init_timer(&cs->timer);
  136. cs->info[0] = '\0';
  137. cs->timer.function = deflect_timer_expire;
  138. cs->timer.data = (ulong) cs; /* pointer to own structure */
  139. cs->ics.driver = drvid;
  140. cs->ics.command = ISDN_CMD_PROT_IO; /* protocol specific io */
  141. cs->ics.arg = DSS1_CMD_INVOKE; /* invoke supplementary service */
  142. cs->ics.parm.dss1_io.proc = (mode == 1) ? 7: (mode == 2) ? 11:8; /* operation */
  143. cs->ics.parm.dss1_io.timeout = 4000; /* from ETS 300 207-1 */
  144. cs->ics.parm.dss1_io.datalen = p - tmp; /* total len */
  145. cs->ics.parm.dss1_io.data = tmp; /* start of buffer */
  146. spin_lock_irqsave(&divert_lock, flags);
  147. cs->ics.parm.dss1_io.ll_id = next_id++; /* id for callback */
  148. spin_unlock_irqrestore(&divert_lock, flags);
  149. *procid = cs->ics.parm.dss1_io.ll_id;
  150. sprintf(cs->info,"%d 0x%lx %s%s 0 %s %02x %d%s%s\n",
  151. (!mode ) ? DIVERT_DEACTIVATE : (mode == 1) ? DIVERT_ACTIVATE : DIVERT_REPORT,
  152. cs->ics.parm.dss1_io.ll_id,
  153. (mode != 2) ? "" : "0 ",
  154. divert_if.drv_to_name(cs->ics.driver),
  155. msn,
  156. service & 0xFF,
  157. proc,
  158. (mode != 1) ? "" : " 0 ",
  159. (mode != 1) ? "" : fwd_nr);
  160. retval = divert_if.ll_cmd(&cs->ics); /* excute command */
  161. if (!retval)
  162. { cs->prev = NULL;
  163. spin_lock_irqsave(&divert_lock, flags);
  164. cs->next = divert_head;
  165. divert_head = cs;
  166. spin_unlock_irqrestore(&divert_lock, flags);
  167. }
  168. else
  169. kfree(cs);
  170. return(retval);
  171. } /* cf_command */
  172. /****************************************/
  173. /* handle a external deflection command */
  174. /****************************************/
  175. int deflect_extern_action(u_char cmd, ulong callid, char *to_nr)
  176. { struct call_struc *cs;
  177. isdn_ctrl ic;
  178. unsigned long flags;
  179. int i;
  180. if ((cmd & 0x7F) > 2) return(-EINVAL); /* invalid command */
  181. cs = divert_head; /* start of parameter list */
  182. while (cs)
  183. { if (cs->divert_id == callid) break; /* found */
  184. cs = cs->next;
  185. } /* search entry */
  186. if (!cs) return(-EINVAL); /* invalid callid */
  187. ic.driver = cs->ics.driver;
  188. ic.arg = cs->ics.arg;
  189. i = -EINVAL;
  190. if (cs->akt_state == DEFLECT_AUTODEL) return(i); /* no valid call */
  191. switch (cmd & 0x7F)
  192. { case 0: /* hangup */
  193. del_timer(&cs->timer);
  194. ic.command = ISDN_CMD_HANGUP;
  195. i = divert_if.ll_cmd(&ic);
  196. spin_lock_irqsave(&divert_lock, flags);
  197. cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
  198. cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
  199. add_timer(&cs->timer);
  200. spin_unlock_irqrestore(&divert_lock, flags);
  201. break;
  202. case 1: /* alert */
  203. if (cs->akt_state == DEFLECT_ALERT) return(0);
  204. cmd &= 0x7F; /* never wait */
  205. del_timer(&cs->timer);
  206. ic.command = ISDN_CMD_ALERT;
  207. if ((i = divert_if.ll_cmd(&ic)))
  208. {
  209. spin_lock_irqsave(&divert_lock, flags);
  210. cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
  211. cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
  212. add_timer(&cs->timer);
  213. spin_unlock_irqrestore(&divert_lock, flags);
  214. }
  215. else
  216. cs->akt_state = DEFLECT_ALERT;
  217. break;
  218. case 2: /* redir */
  219. del_timer(&cs->timer);
  220. strcpy(cs->ics.parm.setup.phone, to_nr);
  221. strcpy(cs->ics.parm.setup.eazmsn, "Testtext manual");
  222. ic.command = ISDN_CMD_REDIR;
  223. if ((i = divert_if.ll_cmd(&ic)))
  224. {
  225. spin_lock_irqsave(&divert_lock, flags);
  226. cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
  227. cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
  228. add_timer(&cs->timer);
  229. spin_unlock_irqrestore(&divert_lock, flags);
  230. }
  231. else
  232. cs->akt_state = DEFLECT_ALERT;
  233. break;
  234. } /* switch */
  235. return(i);
  236. } /* deflect_extern_action */
  237. /********************************/
  238. /* insert a new rule before idx */
  239. /********************************/
  240. int insertrule(int idx, divert_rule *newrule)
  241. { struct deflect_struc *ds,*ds1=NULL;
  242. unsigned long flags;
  243. if (!(ds = (struct deflect_struc *) kmalloc(sizeof(struct deflect_struc),
  244. GFP_KERNEL)))
  245. return(-ENOMEM); /* no memory */
  246. ds->rule = *newrule; /* set rule */
  247. spin_lock_irqsave(&divert_lock, flags);
  248. if (idx >= 0)
  249. { ds1 = table_head;
  250. while ((ds1) && (idx > 0))
  251. { idx--;
  252. ds1 = ds1->next;
  253. }
  254. if (!ds1) idx = -1;
  255. }
  256. if (idx < 0)
  257. { ds->prev = table_tail; /* previous entry */
  258. ds->next = NULL; /* end of chain */
  259. if (ds->prev)
  260. ds->prev->next = ds; /* last forward */
  261. else
  262. table_head = ds; /* is first entry */
  263. table_tail = ds; /* end of queue */
  264. }
  265. else
  266. { ds->next = ds1; /* next entry */
  267. ds->prev = ds1->prev; /* prev entry */
  268. ds1->prev = ds; /* backward chain old element */
  269. if (!ds->prev)
  270. table_head = ds; /* first element */
  271. }
  272. spin_unlock_irqrestore(&divert_lock, flags);
  273. return(0);
  274. } /* insertrule */
  275. /***********************************/
  276. /* delete the rule at position idx */
  277. /***********************************/
  278. int deleterule(int idx)
  279. { struct deflect_struc *ds,*ds1;
  280. unsigned long flags;
  281. if (idx < 0)
  282. { spin_lock_irqsave(&divert_lock, flags);
  283. ds = table_head;
  284. table_head = NULL;
  285. table_tail = NULL;
  286. spin_unlock_irqrestore(&divert_lock, flags);
  287. while (ds)
  288. { ds1 = ds;
  289. ds = ds->next;
  290. kfree(ds1);
  291. }
  292. return(0);
  293. }
  294. spin_lock_irqsave(&divert_lock, flags);
  295. ds = table_head;
  296. while ((ds) && (idx > 0))
  297. { idx--;
  298. ds = ds->next;
  299. }
  300. if (!ds)
  301. {
  302. spin_unlock_irqrestore(&divert_lock, flags);
  303. return(-EINVAL);
  304. }
  305. if (ds->next)
  306. ds->next->prev = ds->prev; /* backward chain */
  307. else
  308. table_tail = ds->prev; /* end of chain */
  309. if (ds->prev)
  310. ds->prev->next = ds->next; /* forward chain */
  311. else
  312. table_head = ds->next; /* start of chain */
  313. spin_unlock_irqrestore(&divert_lock, flags);
  314. kfree(ds);
  315. return(0);
  316. } /* deleterule */
  317. /*******************************************/
  318. /* get a pointer to a specific rule number */
  319. /*******************************************/
  320. divert_rule *getruleptr(int idx)
  321. { struct deflect_struc *ds = table_head;
  322. if (idx < 0) return(NULL);
  323. while ((ds) && (idx >= 0))
  324. { if (!(idx--))
  325. { return(&ds->rule);
  326. break;
  327. }
  328. ds = ds->next;
  329. }
  330. return(NULL);
  331. } /* getruleptr */
  332. /*************************************************/
  333. /* called from common module on an incoming call */
  334. /*************************************************/
  335. static int isdn_divert_icall(isdn_ctrl *ic)
  336. { int retval = 0;
  337. unsigned long flags;
  338. struct call_struc *cs = NULL;
  339. struct deflect_struc *dv;
  340. char *p,*p1;
  341. u_char accept;
  342. /* first check the internal deflection table */
  343. for (dv = table_head; dv ; dv = dv->next )
  344. { /* scan table */
  345. if (((dv->rule.callopt == 1) && (ic->command == ISDN_STAT_ICALLW)) ||
  346. ((dv->rule.callopt == 2) && (ic->command == ISDN_STAT_ICALL)))
  347. continue; /* call option check */
  348. if (!(dv->rule.drvid & (1L << ic->driver)))
  349. continue; /* driver not matching */
  350. if ((dv->rule.si1) && (dv->rule.si1 != ic->parm.setup.si1))
  351. continue; /* si1 not matching */
  352. if ((dv->rule.si2) && (dv->rule.si2 != ic->parm.setup.si2))
  353. continue; /* si2 not matching */
  354. p = dv->rule.my_msn;
  355. p1 = ic->parm.setup.eazmsn;
  356. accept = 0;
  357. while (*p)
  358. { /* complete compare */
  359. if (*p == '-')
  360. { accept = 1; /* call accepted */
  361. break;
  362. }
  363. if (*p++ != *p1++)
  364. break; /* not accepted */
  365. if ((!*p) && (!*p1))
  366. accept = 1;
  367. } /* complete compare */
  368. if (!accept) continue; /* not accepted */
  369. if ((strcmp(dv->rule.caller,"0")) || (ic->parm.setup.phone[0]))
  370. { p = dv->rule.caller;
  371. p1 = ic->parm.setup.phone;
  372. accept = 0;
  373. while (*p)
  374. { /* complete compare */
  375. if (*p == '-')
  376. { accept = 1; /* call accepted */
  377. break;
  378. }
  379. if (*p++ != *p1++)
  380. break; /* not accepted */
  381. if ((!*p) && (!*p1))
  382. accept = 1;
  383. } /* complete compare */
  384. if (!accept) continue; /* not accepted */
  385. }
  386. switch (dv->rule.action)
  387. { case DEFLECT_IGNORE:
  388. return(0);
  389. break;
  390. case DEFLECT_ALERT:
  391. case DEFLECT_PROCEED:
  392. case DEFLECT_REPORT:
  393. case DEFLECT_REJECT:
  394. if (dv->rule.action == DEFLECT_PROCEED)
  395. if ((!if_used) || ((!extern_wait_max) && (!dv->rule.waittime)))
  396. return(0); /* no external deflection needed */
  397. if (!(cs = (struct call_struc *) kmalloc(sizeof(struct call_struc), GFP_ATOMIC)))
  398. return(0); /* no memory */
  399. init_timer(&cs->timer);
  400. cs->info[0] = '\0';
  401. cs->timer.function = deflect_timer_expire;
  402. cs->timer.data = (ulong) cs; /* pointer to own structure */
  403. cs->ics = *ic; /* copy incoming data */
  404. if (!cs->ics.parm.setup.phone[0]) strcpy(cs->ics.parm.setup.phone,"0");
  405. if (!cs->ics.parm.setup.eazmsn[0]) strcpy(cs->ics.parm.setup.eazmsn,"0");
  406. cs->ics.parm.setup.screen = dv->rule.screen;
  407. if (dv->rule.waittime)
  408. cs->timer.expires = jiffies + (HZ * dv->rule.waittime);
  409. else
  410. if (dv->rule.action == DEFLECT_PROCEED)
  411. cs->timer.expires = jiffies + (HZ * extern_wait_max);
  412. else
  413. cs->timer.expires = 0;
  414. cs->akt_state = dv->rule.action;
  415. spin_lock_irqsave(&divert_lock, flags);
  416. cs->divert_id = next_id++; /* new sequence number */
  417. spin_unlock_irqrestore(&divert_lock, flags);
  418. cs->prev = NULL;
  419. if (cs->akt_state == DEFLECT_ALERT)
  420. { strcpy(cs->deflect_dest,dv->rule.to_nr);
  421. if (!cs->timer.expires)
  422. { strcpy(ic->parm.setup.eazmsn,"Testtext direct");
  423. ic->parm.setup.screen = dv->rule.screen;
  424. strcpy(ic->parm.setup.phone,dv->rule.to_nr);
  425. cs->akt_state = DEFLECT_AUTODEL; /* delete after timeout */
  426. cs->timer.expires = jiffies + (HZ * AUTODEL_TIME);
  427. retval = 5;
  428. }
  429. else
  430. retval = 1; /* alerting */
  431. }
  432. else
  433. { cs->deflect_dest[0] = '\0';
  434. retval = 4; /* only proceed */
  435. }
  436. sprintf(cs->info,"%d 0x%lx %s %s %s %s 0x%x 0x%x %d %d %s\n",
  437. cs->akt_state,
  438. cs->divert_id,
  439. divert_if.drv_to_name(cs->ics.driver),
  440. (ic->command == ISDN_STAT_ICALLW) ? "1":"0",
  441. cs->ics.parm.setup.phone,
  442. cs->ics.parm.setup.eazmsn,
  443. cs->ics.parm.setup.si1,
  444. cs->ics.parm.setup.si2,
  445. cs->ics.parm.setup.screen,
  446. dv->rule.waittime,
  447. cs->deflect_dest);
  448. if ((dv->rule.action == DEFLECT_REPORT) ||
  449. (dv->rule.action == DEFLECT_REJECT))
  450. { put_info_buffer(cs->info);
  451. kfree(cs); /* remove */
  452. return((dv->rule.action == DEFLECT_REPORT) ? 0:2); /* nothing to do */
  453. }
  454. break;
  455. default:
  456. return(0); /* ignore call */
  457. break;
  458. } /* switch action */
  459. break;
  460. } /* scan_table */
  461. if (cs)
  462. { cs->prev = NULL;
  463. spin_lock_irqsave(&divert_lock, flags);
  464. cs->next = divert_head;
  465. divert_head = cs;
  466. if (cs->timer.expires) add_timer(&cs->timer);
  467. spin_unlock_irqrestore(&divert_lock, flags);
  468. put_info_buffer(cs->info);
  469. return(retval);
  470. }
  471. else
  472. return(0);
  473. } /* isdn_divert_icall */
  474. void deleteprocs(void)
  475. { struct call_struc *cs, *cs1;
  476. unsigned long flags;
  477. spin_lock_irqsave(&divert_lock, flags);
  478. cs = divert_head;
  479. divert_head = NULL;
  480. while (cs)
  481. { del_timer(&cs->timer);
  482. cs1 = cs;
  483. cs = cs->next;
  484. kfree(cs1);
  485. }
  486. spin_unlock_irqrestore(&divert_lock, flags);
  487. } /* deleteprocs */
  488. /****************************************************/
  489. /* put a address including address type into buffer */
  490. /****************************************************/
  491. static int put_address(char *st, u_char *p, int len)
  492. { u_char retval = 0;
  493. u_char adr_typ = 0; /* network standard */
  494. if (len < 2) return(retval);
  495. if (*p == 0xA1)
  496. { retval = *(++p) + 2; /* total length */
  497. if (retval > len) return(0); /* too short */
  498. len = retval - 2; /* remaining length */
  499. if (len < 3) return(0);
  500. if ((*(++p) != 0x0A) || (*(++p) != 1)) return(0);
  501. adr_typ = *(++p);
  502. len -= 3;
  503. p++;
  504. if (len < 2) return(0);
  505. if (*p++ != 0x12) return(0);
  506. if (*p > len) return(0); /* check number length */
  507. len = *p++;
  508. }
  509. else
  510. if (*p == 0x80)
  511. { retval = *(++p) + 2; /* total length */
  512. if (retval > len) return(0);
  513. len = retval - 2;
  514. p++;
  515. }
  516. else
  517. return(0); /* invalid address information */
  518. sprintf(st,"%d ",adr_typ);
  519. st += strlen(st);
  520. if (!len)
  521. *st++ = '-';
  522. else
  523. while (len--)
  524. *st++ = *p++;
  525. *st = '\0';
  526. return(retval);
  527. } /* put_address */
  528. /*************************************/
  529. /* report a successful interrogation */
  530. /*************************************/
  531. static int interrogate_success(isdn_ctrl *ic, struct call_struc *cs)
  532. { char *src = ic->parm.dss1_io.data;
  533. int restlen = ic->parm.dss1_io.datalen;
  534. int cnt = 1;
  535. u_char n,n1;
  536. char st[90], *p, *stp;
  537. if (restlen < 2) return(-100); /* frame too short */
  538. if (*src++ != 0x30) return(-101);
  539. if ((n = *src++) > 0x81) return(-102); /* invalid length field */
  540. restlen -= 2; /* remaining bytes */
  541. if (n == 0x80)
  542. { if (restlen < 2) return(-103);
  543. if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-104);
  544. restlen -= 2;
  545. }
  546. else
  547. if ( n == 0x81)
  548. { n = *src++;
  549. restlen--;
  550. if (n > restlen) return(-105);
  551. restlen = n;
  552. }
  553. else
  554. if (n > restlen) return(-106);
  555. else
  556. restlen = n; /* standard format */
  557. if (restlen < 3) return(-107); /* no procedure */
  558. if ((*src++ != 2) || (*src++ != 1) || (*src++ != 0x0B)) return(-108);
  559. restlen -= 3;
  560. if (restlen < 2) return(-109); /* list missing */
  561. if (*src == 0x31)
  562. { src++;
  563. if ((n = *src++) > 0x81) return(-110); /* invalid length field */
  564. restlen -= 2; /* remaining bytes */
  565. if (n == 0x80)
  566. { if (restlen < 2) return(-111);
  567. if ((*(src+restlen-1)) || (*(src+restlen-2))) return(-112);
  568. restlen -= 2;
  569. }
  570. else
  571. if ( n == 0x81)
  572. { n = *src++;
  573. restlen--;
  574. if (n > restlen) return(-113);
  575. restlen = n;
  576. }
  577. else
  578. if (n > restlen) return(-114);
  579. else
  580. restlen = n; /* standard format */
  581. } /* result list header */
  582. while (restlen >= 2)
  583. { stp = st;
  584. sprintf(stp,"%d 0x%lx %d %s ",DIVERT_REPORT, ic->parm.dss1_io.ll_id,
  585. cnt++,divert_if.drv_to_name(ic->driver));
  586. stp += strlen(stp);
  587. if (*src++ != 0x30) return(-115); /* invalid enum */
  588. n = *src++;
  589. restlen -= 2;
  590. if (n > restlen) return(-116); /* enum length wrong */
  591. restlen -= n;
  592. p = src; /* one entry */
  593. src += n;
  594. if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
  595. stp += strlen(stp);
  596. p += n1;
  597. n -= n1;
  598. if (n < 6) continue; /* no service and proc */
  599. if ((*p++ != 0x0A) || (*p++ != 1)) continue;
  600. sprintf(stp," 0x%02x ",(*p++) & 0xFF);
  601. stp += strlen(stp);
  602. if ((*p++ != 0x0A) || (*p++ != 1)) continue;
  603. sprintf(stp,"%d ",(*p++) & 0xFF);
  604. stp += strlen(stp);
  605. n -= 6;
  606. if (n > 2)
  607. { if (*p++ != 0x30) continue;
  608. if (*p > (n-2)) continue;
  609. n = *p++;
  610. if (!(n1 = put_address(stp,p,n & 0xFF))) continue;
  611. stp += strlen(stp);
  612. }
  613. sprintf(stp,"\n");
  614. put_info_buffer(st);
  615. } /* while restlen */
  616. if (restlen) return(-117);
  617. return(0);
  618. } /* interrogate_success */
  619. /*********************************************/
  620. /* callback for protocol specific extensions */
  621. /*********************************************/
  622. static int prot_stat_callback(isdn_ctrl *ic)
  623. { struct call_struc *cs, *cs1;
  624. int i;
  625. unsigned long flags;
  626. cs = divert_head; /* start of list */
  627. cs1 = NULL;
  628. while (cs)
  629. { if (ic->driver == cs->ics.driver)
  630. { switch (cs->ics.arg)
  631. { case DSS1_CMD_INVOKE:
  632. if ((cs->ics.parm.dss1_io.ll_id == ic->parm.dss1_io.ll_id) &&
  633. (cs->ics.parm.dss1_io.hl_id == ic->parm.dss1_io.hl_id))
  634. { switch (ic->arg)
  635. { case DSS1_STAT_INVOKE_ERR:
  636. sprintf(cs->info,"128 0x%lx 0x%x\n",
  637. ic->parm.dss1_io.ll_id,
  638. ic->parm.dss1_io.timeout);
  639. put_info_buffer(cs->info);
  640. break;
  641. case DSS1_STAT_INVOKE_RES:
  642. switch (cs->ics.parm.dss1_io.proc)
  643. { case 7:
  644. case 8:
  645. put_info_buffer(cs->info);
  646. break;
  647. case 11:
  648. i = interrogate_success(ic,cs);
  649. if (i)
  650. sprintf(cs->info,"%d 0x%lx %d\n",DIVERT_REPORT,
  651. ic->parm.dss1_io.ll_id,i);
  652. put_info_buffer(cs->info);
  653. break;
  654. default:
  655. printk(KERN_WARNING "dss1_divert: unknown proc %d\n",cs->ics.parm.dss1_io.proc);
  656. break;
  657. }
  658. break;
  659. default:
  660. printk(KERN_WARNING "dss1_divert unknown invoke answer %lx\n",ic->arg);
  661. break;
  662. }
  663. cs1 = cs; /* remember structure */
  664. cs = NULL;
  665. continue; /* abort search */
  666. } /* id found */
  667. break;
  668. case DSS1_CMD_INVOKE_ABORT:
  669. printk(KERN_WARNING "dss1_divert unhandled invoke abort\n");
  670. break;
  671. default:
  672. printk(KERN_WARNING "dss1_divert unknown cmd 0x%lx\n",cs->ics.arg);
  673. break;
  674. } /* switch ics.arg */
  675. cs = cs->next;
  676. } /* driver ok */
  677. }
  678. if (!cs1)
  679. { printk(KERN_WARNING "dss1_divert unhandled process\n");
  680. return(0);
  681. }
  682. if (cs1->ics.driver == -1)
  683. {
  684. spin_lock_irqsave(&divert_lock, flags);
  685. del_timer(&cs1->timer);
  686. if (cs1->prev)
  687. cs1->prev->next = cs1->next; /* forward link */
  688. else
  689. divert_head = cs1->next;
  690. if (cs1->next)
  691. cs1->next->prev = cs1->prev; /* back link */
  692. spin_unlock_irqrestore(&divert_lock, flags);
  693. kfree(cs1);
  694. }
  695. return(0);
  696. } /* prot_stat_callback */
  697. /***************************/
  698. /* status callback from HL */
  699. /***************************/
  700. static int isdn_divert_stat_callback(isdn_ctrl *ic)
  701. { struct call_struc *cs, *cs1;
  702. unsigned long flags;
  703. int retval;
  704. retval = -1;
  705. cs = divert_head; /* start of list */
  706. while (cs)
  707. { if ((ic->driver == cs->ics.driver) && (ic->arg == cs->ics.arg))
  708. { switch (ic->command)
  709. { case ISDN_STAT_DHUP:
  710. sprintf(cs->info,"129 0x%lx\n",cs->divert_id);
  711. del_timer(&cs->timer);
  712. cs->ics.driver = -1;
  713. break;
  714. case ISDN_STAT_CAUSE:
  715. sprintf(cs->info,"130 0x%lx %s\n",cs->divert_id,ic->parm.num);
  716. break;
  717. case ISDN_STAT_REDIR:
  718. sprintf(cs->info,"131 0x%lx\n",cs->divert_id);
  719. del_timer(&cs->timer);
  720. cs->ics.driver = -1;
  721. break;
  722. default:
  723. sprintf(cs->info,"999 0x%lx 0x%x\n",cs->divert_id,(int)(ic->command));
  724. break;
  725. }
  726. put_info_buffer(cs->info);
  727. retval = 0;
  728. }
  729. cs1 = cs;
  730. cs = cs->next;
  731. if (cs1->ics.driver == -1)
  732. {
  733. spin_lock_irqsave(&divert_lock, flags);
  734. if (cs1->prev)
  735. cs1->prev->next = cs1->next; /* forward link */
  736. else
  737. divert_head = cs1->next;
  738. if (cs1->next)
  739. cs1->next->prev = cs1->prev; /* back link */
  740. spin_unlock_irqrestore(&divert_lock, flags);
  741. kfree(cs1);
  742. }
  743. }
  744. return(retval); /* not found */
  745. } /* isdn_divert_stat_callback */
  746. /********************/
  747. /* callback from ll */
  748. /********************/
  749. int ll_callback(isdn_ctrl *ic)
  750. {
  751. switch (ic->command)
  752. { case ISDN_STAT_ICALL:
  753. case ISDN_STAT_ICALLW:
  754. return(isdn_divert_icall(ic));
  755. break;
  756. case ISDN_STAT_PROT:
  757. if ((ic->arg & 0xFF) == ISDN_PTYPE_EURO)
  758. { if (ic->arg != DSS1_STAT_INVOKE_BRD)
  759. return(prot_stat_callback(ic));
  760. else
  761. return(0); /* DSS1 invoke broadcast */
  762. }
  763. else
  764. return(-1); /* protocol not euro */
  765. default:
  766. return(isdn_divert_stat_callback(ic));
  767. }
  768. } /* ll_callback */