12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182 |
- /* $Id: l3ni1.c,v 2.8.2.3 2004/01/13 14:31:25 keil Exp $
- *
- * NI1 D-channel protocol
- *
- * Author Matt Henderson & Guy Ellis
- * Copyright by Traverse Technologies Pty Ltd, www.travers.com.au
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * 2000.6.6 Initial implementation of routines for US NI1
- * Layer 3 protocol based on the EURO/DSS1 D-channel protocol
- * driver written by Karsten Keil et al.
- * NI-1 Hall of Fame - Thanks to....
- * Ragnar Paulson - for some handy code fragments
- * Will Scales - beta tester extraordinaire
- * Brett Whittacre - beta tester and remote devel system in Vegas
- *
- */
- #include "hisax.h"
- #include "isdnl3.h"
- #include "l3ni1.h"
- #include <linux/ctype.h>
- #include <linux/slab.h>
- extern char *HiSax_getrev(const char *revision);
- static const char *ni1_revision = "$Revision: 2.8.2.3 $";
- #define EXT_BEARER_CAPS 1
- #define MsgHead(ptr, cref, mty) \
- *ptr++ = 0x8; \
- if (cref == -1) { \
- *ptr++ = 0x0; \
- } else { \
- *ptr++ = 0x1; \
- *ptr++ = cref^0x80; \
- } \
- *ptr++ = mty
- /**********************************************/
- /* get a new invoke id for remote operations. */
- /* Only a return value != 0 is valid */
- /**********************************************/
- static unsigned char new_invoke_id(struct PStack *p)
- {
- unsigned char retval;
- int i;
- i = 32; /* maximum search depth */
- retval = p->prot.ni1.last_invoke_id + 1; /* try new id */
- while ((i) && (p->prot.ni1.invoke_used[retval >> 3] == 0xFF)) {
- p->prot.ni1.last_invoke_id = (retval & 0xF8) + 8;
- i--;
- }
- if (i) {
- while (p->prot.ni1.invoke_used[retval >> 3] & (1 << (retval & 7)))
- retval++;
- } else
- retval = 0;
- p->prot.ni1.last_invoke_id = retval;
- p->prot.ni1.invoke_used[retval >> 3] |= (1 << (retval & 7));
- return (retval);
- } /* new_invoke_id */
- /*************************/
- /* free a used invoke id */
- /*************************/
- static void free_invoke_id(struct PStack *p, unsigned char id)
- {
- if (!id) return; /* 0 = invalid value */
- p->prot.ni1.invoke_used[id >> 3] &= ~(1 << (id & 7));
- } /* free_invoke_id */
- /**********************************************************/
- /* create a new l3 process and fill in ni1 specific data */
- /**********************************************************/
- static struct l3_process
- *ni1_new_l3_process(struct PStack *st, int cr)
- { struct l3_process *proc;
- if (!(proc = new_l3_process(st, cr)))
- return (NULL);
- proc->prot.ni1.invoke_id = 0;
- proc->prot.ni1.remote_operation = 0;
- proc->prot.ni1.uus1_data[0] = '\0';
- return (proc);
- } /* ni1_new_l3_process */
- /************************************************/
- /* free a l3 process and all ni1 specific data */
- /************************************************/
- static void
- ni1_release_l3_process(struct l3_process *p)
- {
- free_invoke_id(p->st, p->prot.ni1.invoke_id);
- release_l3_process(p);
- } /* ni1_release_l3_process */
- /********************************************************/
- /* search a process with invoke id id and dummy callref */
- /********************************************************/
- static struct l3_process *
- l3ni1_search_dummy_proc(struct PStack *st, int id)
- { struct l3_process *pc = st->l3.proc; /* start of processes */
- if (!id) return (NULL);
- while (pc)
- { if ((pc->callref == -1) && (pc->prot.ni1.invoke_id == id))
- return (pc);
- pc = pc->next;
- }
- return (NULL);
- } /* l3ni1_search_dummy_proc */
- /*******************************************************************/
- /* called when a facility message with a dummy callref is received */
- /* and a return result is delivered. id specifies the invoke id. */
- /*******************************************************************/
- static void
- l3ni1_dummy_return_result(struct PStack *st, int id, u_char *p, u_char nlen)
- { isdn_ctrl ic;
- struct IsdnCardState *cs;
- struct l3_process *pc = NULL;
- if ((pc = l3ni1_search_dummy_proc(st, id)))
- { L3DelTimer(&pc->timer); /* remove timer */
- cs = pc->st->l1.hardware;
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = NI1_STAT_INVOKE_RES;
- ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
- ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
- ic.parm.ni1_io.proc = pc->prot.ni1.proc;
- ic.parm.ni1_io.timeout = 0;
- ic.parm.ni1_io.datalen = nlen;
- ic.parm.ni1_io.data = p;
- free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
- pc->prot.ni1.invoke_id = 0; /* reset id */
- cs->iif.statcallb(&ic);
- ni1_release_l3_process(pc);
- }
- else
- l3_debug(st, "dummy return result id=0x%x result len=%d", id, nlen);
- } /* l3ni1_dummy_return_result */
- /*******************************************************************/
- /* called when a facility message with a dummy callref is received */
- /* and a return error is delivered. id specifies the invoke id. */
- /*******************************************************************/
- static void
- l3ni1_dummy_error_return(struct PStack *st, int id, ulong error)
- { isdn_ctrl ic;
- struct IsdnCardState *cs;
- struct l3_process *pc = NULL;
- if ((pc = l3ni1_search_dummy_proc(st, id)))
- { L3DelTimer(&pc->timer); /* remove timer */
- cs = pc->st->l1.hardware;
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = NI1_STAT_INVOKE_ERR;
- ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
- ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
- ic.parm.ni1_io.proc = pc->prot.ni1.proc;
- ic.parm.ni1_io.timeout = error;
- ic.parm.ni1_io.datalen = 0;
- ic.parm.ni1_io.data = NULL;
- free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
- pc->prot.ni1.invoke_id = 0; /* reset id */
- cs->iif.statcallb(&ic);
- ni1_release_l3_process(pc);
- }
- else
- l3_debug(st, "dummy return error id=0x%x error=0x%lx", id, error);
- } /* l3ni1_error_return */
- /*******************************************************************/
- /* called when a facility message with a dummy callref is received */
- /* and a invoke is delivered. id specifies the invoke id. */
- /*******************************************************************/
- static void
- l3ni1_dummy_invoke(struct PStack *st, int cr, int id,
- int ident, u_char *p, u_char nlen)
- { isdn_ctrl ic;
- struct IsdnCardState *cs;
- l3_debug(st, "dummy invoke %s id=0x%x ident=0x%x datalen=%d",
- (cr == -1) ? "local" : "broadcast", id, ident, nlen);
- if (cr >= -1) return; /* ignore local data */
- cs = st->l1.hardware;
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = NI1_STAT_INVOKE_BRD;
- ic.parm.ni1_io.hl_id = id;
- ic.parm.ni1_io.ll_id = 0;
- ic.parm.ni1_io.proc = ident;
- ic.parm.ni1_io.timeout = 0;
- ic.parm.ni1_io.datalen = nlen;
- ic.parm.ni1_io.data = p;
- cs->iif.statcallb(&ic);
- } /* l3ni1_dummy_invoke */
- static void
- l3ni1_parse_facility(struct PStack *st, struct l3_process *pc,
- int cr, u_char *p)
- {
- int qd_len = 0;
- unsigned char nlen = 0, ilen, cp_tag;
- int ident, id;
- ulong err_ret;
- if (pc)
- st = pc->st; /* valid Stack */
- else
- if ((!st) || (cr >= 0)) return; /* neither pc nor st specified */
- p++;
- qd_len = *p++;
- if (qd_len == 0) {
- l3_debug(st, "qd_len == 0");
- return;
- }
- if ((*p & 0x1F) != 0x11) { /* Service discriminator, supplementary service */
- l3_debug(st, "supplementary service != 0x11");
- return;
- }
- while (qd_len > 0 && !(*p & 0x80)) { /* extension ? */
- p++;
- qd_len--;
- }
- if (qd_len < 2) {
- l3_debug(st, "qd_len < 2");
- return;
- }
- p++;
- qd_len--;
- if ((*p & 0xE0) != 0xA0) { /* class and form */
- l3_debug(st, "class and form != 0xA0");
- return;
- }
- cp_tag = *p & 0x1F; /* remember tag value */
- p++;
- qd_len--;
- if (qd_len < 1)
- { l3_debug(st, "qd_len < 1");
- return;
- }
- if (*p & 0x80)
- { /* length format indefinite or limited */
- nlen = *p++ & 0x7F; /* number of len bytes or indefinite */
- if ((qd_len-- < ((!nlen) ? 3 : (1 + nlen))) ||
- (nlen > 1))
- { l3_debug(st, "length format error or not implemented");
- return;
- }
- if (nlen == 1)
- { nlen = *p++; /* complete length */
- qd_len--;
- }
- else
- { qd_len -= 2; /* trailing null bytes */
- if ((*(p + qd_len)) || (*(p + qd_len + 1)))
- { l3_debug(st, "length format indefinite error");
- return;
- }
- nlen = qd_len;
- }
- }
- else
- { nlen = *p++;
- qd_len--;
- }
- if (qd_len < nlen)
- { l3_debug(st, "qd_len < nlen");
- return;
- }
- qd_len -= nlen;
- if (nlen < 2)
- { l3_debug(st, "nlen < 2");
- return;
- }
- if (*p != 0x02)
- { /* invoke identifier tag */
- l3_debug(st, "invoke identifier tag !=0x02");
- return;
- }
- p++;
- nlen--;
- if (*p & 0x80)
- { /* length format */
- l3_debug(st, "invoke id length format 2");
- return;
- }
- ilen = *p++;
- nlen--;
- if (ilen > nlen || ilen == 0)
- { l3_debug(st, "ilen > nlen || ilen == 0");
- return;
- }
- nlen -= ilen;
- id = 0;
- while (ilen > 0)
- { id = (id << 8) | (*p++ & 0xFF); /* invoke identifier */
- ilen--;
- }
- switch (cp_tag) { /* component tag */
- case 1: /* invoke */
- if (nlen < 2) {
- l3_debug(st, "nlen < 2 22");
- return;
- }
- if (*p != 0x02) { /* operation value */
- l3_debug(st, "operation value !=0x02");
- return;
- }
- p++;
- nlen--;
- ilen = *p++;
- nlen--;
- if (ilen > nlen || ilen == 0) {
- l3_debug(st, "ilen > nlen || ilen == 0 22");
- return;
- }
- nlen -= ilen;
- ident = 0;
- while (ilen > 0) {
- ident = (ident << 8) | (*p++ & 0xFF);
- ilen--;
- }
- if (!pc)
- {
- l3ni1_dummy_invoke(st, cr, id, ident, p, nlen);
- return;
- }
- l3_debug(st, "invoke break");
- break;
- case 2: /* return result */
- /* if no process available handle separately */
- if (!pc)
- { if (cr == -1)
- l3ni1_dummy_return_result(st, id, p, nlen);
- return;
- }
- if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
- { /* Diversion successful */
- free_invoke_id(st, pc->prot.ni1.invoke_id);
- pc->prot.ni1.remote_result = 0; /* success */
- pc->prot.ni1.invoke_id = 0;
- pc->redir_result = pc->prot.ni1.remote_result;
- st->l3.l3l4(st, CC_REDIR | INDICATION, pc); } /* Diversion successful */
- else
- l3_debug(st, "return error unknown identifier");
- break;
- case 3: /* return error */
- err_ret = 0;
- if (nlen < 2)
- { l3_debug(st, "return error nlen < 2");
- return;
- }
- if (*p != 0x02)
- { /* result tag */
- l3_debug(st, "invoke error tag !=0x02");
- return;
- }
- p++;
- nlen--;
- if (*p > 4)
- { /* length format */
- l3_debug(st, "invoke return errlen > 4 ");
- return;
- }
- ilen = *p++;
- nlen--;
- if (ilen > nlen || ilen == 0)
- { l3_debug(st, "error return ilen > nlen || ilen == 0");
- return;
- }
- nlen -= ilen;
- while (ilen > 0)
- { err_ret = (err_ret << 8) | (*p++ & 0xFF); /* error value */
- ilen--;
- }
- /* if no process available handle separately */
- if (!pc)
- { if (cr == -1)
- l3ni1_dummy_error_return(st, id, err_ret);
- return;
- }
- if ((pc->prot.ni1.invoke_id) && (pc->prot.ni1.invoke_id == id))
- { /* Deflection error */
- free_invoke_id(st, pc->prot.ni1.invoke_id);
- pc->prot.ni1.remote_result = err_ret; /* result */
- pc->prot.ni1.invoke_id = 0;
- pc->redir_result = pc->prot.ni1.remote_result;
- st->l3.l3l4(st, CC_REDIR | INDICATION, pc);
- } /* Deflection error */
- else
- l3_debug(st, "return result unknown identifier");
- break;
- default:
- l3_debug(st, "facility default break tag=0x%02x", cp_tag);
- break;
- }
- }
- static void
- l3ni1_message(struct l3_process *pc, u_char mt)
- {
- struct sk_buff *skb;
- u_char *p;
- if (!(skb = l3_alloc_skb(4)))
- return;
- p = skb_put(skb, 4);
- MsgHead(p, pc->callref, mt);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- }
- static void
- l3ni1_message_plus_chid(struct l3_process *pc, u_char mt)
- /* sends an l3 messages plus channel id - added GE 05/09/00 */
- {
- struct sk_buff *skb;
- u_char tmp[16];
- u_char *p = tmp;
- u_char chid;
- chid = (u_char)(pc->para.bchannel & 0x03) | 0x88;
- MsgHead(p, pc->callref, mt);
- *p++ = IE_CHANNEL_ID;
- *p++ = 0x01;
- *p++ = chid;
- if (!(skb = l3_alloc_skb(7)))
- return;
- memcpy(skb_put(skb, 7), tmp, 7);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- }
- static void
- l3ni1_message_cause(struct l3_process *pc, u_char mt, u_char cause)
- {
- struct sk_buff *skb;
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- MsgHead(p, pc->callref, mt);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- }
- static void
- l3ni1_status_send(struct l3_process *pc, u_char pr, void *arg)
- {
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- struct sk_buff *skb;
- MsgHead(p, pc->callref, MT_STATUS);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = pc->para.cause | 0x80;
- *p++ = IE_CALL_STATE;
- *p++ = 0x1;
- *p++ = pc->state & 0x3f;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- }
- static void
- l3ni1_msg_without_setup(struct l3_process *pc, u_char pr, void *arg)
- {
- /* This routine is called if here was no SETUP made (checks in ni1up and in
- * l3ni1_setup) and a RELEASE_COMPLETE have to be sent with an error code
- * MT_STATUS_ENQUIRE in the NULL state is handled too
- */
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- struct sk_buff *skb;
- switch (pc->para.cause) {
- case 81: /* invalid callreference */
- case 88: /* incomp destination */
- case 96: /* mandory IE missing */
- case 100: /* invalid IE contents */
- case 101: /* incompatible Callstate */
- MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = pc->para.cause | 0x80;
- break;
- default:
- printk(KERN_ERR "HiSax l3ni1_msg_without_setup wrong cause %d\n",
- pc->para.cause);
- return;
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- ni1_release_l3_process(pc);
- }
- static int ie_ALERTING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_HLC,
- IE_USER_USER, -1};
- static int ie_CALL_PROCEEDING[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_HLC, -1};
- static int ie_CONNECT[] = {IE_BEARER, IE_CHANNEL_ID | IE_MANDATORY_1,
- IE_FACILITY, IE_PROGRESS, IE_DISPLAY, IE_DATE, IE_SIGNAL,
- IE_CONNECT_PN, IE_CONNECT_SUB, IE_LLC, IE_HLC, IE_USER_USER, -1};
- static int ie_CONNECT_ACKNOWLEDGE[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_SIGNAL, -1};
- static int ie_DISCONNECT[] = {IE_CAUSE | IE_MANDATORY, IE_FACILITY,
- IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
- static int ie_INFORMATION[] = {IE_COMPLETE, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL,
- IE_CALLED_PN, -1};
- static int ie_NOTIFY[] = {IE_BEARER, IE_NOTIFY | IE_MANDATORY, IE_DISPLAY, -1};
- static int ie_PROGRESS[] = {IE_BEARER, IE_CAUSE, IE_FACILITY, IE_PROGRESS |
- IE_MANDATORY, IE_DISPLAY, IE_HLC, IE_USER_USER, -1};
- static int ie_RELEASE[] = {IE_CAUSE | IE_MANDATORY_1, IE_FACILITY, IE_DISPLAY,
- IE_SIGNAL, IE_USER_USER, -1};
- /* a RELEASE_COMPLETE with errors don't require special actions
- static int ie_RELEASE_COMPLETE[] = {IE_CAUSE | IE_MANDATORY_1, IE_DISPLAY, IE_SIGNAL, IE_USER_USER, -1};
- */
- static int ie_RESUME_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
- IE_DISPLAY, -1};
- static int ie_RESUME_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
- static int ie_SETUP[] = {IE_COMPLETE, IE_BEARER | IE_MANDATORY,
- IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY, IE_PROGRESS,
- IE_NET_FAC, IE_DISPLAY, IE_KEYPAD, IE_SIGNAL, IE_CALLING_PN,
- IE_CALLING_SUB, IE_CALLED_PN, IE_CALLED_SUB, IE_REDIR_NR,
- IE_LLC, IE_HLC, IE_USER_USER, -1};
- static int ie_SETUP_ACKNOWLEDGE[] = {IE_CHANNEL_ID | IE_MANDATORY, IE_FACILITY,
- IE_PROGRESS, IE_DISPLAY, IE_SIGNAL, -1};
- static int ie_STATUS[] = {IE_CAUSE | IE_MANDATORY, IE_CALL_STATE |
- IE_MANDATORY, IE_DISPLAY, -1};
- static int ie_STATUS_ENQUIRY[] = {IE_DISPLAY, -1};
- static int ie_SUSPEND_ACKNOWLEDGE[] = {IE_DISPLAY, IE_FACILITY, -1};
- static int ie_SUSPEND_REJECT[] = {IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
- /* not used
- * static int ie_CONGESTION_CONTROL[] = {IE_CONGESTION | IE_MANDATORY,
- * IE_CAUSE | IE_MANDATORY, IE_DISPLAY, -1};
- * static int ie_USER_INFORMATION[] = {IE_MORE_DATA, IE_USER_USER | IE_MANDATORY, -1};
- * static int ie_RESTART[] = {IE_CHANNEL_ID, IE_DISPLAY, IE_RESTART_IND |
- * IE_MANDATORY, -1};
- */
- static int ie_FACILITY[] = {IE_FACILITY | IE_MANDATORY, IE_DISPLAY, -1};
- static int comp_required[] = {1, 2, 3, 5, 6, 7, 9, 10, 11, 14, 15, -1};
- static int l3_valid_states[] = {0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11, 12, 15, 17, 19, 25, -1};
- struct ie_len {
- int ie;
- int len;
- };
- static
- struct ie_len max_ie_len[] = {
- {IE_SEGMENT, 4},
- {IE_BEARER, 12},
- {IE_CAUSE, 32},
- {IE_CALL_ID, 10},
- {IE_CALL_STATE, 3},
- {IE_CHANNEL_ID, 34},
- {IE_FACILITY, 255},
- {IE_PROGRESS, 4},
- {IE_NET_FAC, 255},
- {IE_NOTIFY, 3},
- {IE_DISPLAY, 82},
- {IE_DATE, 8},
- {IE_KEYPAD, 34},
- {IE_SIGNAL, 3},
- {IE_INFORATE, 6},
- {IE_E2E_TDELAY, 11},
- {IE_TDELAY_SEL, 5},
- {IE_PACK_BINPARA, 3},
- {IE_PACK_WINSIZE, 4},
- {IE_PACK_SIZE, 4},
- {IE_CUG, 7},
- {IE_REV_CHARGE, 3},
- {IE_CALLING_PN, 24},
- {IE_CALLING_SUB, 23},
- {IE_CALLED_PN, 24},
- {IE_CALLED_SUB, 23},
- {IE_REDIR_NR, 255},
- {IE_TRANS_SEL, 255},
- {IE_RESTART_IND, 3},
- {IE_LLC, 18},
- {IE_HLC, 5},
- {IE_USER_USER, 131},
- {-1, 0},
- };
- static int
- getmax_ie_len(u_char ie) {
- int i = 0;
- while (max_ie_len[i].ie != -1) {
- if (max_ie_len[i].ie == ie)
- return (max_ie_len[i].len);
- i++;
- }
- return (255);
- }
- static int
- ie_in_set(struct l3_process *pc, u_char ie, int *checklist) {
- int ret = 1;
- while (*checklist != -1) {
- if ((*checklist & 0xff) == ie) {
- if (ie & 0x80)
- return (-ret);
- else
- return (ret);
- }
- ret++;
- checklist++;
- }
- return (0);
- }
- static int
- check_infoelements(struct l3_process *pc, struct sk_buff *skb, int *checklist)
- {
- int *cl = checklist;
- u_char mt;
- u_char *p, ie;
- int l, newpos, oldpos;
- int err_seq = 0, err_len = 0, err_compr = 0, err_ureg = 0;
- u_char codeset = 0;
- u_char old_codeset = 0;
- u_char codelock = 1;
- p = skb->data;
- /* skip cr */
- p++;
- l = (*p++) & 0xf;
- p += l;
- mt = *p++;
- oldpos = 0;
- while ((p - skb->data) < skb->len) {
- if ((*p & 0xf0) == 0x90) { /* shift codeset */
- old_codeset = codeset;
- codeset = *p & 7;
- if (*p & 0x08)
- codelock = 0;
- else
- codelock = 1;
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check IE shift%scodeset %d->%d",
- codelock ? " locking " : " ", old_codeset, codeset);
- p++;
- continue;
- }
- if (!codeset) { /* only codeset 0 */
- if ((newpos = ie_in_set(pc, *p, cl))) {
- if (newpos > 0) {
- if (newpos < oldpos)
- err_seq++;
- else
- oldpos = newpos;
- }
- } else {
- if (ie_in_set(pc, *p, comp_required))
- err_compr++;
- else
- err_ureg++;
- }
- }
- ie = *p++;
- if (ie & 0x80) {
- l = 1;
- } else {
- l = *p++;
- p += l;
- l += 2;
- }
- if (!codeset && (l > getmax_ie_len(ie)))
- err_len++;
- if (!codelock) {
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check IE shift back codeset %d->%d",
- codeset, old_codeset);
- codeset = old_codeset;
- codelock = 1;
- }
- }
- if (err_compr | err_ureg | err_len | err_seq) {
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check IE MT(%x) %d/%d/%d/%d",
- mt, err_compr, err_ureg, err_len, err_seq);
- if (err_compr)
- return (ERR_IE_COMPREHENSION);
- if (err_ureg)
- return (ERR_IE_UNRECOGNIZED);
- if (err_len)
- return (ERR_IE_LENGTH);
- if (err_seq)
- return (ERR_IE_SEQUENCE);
- }
- return (0);
- }
- /* verify if a message type exists and contain no IE error */
- static int
- l3ni1_check_messagetype_validity(struct l3_process *pc, int mt, void *arg)
- {
- switch (mt) {
- case MT_ALERTING:
- case MT_CALL_PROCEEDING:
- case MT_CONNECT:
- case MT_CONNECT_ACKNOWLEDGE:
- case MT_DISCONNECT:
- case MT_INFORMATION:
- case MT_FACILITY:
- case MT_NOTIFY:
- case MT_PROGRESS:
- case MT_RELEASE:
- case MT_RELEASE_COMPLETE:
- case MT_SETUP:
- case MT_SETUP_ACKNOWLEDGE:
- case MT_RESUME_ACKNOWLEDGE:
- case MT_RESUME_REJECT:
- case MT_SUSPEND_ACKNOWLEDGE:
- case MT_SUSPEND_REJECT:
- case MT_USER_INFORMATION:
- case MT_RESTART:
- case MT_RESTART_ACKNOWLEDGE:
- case MT_CONGESTION_CONTROL:
- case MT_STATUS:
- case MT_STATUS_ENQUIRY:
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) OK", mt);
- break;
- case MT_RESUME: /* RESUME only in user->net */
- case MT_SUSPEND: /* SUSPEND only in user->net */
- default:
- if (pc->debug & (L3_DEB_CHECK | L3_DEB_WARN))
- l3_debug(pc->st, "l3ni1_check_messagetype_validity mt(%x) fail", mt);
- pc->para.cause = 97;
- l3ni1_status_send(pc, 0, NULL);
- return (1);
- }
- return (0);
- }
- static void
- l3ni1_std_ie_err(struct l3_process *pc, int ret) {
- if (pc->debug & L3_DEB_CHECK)
- l3_debug(pc->st, "check_infoelements ret %d", ret);
- switch (ret) {
- case 0:
- break;
- case ERR_IE_COMPREHENSION:
- pc->para.cause = 96;
- l3ni1_status_send(pc, 0, NULL);
- break;
- case ERR_IE_UNRECOGNIZED:
- pc->para.cause = 99;
- l3ni1_status_send(pc, 0, NULL);
- break;
- case ERR_IE_LENGTH:
- pc->para.cause = 100;
- l3ni1_status_send(pc, 0, NULL);
- break;
- case ERR_IE_SEQUENCE:
- default:
- break;
- }
- }
- static int
- l3ni1_get_channel_id(struct l3_process *pc, struct sk_buff *skb) {
- u_char *p;
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
- p++;
- if (*p != 1) { /* len for BRI = 1 */
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong chid len %d", *p);
- return (-2);
- }
- p++;
- if (*p & 0x60) { /* only base rate interface */
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong chid %x", *p);
- return (-3);
- }
- return (*p & 0x3);
- } else
- return (-1);
- }
- static int
- l3ni1_get_cause(struct l3_process *pc, struct sk_buff *skb) {
- u_char l, i = 0;
- u_char *p;
- p = skb->data;
- pc->para.cause = 31;
- pc->para.loc = 0;
- if ((p = findie(p, skb->len, IE_CAUSE, 0))) {
- p++;
- l = *p++;
- if (l > 30)
- return (1);
- if (l) {
- pc->para.loc = *p++;
- l--;
- } else {
- return (2);
- }
- if (l && !(pc->para.loc & 0x80)) {
- l--;
- p++; /* skip recommendation */
- }
- if (l) {
- pc->para.cause = *p++;
- l--;
- if (!(pc->para.cause & 0x80))
- return (3);
- } else
- return (4);
- while (l && (i < 6)) {
- pc->para.diag[i++] = *p++;
- l--;
- }
- } else
- return (-1);
- return (0);
- }
- static void
- l3ni1_msg_with_uus(struct l3_process *pc, u_char cmd)
- {
- struct sk_buff *skb;
- u_char tmp[16 + 40];
- u_char *p = tmp;
- int l;
- MsgHead(p, pc->callref, cmd);
- if (pc->prot.ni1.uus1_data[0])
- { *p++ = IE_USER_USER; /* UUS info element */
- *p++ = strlen(pc->prot.ni1.uus1_data) + 1;
- *p++ = 0x04; /* IA5 chars */
- strcpy(p, pc->prot.ni1.uus1_data);
- p += strlen(pc->prot.ni1.uus1_data);
- pc->prot.ni1.uus1_data[0] = '\0';
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- } /* l3ni1_msg_with_uus */
- static void
- l3ni1_release_req(struct l3_process *pc, u_char pr, void *arg)
- {
- StopAllL3Timer(pc);
- newl3state(pc, 19);
- if (!pc->prot.ni1.uus1_data[0])
- l3ni1_message(pc, MT_RELEASE);
- else
- l3ni1_msg_with_uus(pc, MT_RELEASE);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
- }
- static void
- l3ni1_release_cmpl(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int ret;
- if ((ret = l3ni1_get_cause(pc, skb)) > 0) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "RELCMPL get_cause ret(%d)", ret);
- } else if (ret < 0)
- pc->para.cause = NO_CAUSE;
- StopAllL3Timer(pc);
- newl3state(pc, 0);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | CONFIRM, pc);
- ni1_release_l3_process(pc);
- }
- #if EXT_BEARER_CAPS
- static u_char *
- EncodeASyncParams(u_char *p, u_char si2)
- { // 7c 06 88 90 21 42 00 bb
- p[0] = 0;
- p[1] = 0x40; // Intermediate rate: 16 kbit/s jj 2000.02.19
- p[2] = 0x80;
- if (si2 & 32) // 7 data bits
- p[2] += 16;
- else // 8 data bits
- p[2] += 24;
- if (si2 & 16) // 2 stop bits
- p[2] += 96;
- else // 1 stop bit
- p[2] += 32;
- if (si2 & 8) // even parity
- p[2] += 2;
- else // no parity
- p[2] += 3;
- switch (si2 & 0x07) {
- case 0:
- p[0] = 66; // 1200 bit/s
- break;
- case 1:
- p[0] = 88; // 1200/75 bit/s
- break;
- case 2:
- p[0] = 87; // 75/1200 bit/s
- break;
- case 3:
- p[0] = 67; // 2400 bit/s
- break;
- case 4:
- p[0] = 69; // 4800 bit/s
- break;
- case 5:
- p[0] = 72; // 9600 bit/s
- break;
- case 6:
- p[0] = 73; // 14400 bit/s
- break;
- case 7:
- p[0] = 75; // 19200 bit/s
- break;
- }
- return p + 3;
- }
- static u_char
- EncodeSyncParams(u_char si2, u_char ai)
- {
- switch (si2) {
- case 0:
- return ai + 2; // 1200 bit/s
- case 1:
- return ai + 24; // 1200/75 bit/s
- case 2:
- return ai + 23; // 75/1200 bit/s
- case 3:
- return ai + 3; // 2400 bit/s
- case 4:
- return ai + 5; // 4800 bit/s
- case 5:
- return ai + 8; // 9600 bit/s
- case 6:
- return ai + 9; // 14400 bit/s
- case 7:
- return ai + 11; // 19200 bit/s
- case 8:
- return ai + 14; // 48000 bit/s
- case 9:
- return ai + 15; // 56000 bit/s
- case 15:
- return ai + 40; // negotiate bit/s
- default:
- break;
- }
- return ai;
- }
- static u_char
- DecodeASyncParams(u_char si2, u_char *p)
- {
- u_char info;
- switch (p[5]) {
- case 66: // 1200 bit/s
- break; // si2 don't change
- case 88: // 1200/75 bit/s
- si2 += 1;
- break;
- case 87: // 75/1200 bit/s
- si2 += 2;
- break;
- case 67: // 2400 bit/s
- si2 += 3;
- break;
- case 69: // 4800 bit/s
- si2 += 4;
- break;
- case 72: // 9600 bit/s
- si2 += 5;
- break;
- case 73: // 14400 bit/s
- si2 += 6;
- break;
- case 75: // 19200 bit/s
- si2 += 7;
- break;
- }
- info = p[7] & 0x7f;
- if ((info & 16) && (!(info & 8))) // 7 data bits
- si2 += 32; // else 8 data bits
- if ((info & 96) == 96) // 2 stop bits
- si2 += 16; // else 1 stop bit
- if ((info & 2) && (!(info & 1))) // even parity
- si2 += 8; // else no parity
- return si2;
- }
- static u_char
- DecodeSyncParams(u_char si2, u_char info)
- {
- info &= 0x7f;
- switch (info) {
- case 40: // bit/s negotiation failed ai := 165 not 175!
- return si2 + 15;
- case 15: // 56000 bit/s failed, ai := 0 not 169 !
- return si2 + 9;
- case 14: // 48000 bit/s
- return si2 + 8;
- case 11: // 19200 bit/s
- return si2 + 7;
- case 9: // 14400 bit/s
- return si2 + 6;
- case 8: // 9600 bit/s
- return si2 + 5;
- case 5: // 4800 bit/s
- return si2 + 4;
- case 3: // 2400 bit/s
- return si2 + 3;
- case 23: // 75/1200 bit/s
- return si2 + 2;
- case 24: // 1200/75 bit/s
- return si2 + 1;
- default: // 1200 bit/s
- return si2;
- }
- }
- static u_char
- DecodeSI2(struct sk_buff *skb)
- {
- u_char *p; //, *pend=skb->data + skb->len;
- if ((p = findie(skb->data, skb->len, 0x7c, 0))) {
- switch (p[4] & 0x0f) {
- case 0x01:
- if (p[1] == 0x04) // sync. Bitratenadaption
- return DecodeSyncParams(160, p[5]); // V.110/X.30
- else if (p[1] == 0x06) // async. Bitratenadaption
- return DecodeASyncParams(192, p); // V.110/X.30
- break;
- case 0x08: // if (p[5] == 0x02) // sync. Bitratenadaption
- if (p[1] > 3)
- return DecodeSyncParams(176, p[5]); // V.120
- break;
- }
- }
- return 0;
- }
- #endif
- static void
- l3ni1_setup_req(struct l3_process *pc, u_char pr,
- void *arg)
- {
- struct sk_buff *skb;
- u_char tmp[128];
- u_char *p = tmp;
- u_char *teln;
- u_char *sub;
- u_char *sp;
- int l;
- MsgHead(p, pc->callref, MT_SETUP);
- teln = pc->para.setup.phone;
- *p++ = 0xa1; /* complete indicator */
- /*
- * Set Bearer Capability, Map info from 1TR6-convention to NI1
- */
- switch (pc->para.setup.si1) {
- case 1: /* Telephony */
- *p++ = IE_BEARER;
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* 3.1khz Audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa2; /* u-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = IE_BEARER;
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- break;
- }
- sub = NULL;
- sp = teln;
- while (*sp) {
- if ('.' == *sp) {
- sub = sp;
- *sp = 0;
- } else
- sp++;
- }
- *p++ = IE_KEYPAD;
- *p++ = strlen(teln);
- while (*teln)
- *p++ = (*teln++) & 0x7F;
- if (sub)
- *sub++ = '.';
- #if EXT_BEARER_CAPS
- if ((pc->para.setup.si2 >= 160) && (pc->para.setup.si2 <= 175)) { // sync. Bitratenadaption, V.110/X.30
- *p++ = IE_LLC;
- *p++ = 0x04;
- *p++ = 0x88;
- *p++ = 0x90;
- *p++ = 0x21;
- *p++ = EncodeSyncParams(pc->para.setup.si2 - 160, 0x80);
- } else if ((pc->para.setup.si2 >= 176) && (pc->para.setup.si2 <= 191)) { // sync. Bitratenadaption, V.120
- *p++ = IE_LLC;
- *p++ = 0x05;
- *p++ = 0x88;
- *p++ = 0x90;
- *p++ = 0x28;
- *p++ = EncodeSyncParams(pc->para.setup.si2 - 176, 0);
- *p++ = 0x82;
- } else if (pc->para.setup.si2 >= 192) { // async. Bitratenadaption, V.110/X.30
- *p++ = IE_LLC;
- *p++ = 0x06;
- *p++ = 0x88;
- *p++ = 0x90;
- *p++ = 0x21;
- p = EncodeASyncParams(p, pc->para.setup.si2 - 192);
- } else {
- switch (pc->para.setup.si1) {
- case 1: /* Telephony */
- *p++ = IE_LLC;
- *p++ = 0x3; /* Length */
- *p++ = 0x90; /* Coding Std. CCITT, 3.1 kHz audio */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- *p++ = 0xa2; /* u-Law Audio */
- break;
- case 5: /* Datatransmission 64k, BTX */
- case 7: /* Datatransmission 64k */
- default:
- *p++ = IE_LLC;
- *p++ = 0x2; /* Length */
- *p++ = 0x88; /* Coding Std. CCITT, unrestr. dig. Inform. */
- *p++ = 0x90; /* Circuit-Mode 64kbps */
- break;
- }
- }
- #endif
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- {
- return;
- }
- memcpy(skb_put(skb, l), tmp, l);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T303, CC_T303);
- newl3state(pc, 1);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- }
- static void
- l3ni1_call_proc(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int id, ret;
- if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
- if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer with wrong chid %x", id);
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- pc->para.bchannel = id;
- } else if (1 == pc->state) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
- if (id == -1)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- ret = check_infoelements(pc, skb, ie_CALL_PROCEEDING);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- newl3state(pc, 3);
- L3AddTimer(&pc->timer, T310, CC_T310);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_PROCEEDING | INDICATION, pc);
- }
- static void
- l3ni1_setup_ack(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int id, ret;
- if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
- if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer with wrong chid %x", id);
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- pc->para.bchannel = id;
- } else {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup answer wrong chid (ret %d)", id);
- if (id == -1)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- ret = check_infoelements(pc, skb, ie_SETUP_ACKNOWLEDGE);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- newl3state(pc, 2);
- L3AddTimer(&pc->timer, T304, CC_T304);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
- }
- static void
- l3ni1_disconnect(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- u_char *p;
- int ret;
- u_char cause = 0;
- StopAllL3Timer(pc);
- if ((ret = l3ni1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "DISC get_cause ret(%d)", ret);
- if (ret < 0)
- cause = 96;
- else if (ret > 0)
- cause = 100;
- }
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
- l3ni1_parse_facility(pc->st, pc, pc->callref, p);
- ret = check_infoelements(pc, skb, ie_DISCONNECT);
- if (ERR_IE_COMPREHENSION == ret)
- cause = 96;
- else if ((!cause) && (ERR_IE_UNRECOGNIZED == ret))
- cause = 99;
- ret = pc->state;
- newl3state(pc, 12);
- if (cause)
- newl3state(pc, 19);
- if (11 != ret)
- pc->st->l3.l3l4(pc->st, CC_DISCONNECT | INDICATION, pc);
- else if (!cause)
- l3ni1_release_req(pc, pr, NULL);
- if (cause) {
- l3ni1_message_cause(pc, MT_RELEASE, cause);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
- }
- }
- static void
- l3ni1_connect(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int ret;
- ret = check_infoelements(pc, skb, ie_CONNECT);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer); /* T310 */
- newl3state(pc, 10);
- pc->para.chargeinfo = 0;
- /* here should inserted COLP handling KKe */
- if (ret)
- l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_SETUP | CONFIRM, pc);
- }
- static void
- l3ni1_alerting(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int ret;
- ret = check_infoelements(pc, skb, ie_ALERTING);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer); /* T304 */
- newl3state(pc, 4);
- if (ret)
- l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_ALERTING | INDICATION, pc);
- }
- static void
- l3ni1_setup(struct l3_process *pc, u_char pr, void *arg)
- {
- u_char *p;
- int bcfound = 0;
- char tmp[80];
- struct sk_buff *skb = arg;
- int id;
- int err = 0;
- /*
- * Bearer Capabilities
- */
- p = skb->data;
- /* only the first occurrence 'll be detected ! */
- if ((p = findie(p, skb->len, 0x04, 0))) {
- if ((p[1] < 2) || (p[1] > 11))
- err = 1;
- else {
- pc->para.setup.si2 = 0;
- switch (p[2] & 0x7f) {
- case 0x00: /* Speech */
- case 0x10: /* 3.1 Khz audio */
- pc->para.setup.si1 = 1;
- break;
- case 0x08: /* Unrestricted digital information */
- pc->para.setup.si1 = 7;
- /* JIM, 05.11.97 I wanna set service indicator 2 */
- #if EXT_BEARER_CAPS
- pc->para.setup.si2 = DecodeSI2(skb);
- #endif
- break;
- case 0x09: /* Restricted digital information */
- pc->para.setup.si1 = 2;
- break;
- case 0x11:
- /* Unrestr. digital information with
- * tones/announcements ( or 7 kHz audio
- */
- pc->para.setup.si1 = 3;
- break;
- case 0x18: /* Video */
- pc->para.setup.si1 = 4;
- break;
- default:
- err = 2;
- break;
- }
- switch (p[3] & 0x7f) {
- case 0x40: /* packed mode */
- pc->para.setup.si1 = 8;
- break;
- case 0x10: /* 64 kbit */
- case 0x11: /* 2*64 kbit */
- case 0x13: /* 384 kbit */
- case 0x15: /* 1536 kbit */
- case 0x17: /* 1920 kbit */
- pc->para.moderate = p[3] & 0x7f;
- break;
- default:
- err = 3;
- break;
- }
- }
- if (pc->debug & L3_DEB_SI)
- l3_debug(pc->st, "SI=%d, AI=%d",
- pc->para.setup.si1, pc->para.setup.si2);
- if (err) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup with wrong bearer(l=%d:%x,%x)",
- p[1], p[2], p[3]);
- pc->para.cause = 100;
- l3ni1_msg_without_setup(pc, pr, NULL);
- return;
- }
- } else {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup without bearer capabilities");
- /* ETS 300-104 1.3.3 */
- pc->para.cause = 96;
- l3ni1_msg_without_setup(pc, pr, NULL);
- return;
- }
- /*
- * Channel Identification
- */
- if ((id = l3ni1_get_channel_id(pc, skb)) >= 0) {
- if ((pc->para.bchannel = id)) {
- if ((3 == id) && (0x10 == pc->para.moderate)) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup with wrong chid %x",
- id);
- pc->para.cause = 100;
- l3ni1_msg_without_setup(pc, pr, NULL);
- return;
- }
- bcfound++;
- } else
- { if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup without bchannel, call waiting");
- bcfound++;
- }
- } else {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "setup with wrong chid ret %d", id);
- if (id == -1)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3ni1_msg_without_setup(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- err = check_infoelements(pc, skb, ie_SETUP);
- if (ERR_IE_COMPREHENSION == err) {
- pc->para.cause = 96;
- l3ni1_msg_without_setup(pc, pr, NULL);
- return;
- }
- p = skb->data;
- if ((p = findie(p, skb->len, 0x70, 0)))
- iecpy(pc->para.setup.eazmsn, p, 1);
- else
- pc->para.setup.eazmsn[0] = 0;
- p = skb->data;
- if ((p = findie(p, skb->len, 0x71, 0))) {
- /* Called party subaddress */
- if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
- tmp[0] = '.';
- iecpy(&tmp[1], p, 2);
- strcat(pc->para.setup.eazmsn, tmp);
- } else if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong called subaddress");
- }
- p = skb->data;
- if ((p = findie(p, skb->len, 0x6c, 0))) {
- pc->para.setup.plan = p[2];
- if (p[2] & 0x80) {
- iecpy(pc->para.setup.phone, p, 1);
- pc->para.setup.screen = 0;
- } else {
- iecpy(pc->para.setup.phone, p, 2);
- pc->para.setup.screen = p[3];
- }
- } else {
- pc->para.setup.phone[0] = 0;
- pc->para.setup.plan = 0;
- pc->para.setup.screen = 0;
- }
- p = skb->data;
- if ((p = findie(p, skb->len, 0x6d, 0))) {
- /* Calling party subaddress */
- if ((p[1] >= 2) && (p[2] == 0x80) && (p[3] == 0x50)) {
- tmp[0] = '.';
- iecpy(&tmp[1], p, 2);
- strcat(pc->para.setup.phone, tmp);
- } else if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "wrong calling subaddress");
- }
- newl3state(pc, 6);
- if (err) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, err);
- pc->st->l3.l3l4(pc->st, CC_SETUP | INDICATION, pc);
- }
- static void
- l3ni1_reset(struct l3_process *pc, u_char pr, void *arg)
- {
- ni1_release_l3_process(pc);
- }
- static void
- l3ni1_disconnect_req(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb;
- u_char tmp[16 + 40];
- u_char *p = tmp;
- int l;
- u_char cause = 16;
- if (pc->para.cause != NO_CAUSE)
- cause = pc->para.cause;
- StopAllL3Timer(pc);
- MsgHead(p, pc->callref, MT_DISCONNECT);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
- if (pc->prot.ni1.uus1_data[0])
- { *p++ = IE_USER_USER; /* UUS info element */
- *p++ = strlen(pc->prot.ni1.uus1_data) + 1;
- *p++ = 0x04; /* IA5 chars */
- strcpy(p, pc->prot.ni1.uus1_data);
- p += strlen(pc->prot.ni1.uus1_data);
- pc->prot.ni1.uus1_data[0] = '\0';
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- newl3state(pc, 11);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- L3AddTimer(&pc->timer, T305, CC_T305);
- }
- static void
- l3ni1_setup_rsp(struct l3_process *pc, u_char pr,
- void *arg)
- {
- if (!pc->para.bchannel)
- { if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "D-chan connect for waiting call");
- l3ni1_disconnect_req(pc, pr, arg);
- return;
- }
- newl3state(pc, 8);
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "D-chan connect for waiting call");
- l3ni1_message_plus_chid(pc, MT_CONNECT); /* GE 05/09/00 */
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T313, CC_T313);
- }
- static void
- l3ni1_connect_ack(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int ret;
- ret = check_infoelements(pc, skb, ie_CONNECT_ACKNOWLEDGE);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- newl3state(pc, 10);
- L3DelTimer(&pc->timer);
- if (ret)
- l3ni1_std_ie_err(pc, ret);
- pc->st->l3.l3l4(pc->st, CC_SETUP_COMPL | INDICATION, pc);
- }
- static void
- l3ni1_reject_req(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb;
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- u_char cause = 21;
- if (pc->para.cause != NO_CAUSE)
- cause = pc->para.cause;
- MsgHead(p, pc->callref, MT_RELEASE_COMPLETE);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- ni1_release_l3_process(pc);
- }
- static void
- l3ni1_release(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- u_char *p;
- int ret, cause = 0;
- StopAllL3Timer(pc);
- if ((ret = l3ni1_get_cause(pc, skb)) > 0) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "REL get_cause ret(%d)", ret);
- } else if (ret < 0)
- pc->para.cause = NO_CAUSE;
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
- l3ni1_parse_facility(pc->st, pc, pc->callref, p);
- }
- if ((ret < 0) && (pc->state != 11))
- cause = 96;
- else if (ret > 0)
- cause = 100;
- ret = check_infoelements(pc, skb, ie_RELEASE);
- if (ERR_IE_COMPREHENSION == ret)
- cause = 96;
- else if ((ERR_IE_UNRECOGNIZED == ret) && (!cause))
- cause = 99;
- if (cause)
- l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, cause);
- else
- l3ni1_message(pc, MT_RELEASE_COMPLETE);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- ni1_release_l3_process(pc);
- }
- static void
- l3ni1_alert_req(struct l3_process *pc, u_char pr,
- void *arg)
- {
- newl3state(pc, 7);
- if (!pc->prot.ni1.uus1_data[0])
- l3ni1_message(pc, MT_ALERTING);
- else
- l3ni1_msg_with_uus(pc, MT_ALERTING);
- }
- static void
- l3ni1_proceed_req(struct l3_process *pc, u_char pr,
- void *arg)
- {
- newl3state(pc, 9);
- l3ni1_message(pc, MT_CALL_PROCEEDING);
- pc->st->l3.l3l4(pc->st, CC_PROCEED_SEND | INDICATION, pc);
- }
- static void
- l3ni1_setup_ack_req(struct l3_process *pc, u_char pr,
- void *arg)
- {
- newl3state(pc, 25);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T302, CC_T302);
- l3ni1_message(pc, MT_SETUP_ACKNOWLEDGE);
- }
- /********************************************/
- /* deliver a incoming display message to HL */
- /********************************************/
- static void
- l3ni1_deliver_display(struct l3_process *pc, int pr, u_char *infp)
- { u_char len;
- isdn_ctrl ic;
- struct IsdnCardState *cs;
- char *p;
- if (*infp++ != IE_DISPLAY) return;
- if ((len = *infp++) > 80) return; /* total length <= 82 */
- if (!pc->chan) return;
- p = ic.parm.display;
- while (len--)
- *p++ = *infp++;
- *p = '\0';
- ic.command = ISDN_STAT_DISPLAY;
- cs = pc->st->l1.hardware;
- ic.driver = cs->myid;
- ic.arg = pc->chan->chan;
- cs->iif.statcallb(&ic);
- } /* l3ni1_deliver_display */
- static void
- l3ni1_progress(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int err = 0;
- u_char *p;
- if ((p = findie(skb->data, skb->len, IE_PROGRESS, 0))) {
- if (p[1] != 2) {
- err = 1;
- pc->para.cause = 100;
- } else if (!(p[2] & 0x70)) {
- switch (p[2]) {
- case 0x80:
- case 0x81:
- case 0x82:
- case 0x84:
- case 0x85:
- case 0x87:
- case 0x8a:
- switch (p[3]) {
- case 0x81:
- case 0x82:
- case 0x83:
- case 0x84:
- case 0x88:
- break;
- default:
- err = 2;
- pc->para.cause = 100;
- break;
- }
- break;
- default:
- err = 3;
- pc->para.cause = 100;
- break;
- }
- }
- } else {
- pc->para.cause = 96;
- err = 4;
- }
- if (err) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "progress error %d", err);
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- err = check_infoelements(pc, skb, ie_PROGRESS);
- if (err)
- l3ni1_std_ie_err(pc, err);
- if (ERR_IE_COMPREHENSION != err)
- pc->st->l3.l3l4(pc->st, CC_PROGRESS | INDICATION, pc);
- }
- static void
- l3ni1_notify(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int err = 0;
- u_char *p;
- if ((p = findie(skb->data, skb->len, IE_NOTIFY, 0))) {
- if (p[1] != 1) {
- err = 1;
- pc->para.cause = 100;
- } else {
- switch (p[2]) {
- case 0x80:
- case 0x81:
- case 0x82:
- break;
- default:
- pc->para.cause = 100;
- err = 2;
- break;
- }
- }
- } else {
- pc->para.cause = 96;
- err = 3;
- }
- if (err) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "notify error %d", err);
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- /* Now we are on none mandatory IEs */
- err = check_infoelements(pc, skb, ie_NOTIFY);
- if (err)
- l3ni1_std_ie_err(pc, err);
- if (ERR_IE_COMPREHENSION != err)
- pc->st->l3.l3l4(pc->st, CC_NOTIFY | INDICATION, pc);
- }
- static void
- l3ni1_status_enq(struct l3_process *pc, u_char pr, void *arg)
- {
- int ret;
- struct sk_buff *skb = arg;
- ret = check_infoelements(pc, skb, ie_STATUS_ENQUIRY);
- l3ni1_std_ie_err(pc, ret);
- pc->para.cause = 30; /* response to STATUS_ENQUIRY */
- l3ni1_status_send(pc, pr, NULL);
- }
- static void
- l3ni1_information(struct l3_process *pc, u_char pr, void *arg)
- {
- int ret;
- struct sk_buff *skb = arg;
- u_char *p;
- char tmp[32];
- ret = check_infoelements(pc, skb, ie_INFORMATION);
- if (ret)
- l3ni1_std_ie_err(pc, ret);
- if (pc->state == 25) { /* overlap receiving */
- L3DelTimer(&pc->timer);
- p = skb->data;
- if ((p = findie(p, skb->len, 0x70, 0))) {
- iecpy(tmp, p, 1);
- strcat(pc->para.setup.eazmsn, tmp);
- pc->st->l3.l3l4(pc->st, CC_MORE_INFO | INDICATION, pc);
- }
- L3AddTimer(&pc->timer, T302, CC_T302);
- }
- }
- /******************************/
- /* handle deflection requests */
- /******************************/
- static void l3ni1_redir_req(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb;
- u_char tmp[128];
- u_char *p = tmp;
- u_char *subp;
- u_char len_phone = 0;
- u_char len_sub = 0;
- int l;
- strcpy(pc->prot.ni1.uus1_data, pc->chan->setup.eazmsn); /* copy uus element if available */
- if (!pc->chan->setup.phone[0])
- { pc->para.cause = -1;
- l3ni1_disconnect_req(pc, pr, arg); /* disconnect immediately */
- return;
- } /* only uus */
- if (pc->prot.ni1.invoke_id)
- free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
- if (!(pc->prot.ni1.invoke_id = new_invoke_id(pc->st)))
- return;
- MsgHead(p, pc->callref, MT_FACILITY);
- for (subp = pc->chan->setup.phone; (*subp) && (*subp != '.'); subp++) len_phone++; /* len of phone number */
- if (*subp++ == '.') len_sub = strlen(subp) + 2; /* length including info subaddress element */
- *p++ = 0x1c; /* Facility info element */
- *p++ = len_phone + len_sub + 2 + 2 + 8 + 3 + 3; /* length of element */
- *p++ = 0x91; /* remote operations protocol */
- *p++ = 0xa1; /* invoke component */
- *p++ = len_phone + len_sub + 2 + 2 + 8 + 3; /* length of data */
- *p++ = 0x02; /* invoke id tag, integer */
- *p++ = 0x01; /* length */
- *p++ = pc->prot.ni1.invoke_id; /* invoke id */
- *p++ = 0x02; /* operation value tag, integer */
- *p++ = 0x01; /* length */
- *p++ = 0x0D; /* Call Deflect */
- *p++ = 0x30; /* sequence phone number */
- *p++ = len_phone + 2 + 2 + 3 + len_sub; /* length */
- *p++ = 0x30; /* Deflected to UserNumber */
- *p++ = len_phone + 2 + len_sub; /* length */
- *p++ = 0x80; /* NumberDigits */
- *p++ = len_phone; /* length */
- for (l = 0; l < len_phone; l++)
- *p++ = pc->chan->setup.phone[l];
- if (len_sub)
- { *p++ = 0x04; /* called party subaddress */
- *p++ = len_sub - 2;
- while (*subp) *p++ = *subp++;
- }
- *p++ = 0x01; /* screening identifier */
- *p++ = 0x01;
- *p++ = pc->chan->setup.screen;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l))) return;
- memcpy(skb_put(skb, l), tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- } /* l3ni1_redir_req */
- /********************************************/
- /* handle deflection request in early state */
- /********************************************/
- static void l3ni1_redir_req_early(struct l3_process *pc, u_char pr, void *arg)
- {
- l3ni1_proceed_req(pc, pr, arg);
- l3ni1_redir_req(pc, pr, arg);
- } /* l3ni1_redir_req_early */
- /***********************************************/
- /* handle special commands for this protocol. */
- /* Examples are call independent services like */
- /* remote operations with dummy callref. */
- /***********************************************/
- static int l3ni1_cmd_global(struct PStack *st, isdn_ctrl *ic)
- { u_char id;
- u_char temp[265];
- u_char *p = temp;
- int i, l, proc_len;
- struct sk_buff *skb;
- struct l3_process *pc = NULL;
- switch (ic->arg)
- { case NI1_CMD_INVOKE:
- if (ic->parm.ni1_io.datalen < 0) return (-2); /* invalid parameter */
- for (proc_len = 1, i = ic->parm.ni1_io.proc >> 8; i; i++)
- i = i >> 8; /* add one byte */
- l = ic->parm.ni1_io.datalen + proc_len + 8; /* length excluding ie header */
- if (l > 255)
- return (-2); /* too long */
- if (!(id = new_invoke_id(st)))
- return (0); /* first get a invoke id -> return if no available */
- i = -1;
- MsgHead(p, i, MT_FACILITY); /* build message head */
- *p++ = 0x1C; /* Facility IE */
- *p++ = l; /* length of ie */
- *p++ = 0x91; /* remote operations */
- *p++ = 0xA1; /* invoke */
- *p++ = l - 3; /* length of invoke */
- *p++ = 0x02; /* invoke id tag */
- *p++ = 0x01; /* length is 1 */
- *p++ = id; /* invoke id */
- *p++ = 0x02; /* operation */
- *p++ = proc_len; /* length of operation */
- for (i = proc_len; i; i--)
- *p++ = (ic->parm.ni1_io.proc >> (i - 1)) & 0xFF;
- memcpy(p, ic->parm.ni1_io.data, ic->parm.ni1_io.datalen); /* copy data */
- l = (p - temp) + ic->parm.ni1_io.datalen; /* total length */
- if (ic->parm.ni1_io.timeout > 0) {
- pc = ni1_new_l3_process(st, -1);
- if (!pc) {
- free_invoke_id(st, id);
- return (-2);
- }
- /* remember id */
- pc->prot.ni1.ll_id = ic->parm.ni1_io.ll_id;
- /* and procedure */
- pc->prot.ni1.proc = ic->parm.ni1_io.proc;
- }
- if (!(skb = l3_alloc_skb(l)))
- { free_invoke_id(st, id);
- if (pc) ni1_release_l3_process(pc);
- return (-2);
- }
- memcpy(skb_put(skb, l), temp, l);
- if (pc)
- { pc->prot.ni1.invoke_id = id; /* remember id */
- L3AddTimer(&pc->timer, ic->parm.ni1_io.timeout, CC_TNI1_IO | REQUEST);
- }
- l3_msg(st, DL_DATA | REQUEST, skb);
- ic->parm.ni1_io.hl_id = id; /* return id */
- return (0);
- case NI1_CMD_INVOKE_ABORT:
- if ((pc = l3ni1_search_dummy_proc(st, ic->parm.ni1_io.hl_id)))
- { L3DelTimer(&pc->timer); /* remove timer */
- ni1_release_l3_process(pc);
- return (0);
- }
- else
- { l3_debug(st, "l3ni1_cmd_global abort unknown id");
- return (-2);
- }
- break;
- default:
- l3_debug(st, "l3ni1_cmd_global unknown cmd 0x%lx", ic->arg);
- return (-1);
- } /* switch ic-> arg */
- return (-1);
- } /* l3ni1_cmd_global */
- static void
- l3ni1_io_timer(struct l3_process *pc)
- { isdn_ctrl ic;
- struct IsdnCardState *cs = pc->st->l1.hardware;
- L3DelTimer(&pc->timer); /* remove timer */
- ic.driver = cs->myid;
- ic.command = ISDN_STAT_PROT;
- ic.arg = NI1_STAT_INVOKE_ERR;
- ic.parm.ni1_io.hl_id = pc->prot.ni1.invoke_id;
- ic.parm.ni1_io.ll_id = pc->prot.ni1.ll_id;
- ic.parm.ni1_io.proc = pc->prot.ni1.proc;
- ic.parm.ni1_io.timeout = -1;
- ic.parm.ni1_io.datalen = 0;
- ic.parm.ni1_io.data = NULL;
- free_invoke_id(pc->st, pc->prot.ni1.invoke_id);
- pc->prot.ni1.invoke_id = 0; /* reset id */
- cs->iif.statcallb(&ic);
- ni1_release_l3_process(pc);
- } /* l3ni1_io_timer */
- static void
- l3ni1_release_ind(struct l3_process *pc, u_char pr, void *arg)
- {
- u_char *p;
- struct sk_buff *skb = arg;
- int callState = 0;
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CALL_STATE, 0))) {
- p++;
- if (1 == *p++)
- callState = *p;
- }
- if (callState == 0) {
- /* ETS 300-104 7.6.1, 8.6.1, 10.6.1... and 16.1
- * set down layer 3 without sending any message
- */
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- ni1_release_l3_process(pc);
- } else {
- pc->st->l3.l3l4(pc->st, CC_IGNORE | INDICATION, pc);
- }
- }
- static void
- l3ni1_dummy(struct l3_process *pc, u_char pr, void *arg)
- {
- }
- static void
- l3ni1_t302(struct l3_process *pc, u_char pr, void *arg)
- {
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 28; /* invalid number */
- l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
- }
- static void
- l3ni1_t303(struct l3_process *pc, u_char pr, void *arg)
- {
- if (pc->N303 > 0) {
- pc->N303--;
- L3DelTimer(&pc->timer);
- l3ni1_setup_req(pc, pr, arg);
- } else {
- L3DelTimer(&pc->timer);
- l3ni1_message_cause(pc, MT_RELEASE_COMPLETE, 102);
- pc->st->l3.l3l4(pc->st, CC_NOSETUP_RSP, pc);
- ni1_release_l3_process(pc);
- }
- }
- static void
- l3ni1_t304(struct l3_process *pc, u_char pr, void *arg)
- {
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 102;
- l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
- }
- static void
- l3ni1_t305(struct l3_process *pc, u_char pr, void *arg)
- {
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- struct sk_buff *skb;
- u_char cause = 16;
- L3DelTimer(&pc->timer);
- if (pc->para.cause != NO_CAUSE)
- cause = pc->para.cause;
- MsgHead(p, pc->callref, MT_RELEASE);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = cause | 0x80;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- newl3state(pc, 19);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
- }
- static void
- l3ni1_t310(struct l3_process *pc, u_char pr, void *arg)
- {
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 102;
- l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
- }
- static void
- l3ni1_t313(struct l3_process *pc, u_char pr, void *arg)
- {
- L3DelTimer(&pc->timer);
- pc->para.loc = 0;
- pc->para.cause = 102;
- l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_CONNECT_ERR, pc);
- }
- static void
- l3ni1_t308_1(struct l3_process *pc, u_char pr, void *arg)
- {
- newl3state(pc, 19);
- L3DelTimer(&pc->timer);
- l3ni1_message(pc, MT_RELEASE);
- L3AddTimer(&pc->timer, T308, CC_T308_2);
- }
- static void
- l3ni1_t308_2(struct l3_process *pc, u_char pr, void *arg)
- {
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE_ERR, pc);
- ni1_release_l3_process(pc);
- }
- static void
- l3ni1_t318(struct l3_process *pc, u_char pr, void *arg)
- {
- L3DelTimer(&pc->timer);
- pc->para.cause = 102; /* Timer expiry */
- pc->para.loc = 0; /* local */
- pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
- newl3state(pc, 19);
- l3ni1_message(pc, MT_RELEASE);
- L3AddTimer(&pc->timer, T308, CC_T308_1);
- }
- static void
- l3ni1_t319(struct l3_process *pc, u_char pr, void *arg)
- {
- L3DelTimer(&pc->timer);
- pc->para.cause = 102; /* Timer expiry */
- pc->para.loc = 0; /* local */
- pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
- newl3state(pc, 10);
- }
- static void
- l3ni1_restart(struct l3_process *pc, u_char pr, void *arg)
- {
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- ni1_release_l3_process(pc);
- }
- static void
- l3ni1_status(struct l3_process *pc, u_char pr, void *arg)
- {
- u_char *p;
- struct sk_buff *skb = arg;
- int ret;
- u_char cause = 0, callState = 0;
- if ((ret = l3ni1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "STATUS get_cause ret(%d)", ret);
- if (ret < 0)
- cause = 96;
- else if (ret > 0)
- cause = 100;
- }
- if ((p = findie(skb->data, skb->len, IE_CALL_STATE, 0))) {
- p++;
- if (1 == *p++) {
- callState = *p;
- if (!ie_in_set(pc, *p, l3_valid_states))
- cause = 100;
- } else
- cause = 100;
- } else
- cause = 96;
- if (!cause) { /* no error before */
- ret = check_infoelements(pc, skb, ie_STATUS);
- if (ERR_IE_COMPREHENSION == ret)
- cause = 96;
- else if (ERR_IE_UNRECOGNIZED == ret)
- cause = 99;
- }
- if (cause) {
- u_char tmp;
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "STATUS error(%d/%d)", ret, cause);
- tmp = pc->para.cause;
- pc->para.cause = cause;
- l3ni1_status_send(pc, 0, NULL);
- if (cause == 99)
- pc->para.cause = tmp;
- else
- return;
- }
- cause = pc->para.cause;
- if (((cause & 0x7f) == 111) && (callState == 0)) {
- /* ETS 300-104 7.6.1, 8.6.1, 10.6.1...
- * if received MT_STATUS with cause == 111 and call
- * state == 0, then we must set down layer 3
- */
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- newl3state(pc, 0);
- ni1_release_l3_process(pc);
- }
- }
- static void
- l3ni1_facility(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int ret;
- ret = check_infoelements(pc, skb, ie_FACILITY);
- l3ni1_std_ie_err(pc, ret);
- {
- u_char *p;
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0)))
- l3ni1_parse_facility(pc->st, pc, pc->callref, p);
- }
- }
- static void
- l3ni1_suspend_req(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb;
- u_char tmp[32];
- u_char *p = tmp;
- u_char i, l;
- u_char *msg = pc->chan->setup.phone;
- MsgHead(p, pc->callref, MT_SUSPEND);
- l = *msg++;
- if (l && (l <= 10)) { /* Max length 10 octets */
- *p++ = IE_CALL_ID;
- *p++ = l;
- for (i = 0; i < l; i++)
- *p++ = *msg++;
- } else if (l) {
- l3_debug(pc->st, "SUS wrong CALL_ID len %d", l);
- return;
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- newl3state(pc, 15);
- L3AddTimer(&pc->timer, T319, CC_T319);
- }
- static void
- l3ni1_suspend_ack(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int ret;
- L3DelTimer(&pc->timer);
- newl3state(pc, 0);
- pc->para.cause = NO_CAUSE;
- pc->st->l3.l3l4(pc->st, CC_SUSPEND | CONFIRM, pc);
- /* We don't handle suspend_ack for IE errors now */
- if ((ret = check_infoelements(pc, skb, ie_SUSPEND_ACKNOWLEDGE)))
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "SUSPACK check ie(%d)", ret);
- ni1_release_l3_process(pc);
- }
- static void
- l3ni1_suspend_rej(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int ret;
- if ((ret = l3ni1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "SUSP_REJ get_cause ret(%d)", ret);
- if (ret < 0)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- ret = check_infoelements(pc, skb, ie_SUSPEND_REJECT);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_SUSPEND_ERR, pc);
- newl3state(pc, 10);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, ret);
- }
- static void
- l3ni1_resume_req(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb;
- u_char tmp[32];
- u_char *p = tmp;
- u_char i, l;
- u_char *msg = pc->para.setup.phone;
- MsgHead(p, pc->callref, MT_RESUME);
- l = *msg++;
- if (l && (l <= 10)) { /* Max length 10 octets */
- *p++ = IE_CALL_ID;
- *p++ = l;
- for (i = 0; i < l; i++)
- *p++ = *msg++;
- } else if (l) {
- l3_debug(pc->st, "RES wrong CALL_ID len %d", l);
- return;
- }
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- newl3state(pc, 17);
- L3AddTimer(&pc->timer, T318, CC_T318);
- }
- static void
- l3ni1_resume_ack(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int id, ret;
- if ((id = l3ni1_get_channel_id(pc, skb)) > 0) {
- if ((0 == id) || ((3 == id) && (0x10 == pc->para.moderate))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "resume ack with wrong chid %x", id);
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- pc->para.bchannel = id;
- } else if (1 == pc->state) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "resume ack without chid (ret %d)", id);
- pc->para.cause = 96;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- ret = check_infoelements(pc, skb, ie_RESUME_ACKNOWLEDGE);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RESUME | CONFIRM, pc);
- newl3state(pc, 10);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, ret);
- }
- static void
- l3ni1_resume_rej(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- int ret;
- if ((ret = l3ni1_get_cause(pc, skb))) {
- if (pc->debug & L3_DEB_WARN)
- l3_debug(pc->st, "RES_REJ get_cause ret(%d)", ret);
- if (ret < 0)
- pc->para.cause = 96;
- else
- pc->para.cause = 100;
- l3ni1_status_send(pc, pr, NULL);
- return;
- }
- ret = check_infoelements(pc, skb, ie_RESUME_REJECT);
- if (ERR_IE_COMPREHENSION == ret) {
- l3ni1_std_ie_err(pc, ret);
- return;
- }
- L3DelTimer(&pc->timer);
- pc->st->l3.l3l4(pc->st, CC_RESUME_ERR, pc);
- newl3state(pc, 0);
- if (ret) /* STATUS for none mandatory IE errors after actions are taken */
- l3ni1_std_ie_err(pc, ret);
- ni1_release_l3_process(pc);
- }
- static void
- l3ni1_global_restart(struct l3_process *pc, u_char pr, void *arg)
- {
- u_char tmp[32];
- u_char *p;
- u_char ri, ch = 0, chan = 0;
- int l;
- struct sk_buff *skb = arg;
- struct l3_process *up;
- newl3state(pc, 2);
- L3DelTimer(&pc->timer);
- p = skb->data;
- if ((p = findie(p, skb->len, IE_RESTART_IND, 0))) {
- ri = p[2];
- l3_debug(pc->st, "Restart %x", ri);
- } else {
- l3_debug(pc->st, "Restart without restart IE");
- ri = 0x86;
- }
- p = skb->data;
- if ((p = findie(p, skb->len, IE_CHANNEL_ID, 0))) {
- chan = p[2] & 3;
- ch = p[2];
- if (pc->st->l3.debug)
- l3_debug(pc->st, "Restart for channel %d", chan);
- }
- newl3state(pc, 2);
- up = pc->st->l3.proc;
- while (up) {
- if ((ri & 7) == 7)
- up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
- else if (up->para.bchannel == chan)
- up->st->lli.l4l3(up->st, CC_RESTART | REQUEST, up);
- up = up->next;
- }
- p = tmp;
- MsgHead(p, pc->callref, MT_RESTART_ACKNOWLEDGE);
- if (chan) {
- *p++ = IE_CHANNEL_ID;
- *p++ = 1;
- *p++ = ch | 0x80;
- }
- *p++ = 0x79; /* RESTART Ind */
- *p++ = 1;
- *p++ = ri;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- newl3state(pc, 0);
- l3_msg(pc->st, DL_DATA | REQUEST, skb);
- }
- static void
- l3ni1_dl_reset(struct l3_process *pc, u_char pr, void *arg)
- {
- pc->para.cause = 0x29; /* Temporary failure */
- pc->para.loc = 0;
- l3ni1_disconnect_req(pc, pr, NULL);
- pc->st->l3.l3l4(pc->st, CC_SETUP_ERR, pc);
- }
- static void
- l3ni1_dl_release(struct l3_process *pc, u_char pr, void *arg)
- {
- newl3state(pc, 0);
- pc->para.cause = 0x1b; /* Destination out of order */
- pc->para.loc = 0;
- pc->st->l3.l3l4(pc->st, CC_RELEASE | INDICATION, pc);
- release_l3_process(pc);
- }
- static void
- l3ni1_dl_reestablish(struct l3_process *pc, u_char pr, void *arg)
- {
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, T309, CC_T309);
- l3_msg(pc->st, DL_ESTABLISH | REQUEST, NULL);
- }
- static void
- l3ni1_dl_reest_status(struct l3_process *pc, u_char pr, void *arg)
- {
- L3DelTimer(&pc->timer);
- pc->para.cause = 0x1F; /* normal, unspecified */
- l3ni1_status_send(pc, 0, NULL);
- }
- static void l3ni1_SendSpid(struct l3_process *pc, u_char pr, struct sk_buff *skb, int iNewState)
- {
- u_char *p;
- char *pSPID;
- struct Channel *pChan = pc->st->lli.userdata;
- int l;
- if (skb)
- dev_kfree_skb(skb);
- if (!(pSPID = strchr(pChan->setup.eazmsn, ':')))
- {
- printk(KERN_ERR "SPID not supplied in EAZMSN %s\n", pChan->setup.eazmsn);
- newl3state(pc, 0);
- pc->st->l3.l3l2(pc->st, DL_RELEASE | REQUEST, NULL);
- return;
- }
- l = strlen(++pSPID);
- if (!(skb = l3_alloc_skb(5 + l)))
- {
- printk(KERN_ERR "HiSax can't get memory to send SPID\n");
- return;
- }
- p = skb_put(skb, 5);
- *p++ = PROTO_DIS_EURO;
- *p++ = 0;
- *p++ = MT_INFORMATION;
- *p++ = IE_SPID;
- *p++ = l;
- memcpy(skb_put(skb, l), pSPID, l);
- newl3state(pc, iNewState);
- L3DelTimer(&pc->timer);
- L3AddTimer(&pc->timer, TSPID, CC_TSPID);
- pc->st->l3.l3l2(pc->st, DL_DATA | REQUEST, skb);
- }
- static void l3ni1_spid_send(struct l3_process *pc, u_char pr, void *arg)
- {
- l3ni1_SendSpid(pc, pr, arg, 20);
- }
- static void l3ni1_spid_epid(struct l3_process *pc, u_char pr, void *arg)
- {
- struct sk_buff *skb = arg;
- if (skb->data[1] == 0)
- if (skb->data[3] == IE_ENDPOINT_ID)
- {
- L3DelTimer(&pc->timer);
- newl3state(pc, 0);
- l3_msg(pc->st, DL_ESTABLISH | CONFIRM, NULL);
- }
- dev_kfree_skb(skb);
- }
- static void l3ni1_spid_tout(struct l3_process *pc, u_char pr, void *arg)
- {
- if (pc->state < 22)
- l3ni1_SendSpid(pc, pr, arg, pc->state + 1);
- else
- {
- L3DelTimer(&pc->timer);
- dev_kfree_skb(arg);
- printk(KERN_ERR "SPID not accepted\n");
- newl3state(pc, 0);
- pc->st->l3.l3l2(pc->st, DL_RELEASE | REQUEST, NULL);
- }
- }
- /* *INDENT-OFF* */
- static struct stateentry downstatelist[] =
- {
- {SBIT(0),
- CC_SETUP | REQUEST, l3ni1_setup_req},
- {SBIT(0),
- CC_RESUME | REQUEST, l3ni1_resume_req},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(25),
- CC_DISCONNECT | REQUEST, l3ni1_disconnect_req},
- {SBIT(12),
- CC_RELEASE | REQUEST, l3ni1_release_req},
- {ALL_STATES,
- CC_RESTART | REQUEST, l3ni1_restart},
- {SBIT(6) | SBIT(25),
- CC_IGNORE | REQUEST, l3ni1_reset},
- {SBIT(6) | SBIT(25),
- CC_REJECT | REQUEST, l3ni1_reject_req},
- {SBIT(6) | SBIT(25),
- CC_PROCEED_SEND | REQUEST, l3ni1_proceed_req},
- {SBIT(6),
- CC_MORE_INFO | REQUEST, l3ni1_setup_ack_req},
- {SBIT(25),
- CC_MORE_INFO | REQUEST, l3ni1_dummy},
- {SBIT(6) | SBIT(9) | SBIT(25),
- CC_ALERTING | REQUEST, l3ni1_alert_req},
- {SBIT(6) | SBIT(7) | SBIT(9) | SBIT(25),
- CC_SETUP | RESPONSE, l3ni1_setup_rsp},
- {SBIT(10),
- CC_SUSPEND | REQUEST, l3ni1_suspend_req},
- {SBIT(7) | SBIT(9) | SBIT(25),
- CC_REDIR | REQUEST, l3ni1_redir_req},
- {SBIT(6),
- CC_REDIR | REQUEST, l3ni1_redir_req_early},
- {SBIT(9) | SBIT(25),
- CC_DISCONNECT | REQUEST, l3ni1_disconnect_req},
- {SBIT(25),
- CC_T302, l3ni1_t302},
- {SBIT(1),
- CC_T303, l3ni1_t303},
- {SBIT(2),
- CC_T304, l3ni1_t304},
- {SBIT(3),
- CC_T310, l3ni1_t310},
- {SBIT(8),
- CC_T313, l3ni1_t313},
- {SBIT(11),
- CC_T305, l3ni1_t305},
- {SBIT(15),
- CC_T319, l3ni1_t319},
- {SBIT(17),
- CC_T318, l3ni1_t318},
- {SBIT(19),
- CC_T308_1, l3ni1_t308_1},
- {SBIT(19),
- CC_T308_2, l3ni1_t308_2},
- {SBIT(10),
- CC_T309, l3ni1_dl_release},
- { SBIT(20) | SBIT(21) | SBIT(22),
- CC_TSPID, l3ni1_spid_tout },
- };
- static struct stateentry datastatelist[] =
- {
- {ALL_STATES,
- MT_STATUS_ENQUIRY, l3ni1_status_enq},
- {ALL_STATES,
- MT_FACILITY, l3ni1_facility},
- {SBIT(19),
- MT_STATUS, l3ni1_release_ind},
- {ALL_STATES,
- MT_STATUS, l3ni1_status},
- {SBIT(0),
- MT_SETUP, l3ni1_setup},
- {SBIT(6) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(12) |
- SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
- MT_SETUP, l3ni1_dummy},
- {SBIT(1) | SBIT(2),
- MT_CALL_PROCEEDING, l3ni1_call_proc},
- {SBIT(1),
- MT_SETUP_ACKNOWLEDGE, l3ni1_setup_ack},
- {SBIT(2) | SBIT(3),
- MT_ALERTING, l3ni1_alerting},
- {SBIT(2) | SBIT(3),
- MT_PROGRESS, l3ni1_progress},
- {SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) |
- SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
- MT_INFORMATION, l3ni1_information},
- {SBIT(10) | SBIT(11) | SBIT(15),
- MT_NOTIFY, l3ni1_notify},
- {SBIT(0) | SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(10) |
- SBIT(11) | SBIT(12) | SBIT(15) | SBIT(17) | SBIT(19) | SBIT(25),
- MT_RELEASE_COMPLETE, l3ni1_release_cmpl},
- {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),
- MT_RELEASE, l3ni1_release},
- {SBIT(19), MT_RELEASE, l3ni1_release_ind},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4) | SBIT(7) | SBIT(8) | SBIT(9) | SBIT(10) | SBIT(11) | SBIT(15) | SBIT(17) | SBIT(25),
- MT_DISCONNECT, l3ni1_disconnect},
- {SBIT(19),
- MT_DISCONNECT, l3ni1_dummy},
- {SBIT(1) | SBIT(2) | SBIT(3) | SBIT(4),
- MT_CONNECT, l3ni1_connect},
- {SBIT(8),
- MT_CONNECT_ACKNOWLEDGE, l3ni1_connect_ack},
- {SBIT(15),
- MT_SUSPEND_ACKNOWLEDGE, l3ni1_suspend_ack},
- {SBIT(15),
- MT_SUSPEND_REJECT, l3ni1_suspend_rej},
- {SBIT(17),
- MT_RESUME_ACKNOWLEDGE, l3ni1_resume_ack},
- {SBIT(17),
- MT_RESUME_REJECT, l3ni1_resume_rej},
- };
- static struct stateentry globalmes_list[] =
- {
- {ALL_STATES,
- MT_STATUS, l3ni1_status},
- {SBIT(0),
- MT_RESTART, l3ni1_global_restart},
- /* {SBIT(1),
- MT_RESTART_ACKNOWLEDGE, l3ni1_restart_ack},
- */
- { SBIT(0), MT_DL_ESTABLISHED, l3ni1_spid_send },
- { SBIT(20) | SBIT(21) | SBIT(22), MT_INFORMATION, l3ni1_spid_epid },
- };
- static struct stateentry manstatelist[] =
- {
- {SBIT(2),
- DL_ESTABLISH | INDICATION, l3ni1_dl_reset},
- {SBIT(10),
- DL_ESTABLISH | CONFIRM, l3ni1_dl_reest_status},
- {SBIT(10),
- DL_RELEASE | INDICATION, l3ni1_dl_reestablish},
- {ALL_STATES,
- DL_RELEASE | INDICATION, l3ni1_dl_release},
- };
- /* *INDENT-ON* */
- static void
- global_handler(struct PStack *st, int mt, struct sk_buff *skb)
- {
- u_char tmp[16];
- u_char *p = tmp;
- int l;
- int i;
- struct l3_process *proc = st->l3.global;
- if (skb)
- proc->callref = skb->data[2]; /* cr flag */
- else
- proc->callref = 0;
- for (i = 0; i < ARRAY_SIZE(globalmes_list); i++)
- if ((mt == globalmes_list[i].primitive) &&
- ((1 << proc->state) & globalmes_list[i].state))
- break;
- if (i == ARRAY_SIZE(globalmes_list)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1 global state %d mt %x unhandled",
- proc->state, mt);
- }
- MsgHead(p, proc->callref, MT_STATUS);
- *p++ = IE_CAUSE;
- *p++ = 0x2;
- *p++ = 0x80;
- *p++ = 81 | 0x80; /* invalid cr */
- *p++ = 0x14; /* CallState */
- *p++ = 0x1;
- *p++ = proc->state & 0x3f;
- l = p - tmp;
- if (!(skb = l3_alloc_skb(l)))
- return;
- memcpy(skb_put(skb, l), tmp, l);
- l3_msg(proc->st, DL_DATA | REQUEST, skb);
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1 global %d mt %x",
- proc->state, mt);
- }
- globalmes_list[i].rout(proc, mt, skb);
- }
- }
- static void
- ni1up(struct PStack *st, int pr, void *arg)
- {
- int i, mt, cr, callState;
- char *ptr;
- u_char *p;
- struct sk_buff *skb = arg;
- struct l3_process *proc;
- switch (pr) {
- case (DL_DATA | INDICATION):
- case (DL_UNIT_DATA | INDICATION):
- break;
- case (DL_ESTABLISH | INDICATION):
- case (DL_RELEASE | INDICATION):
- case (DL_RELEASE | CONFIRM):
- l3_msg(st, pr, arg);
- return;
- break;
- case (DL_ESTABLISH | CONFIRM):
- global_handler(st, MT_DL_ESTABLISHED, NULL);
- return;
- default:
- printk(KERN_ERR "HiSax ni1up unknown pr=%04x\n", pr);
- return;
- }
- if (skb->len < 3) {
- l3_debug(st, "ni1up frame too short(%d)", skb->len);
- dev_kfree_skb(skb);
- return;
- }
- if (skb->data[0] != PROTO_DIS_EURO) {
- if (st->l3.debug & L3_DEB_PROTERR) {
- l3_debug(st, "ni1up%sunexpected discriminator %x message len %d",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- skb->data[0], skb->len);
- }
- dev_kfree_skb(skb);
- return;
- }
- cr = getcallref(skb->data);
- if (skb->len < ((skb->data[1] & 0x0f) + 3)) {
- l3_debug(st, "ni1up frame too short(%d)", skb->len);
- dev_kfree_skb(skb);
- return;
- }
- mt = skb->data[skb->data[1] + 2];
- if (st->l3.debug & L3_DEB_STATE)
- l3_debug(st, "ni1up cr %d", cr);
- if (cr == -2) { /* wrong Callref */
- if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "ni1up wrong Callref");
- dev_kfree_skb(skb);
- return;
- } else if (cr == -1) { /* Dummy Callref */
- if (mt == MT_FACILITY)
- {
- if ((p = findie(skb->data, skb->len, IE_FACILITY, 0))) {
- l3ni1_parse_facility(st, NULL,
- (pr == (DL_DATA | INDICATION)) ? -1 : -2, p);
- dev_kfree_skb(skb);
- return;
- }
- }
- else
- {
- global_handler(st, mt, skb);
- return;
- }
- if (st->l3.debug & L3_DEB_WARN)
- l3_debug(st, "ni1up dummy Callref (no facility msg or ie)");
- dev_kfree_skb(skb);
- return;
- } else if ((((skb->data[1] & 0x0f) == 1) && (0 == (cr & 0x7f))) ||
- (((skb->data[1] & 0x0f) == 2) && (0 == (cr & 0x7fff)))) { /* Global CallRef */
- if (st->l3.debug & L3_DEB_STATE)
- l3_debug(st, "ni1up Global CallRef");
- global_handler(st, mt, skb);
- dev_kfree_skb(skb);
- return;
- } else if (!(proc = getl3proc(st, cr))) {
- /* No transaction process exist, that means no call with
- * this callreference is active
- */
- if (mt == MT_SETUP) {
- /* Setup creates a new transaction process */
- if (skb->data[2] & 0x80) {
- /* Setup with wrong CREF flag */
- if (st->l3.debug & L3_DEB_STATE)
- l3_debug(st, "ni1up wrong CRef flag");
- dev_kfree_skb(skb);
- return;
- }
- if (!(proc = ni1_new_l3_process(st, cr))) {
- /* May be to answer with RELEASE_COMPLETE and
- * CAUSE 0x2f "Resource unavailable", but this
- * need a new_l3_process too ... arghh
- */
- dev_kfree_skb(skb);
- return;
- }
- } else if (mt == MT_STATUS) {
- if ((ptr = findie(skb->data, skb->len, IE_CAUSE, 0)) != NULL) {
- ptr++;
- if (*ptr++ == 2)
- ptr++;
- }
- callState = 0;
- if ((ptr = findie(skb->data, skb->len, IE_CALL_STATE, 0)) != NULL) {
- ptr++;
- if (*ptr++ == 2)
- ptr++;
- callState = *ptr;
- }
- /* ETS 300-104 part 2.4.1
- * if setup has not been made and a message type
- * MT_STATUS is received with call state == 0,
- * we must send nothing
- */
- if (callState != 0) {
- /* ETS 300-104 part 2.4.2
- * if setup has not been made and a message type
- * MT_STATUS is received with call state != 0,
- * we must send MT_RELEASE_COMPLETE cause 101
- */
- if ((proc = ni1_new_l3_process(st, cr))) {
- proc->para.cause = 101;
- l3ni1_msg_without_setup(proc, 0, NULL);
- }
- }
- dev_kfree_skb(skb);
- return;
- } else if (mt == MT_RELEASE_COMPLETE) {
- dev_kfree_skb(skb);
- return;
- } else {
- /* ETS 300-104 part 2
- * if setup has not been made and a message type
- * (except MT_SETUP and RELEASE_COMPLETE) is received,
- * we must send MT_RELEASE_COMPLETE cause 81 */
- dev_kfree_skb(skb);
- if ((proc = ni1_new_l3_process(st, cr))) {
- proc->para.cause = 81;
- l3ni1_msg_without_setup(proc, 0, NULL);
- }
- return;
- }
- }
- if (l3ni1_check_messagetype_validity(proc, mt, skb)) {
- dev_kfree_skb(skb);
- return;
- }
- if ((p = findie(skb->data, skb->len, IE_DISPLAY, 0)) != NULL)
- l3ni1_deliver_display(proc, pr, p); /* Display IE included */
- for (i = 0; i < ARRAY_SIZE(datastatelist); i++)
- if ((mt == datastatelist[i].primitive) &&
- ((1 << proc->state) & datastatelist[i].state))
- break;
- if (i == ARRAY_SIZE(datastatelist)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1up%sstate %d mt %#x unhandled",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- proc->state, mt);
- }
- if ((MT_RELEASE_COMPLETE != mt) && (MT_RELEASE != mt)) {
- proc->para.cause = 101;
- l3ni1_status_send(proc, pr, skb);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1up%sstate %d mt %x",
- (pr == (DL_DATA | INDICATION)) ? " " : "(broadcast) ",
- proc->state, mt);
- }
- datastatelist[i].rout(proc, pr, skb);
- }
- dev_kfree_skb(skb);
- return;
- }
- static void
- ni1down(struct PStack *st, int pr, void *arg)
- {
- int i, cr;
- struct l3_process *proc;
- struct Channel *chan;
- if ((DL_ESTABLISH | REQUEST) == pr) {
- l3_msg(st, pr, NULL);
- return;
- } else if (((CC_SETUP | REQUEST) == pr) || ((CC_RESUME | REQUEST) == pr)) {
- chan = arg;
- cr = newcallref();
- cr |= 0x80;
- if ((proc = ni1_new_l3_process(st, cr))) {
- proc->chan = chan;
- chan->proc = proc;
- memcpy(&proc->para.setup, &chan->setup, sizeof(setup_parm));
- proc->callref = cr;
- }
- } else {
- proc = arg;
- }
- if (!proc) {
- printk(KERN_ERR "HiSax ni1down without proc pr=%04x\n", pr);
- return;
- }
- if (pr == (CC_TNI1_IO | REQUEST)) {
- l3ni1_io_timer(proc); /* timer expires */
- return;
- }
- for (i = 0; i < ARRAY_SIZE(downstatelist); i++)
- if ((pr == downstatelist[i].primitive) &&
- ((1 << proc->state) & downstatelist[i].state))
- break;
- if (i == ARRAY_SIZE(downstatelist)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1down state %d prim %#x unhandled",
- proc->state, pr);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "ni1down state %d prim %#x",
- proc->state, pr);
- }
- downstatelist[i].rout(proc, pr, arg);
- }
- }
- static void
- ni1man(struct PStack *st, int pr, void *arg)
- {
- int i;
- struct l3_process *proc = arg;
- if (!proc) {
- printk(KERN_ERR "HiSax ni1man without proc pr=%04x\n", pr);
- return;
- }
- for (i = 0; i < ARRAY_SIZE(manstatelist); i++)
- if ((pr == manstatelist[i].primitive) &&
- ((1 << proc->state) & manstatelist[i].state))
- break;
- if (i == ARRAY_SIZE(manstatelist)) {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "cr %d ni1man state %d prim %#x unhandled",
- proc->callref & 0x7f, proc->state, pr);
- }
- } else {
- if (st->l3.debug & L3_DEB_STATE) {
- l3_debug(st, "cr %d ni1man state %d prim %#x",
- proc->callref & 0x7f, proc->state, pr);
- }
- manstatelist[i].rout(proc, pr, arg);
- }
- }
- void
- setstack_ni1(struct PStack *st)
- {
- char tmp[64];
- int i;
- st->lli.l4l3 = ni1down;
- st->lli.l4l3_proto = l3ni1_cmd_global;
- st->l2.l2l3 = ni1up;
- st->l3.l3ml3 = ni1man;
- st->l3.N303 = 1;
- st->prot.ni1.last_invoke_id = 0;
- st->prot.ni1.invoke_used[0] = 1; /* Bit 0 must always be set to 1 */
- i = 1;
- while (i < 32)
- st->prot.ni1.invoke_used[i++] = 0;
- if (!(st->l3.global = kmalloc(sizeof(struct l3_process), GFP_ATOMIC))) {
- printk(KERN_ERR "HiSax can't get memory for ni1 global CR\n");
- } else {
- st->l3.global->state = 0;
- st->l3.global->callref = 0;
- st->l3.global->next = NULL;
- st->l3.global->debug = L3_DEB_WARN;
- st->l3.global->st = st;
- st->l3.global->N303 = 1;
- st->l3.global->prot.ni1.invoke_id = 0;
- L3InitTimer(st->l3.global, &st->l3.global->timer);
- }
- strcpy(tmp, ni1_revision);
- printk(KERN_INFO "HiSax: National ISDN-1 Rev. %s\n", HiSax_getrev(tmp));
- }
|