关于ss7的crc-16校验计算
一、libss7的处理
libss7中只对MTP2的头部字段(FSN/FIB/BSN/BIB/LI)进行初始化,对于信息之后的CK字段不做处理;即libss7不对CRC校验进行任何处理,而是交给了第一层物理层的驱动来处理。
具体的CRC校验处理在dahdi-thrunk的dahdi-base.c文件中进行。
它直接调用的Linux内核中的ppp_defs.h中的crc-ccitt相关的计算函数和宏定义。内核中有支持ccitt crc-16的相关代码,采用查表法形式进行计算。
其计算函数见dahdi-base.c中822~840行:
static inline void calc_fcs(struct dahdi_chan *ss, int inwritebuf)
{
int x;
unsigned int fcs = PPP_INITFCS;
unsigned char *data = ss->writebuf[inwritebuf];
int len = ss->writen[inwritebuf];
/* Not enough space to do FCS calculation */
if (len < 2)
return;
for (x = 0; x < len - 2; x++)
fcs = PPP_FCS(fcs, data[x]);
fcs ^= 0xffff;
/* Send out the FCS */
data[len - 2] = (fcs & 0xff);
data[len - 1] = (fcs >> 8) & 0xff;
}
这是发送端的计算。
在接收端,只需要进行ms->infcs = PPP_FCS(ms->infcs, rxc);计算(6841行)在函数__putbuf_chunk中处理接收缓冲区数据。这里不用取反,即不用与0xffff异或。
然后将结果与一个固定值PPP_GOODFCS=0xf0b8进行比较即可。具体计算原理见第三节。
PPP_FCS(fcs.c),PPP_GOODFCS=0xf0b8,PPP_INITFCS=0xffff等均在linux内核的ppp_defs.h中定义。
二、chan_ss7的处理
chan_ss7中同样采用了ccitt crc-16标准计算方法,不过起使用代码好像有问题,网上搜索,也有很多系统使用时出现CRC校验错的情况。
chan_ss7的处理是将PPP_FCS等计算函数提取出来归入chan_ss7模块中,CRC校验和处理是在MTP2即第二层进行。具体定义和调用都在mtp.c文件中。
定义PPP_FCS在第707~742行,与linux内核中的定义一致;
调用时,发送端1451行mtp2_fill_zaptel_buf函数是填充发送缓冲区的函数,里面计算CRC的过程也是一样:m->tx_crc = 0xffff;
m->tx_crc = PPP_FCS(m->tx_crc, data);
m->tx_crc ^= 0xffff;
接收端,chan_ss7 0.9china版本代码似乎有问题:
(1350行)m->rx_crc = PPP_FCS(m->rx_crc, res); 此处res为int型,明显有问题。应该是需要一个接收缓冲区字符数组。
不过起发送端计算crc和接收端校验crc的思路是与dahdi中一致。
三、计算原则和代码调用说明
SS7中CRC-16的校验采用CCITT标准,其生成多项式为 X16 + X12 + X5 + 1,二进制表示为0x11021,由于生成多项式第一位都是1,故常省略表示为0x1021.
计算需要注意的是,信息比特的发送顺序和生成多项式以及CRC检验码的比特顺序。
1、信息比特发送顺序:
我们传统的CRC计算是采用高位先发传输顺序(左边高位),但SS7的帧是低位先发,如下图所示,右边的比特先发送,这和我们手工计算刚好相反,采用移位寄存器计算CRC时,刚好一个左移,一个是右移,所以,生成多项式也要把比特位进行高低位翻转,这是就变成0x8408。
SS7 MTP2帧的发送方向(低位先发)
2、CRC校验码的生成、填充与检验
CRC计算采用翻转比特的生成多项式0x8408进行(比特完全倒转进行计算)程序计算时采用成熟快速的查表法进行(见附录中的源代码)。
需要注意的是,为了避免发送信息序列的头尾有多个0(可能数量多少不影响CRC的值)的情况,CCITT CRC-16计算时,设置了一个初始CRC值为全1,即0xffff。计算出来的值需要进行取反后才能添加到信息序列后面,取反是指crc^0xffff。在添加到信息序列后面时,也是采用低位先发(以当前状态为准)。也就是CK部分靠近信息的8比特放低八位,前面(上图)放高八位。
校验时,有两种方式,一种是对信息序列进行计算然后与CK位进行比较,还有一种也是当前采用的,就是连同16位CK位和信息位一起参与CRC校验计算,其计算出来的应该是一个固定的值 0xf0b8(即所谓的GOODFCS)。
具体的CCITT CRC-16的原理和推导,参见博客文章:
CCITT CRC-16计算原理与实现
阅读(3109) | 评论(0) | 转发(0) |