⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 l3ni1.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
/* $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>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 voidni1_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 voidl3ni1_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 voidl3ni1_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 voidl3ni1_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 voidl3ni1_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 voidl3ni1_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 voidl3ni1_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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -