常见以太网帧结构详解
1 以太网相关背景
以太网这个术语通常是指由DEC,Intel和Xerox公司在1982年联合公布的一个标准,它是当今TCP/IP采用的主要的局域网技术,它采用一种称作CSMA/CD的媒体接入方法。几年后,IEEE802委员会公布了一个稍有不同的标准集,其中802.3针对整个CSMA/CD网络,802.4针对令牌总线网络,802.5针对令牌环网络;此三种帧的通用部分由802.2标准来定义,也就是我们熟悉的802网络共有的逻辑链路控制(LLC)。由于目前CSMA/CD的媒体接入方式占主流,因此本文仅对以太网和IEEE 802.3的帧格式作详细的分析。
在TCP/IP世界中,以太网IP数据报文的封装在RFC 894中定义,IEEE802.3网络的IP数据报文封装在RFC 1042中定义。标准规定:
1)主机必须能发送和接收采用RFC 894(以太网)封装格式的分组;
2)主机应该能接收RFC 1042(IEEE 802.3)封装格式的分组;
3)主机可以发送采用RFC 1042(IEEE 802.3)封装格式的分组。如果主机能同时发送两种类型的分组数据,那么发送的分组必须是可以设置的,而且默认条件下必须是RFC 894(以太网)。
最常使用的封装格式是RFC 894定义的格式,俗称Ethernet II或者Ethernet DIX。下面,我们就以Ethernet II称呼RFC 894定义的以太帧,以IEEE802.3称呼RFC 1042定义的以太帧。
2 帧格式
Ethernet II和IEEE802.3的帧格式分别如下。
Ethernet II帧格式:
----------------------------------------------------------------------------------------------
| 前序 | 目的地址 | 源地址 | 类型 | 数据 | FCS |
----------------------------------------------------------------------------------------------
| 8 byte | 6 byte | 6 byte | 2 byte | 46~1500 byte | 4 byte|
IEEE802.3一般帧格式
--------------------------------------------------------------------------------------------------------------
| 前序 | 帧起始定界符 | 目的地址 | 源地址 | 长度 | 数据 | FCS |
------------------------------------------------------------------------------------------------------------
| 7 byte | 1 byte | 2/6 byte | 2/6 byte | 2 byte | 46~1500 byte | 4 byte |
Ethernet II和IEEE802.3的帧格式比较类似,主要的不同点在于前者定义的2字节的类型,而后者定义的是2字节的长度;所幸的是,后者定义的有效长度值与前者定义的有效类型值无一相同,这样就容易区分两种帧格式了。
一、 前序字段
前序字段由8个(Ethernet II)或7个(IEEE802.3)字节的交替出现的1和0组成,设置该字段的目的是指示帧的开始并便于网络中的所有接收器均能与到达帧同步,另外,该字段本身(在Ethernet II中)或与帧起始定界符一起(在IEEE802.3中)能保证各帧之间用于错误检测和恢复操作的时间间隔不小于9.6毫秒。
二、 帧起始定界符字段
该字段仅在IEEE802.3标准中有效,它可以被看作前序字段的延续。实际上,该字段的组成方式继续使用前序字段中的格式,这个一个字节的字段的前6个比特位置由交替出现的1和0构成。该字段的最后两个比特位置是11,这两位中断了同步模式并提醒接收后面跟随的是帧数据。
当控制器将接收帧送入其缓冲器时,前序字段和帧起始定界符字段均被去除。类似地当控制器发送帧时,它将这两个字段(如果传输的是IEEE802.3帧)或一个前序字段(如果传输的是真正的以太网帧)作为前缀加入帧中。
三、 目的地址字段
目的地址字段确定帧的接收者。两个字节的源地址和目的地址可用于IEEE802.3网络,而6个字节的源地址和目的地址字段既可用于Ethernet II网络又可用于IEEE802.3网络。用户可以选择两字节或六字节的目的地址字段,但对IEEE802.3设备来说,局域网中的所有工作站必须使用同样的地址结构。目前,几乎所有的802.3网络使用6字节寻址,帧结构中包含两字节字段选项主要是用于使用16比特地址字段的早期的局域网。
四、 源地址字段
源地址字段标识发送帧的工作站。和目前地址字段类似,源地址字段的长度可以是两个或六个字节。只有IEEE802.3标准支持两字节源地址并要求使用的目的地址。Ethernet II和IEEE802.3标准均支持六个字节的源地址字段。当使用六个字节的源地址字段时,前三个字节表示由IEEE分配给厂商的地址,将烧录在每一块网络接口卡的ROM中。而制造商通常为其每一网络接口卡分配后字节。
五、 类型字段
两字节的类型字段仅用于Ethernet II帧。该字段用于标识数据字段中包含的高层协议,也就是说,该字段告诉接收设备如何解释数据字段。在以太网中,多种协议可以在局域网中同时共存,例如:类型字段取值为十六进制0800的帧将被识别为IP协议帧,而类型字段取值为十六进制8137的帧将被识别为IPX和SPX传输协议帧。因此,在Ethernet II的类型字段中设置相应的十六进制值提供了在局域网中支持多协议传输的机制。
在IEEE802.3标准中类型字段被替换为长度字段,因而Ethernet II帧和IEEE802.3帧之间不能兼容。
六、 长度字段
用于IEEE802.3的两字节长度字段定义了数据字段包含的字节数。不论是在Ethernet II还是IEEE 802.3标准中,从前序到FCS字段的帧长度最小必须是64字节。最小帧长度保证有足够的传输时间用于以太网网络接口卡精确地检测冲突,这一最小时间是根据网络的最大电缆长度和帧沿电缆长度传播所要求的时间确定的。基于最小帧长为64字节和使用六字节地址字段的要求,意味着每个数据字段的最小长度为46字节。唯一的例外是吉比特以太网。在1000Mbit/s的工作速率下,原来的802.3标准不可能提供足够的帧持续时间使电缆长度达到100米。这是因为在1000Mbit/s的数据率下,一个工作站在发现网段另一端出现的任何冲突之前已经处在帧传输过程中的可能性很高。为解决这一问题,设计了将以太网最小帧长扩展为512字节的负载扩展方法。
对除了吉比特以太网之外的所有以太网版本,如果传输数据少于46个字节,应将数据字段填充至46字节。不过,填充字符的个数不包括在长度字段值中。同时支持以太网和IEEE802.3帧格式的网络接口卡通过这一字段的值区分这两种帧。也就是说,因为数据字段的最大长度为1500字节,所以超过十六进制数05DC的值说明它不是长度字段(IEEE802.3).而是类型字段(Ethernet II)。
七、 数据字段
如前所述,数据字段的最小长度必须为46字节以保证帧长至少为64字节,这意味着传输一字节信息也必须使用46字节的数据字段:如果填入该该字段的信息少于46字节,该字段的其余部分也必须进行填充。数据字段的最大长度为1500字节。
八、 校验序列字段
既可用于Ethernet II又可用于IEE802.3标准的帧校验序列字段提供了一种错误检测机制,每一个发送器均计算一个包括了地址字段、类型/长度字段和数据字段的循环冗余校验(CRC)码。发送器于是将计算出的CRC填入四字节的FCS字段。
虽然IEEE802.3标准必然要取代Ethernet II,但由于二者的相似以及Ethernet II作为IEEE802.3的基础这一事实,我们将这两者均看作以太网。
3 以太网帧结构的变种格式
以太网帧结构的变种,仅涉及到IEEE802.3帧。下图描述了IEEE802.3帧数据部分的结构,这个结构就是IEEE802.2定义的LLC(逻辑链路控制),LLC用来识别信息包中所承载的协议。LLC报头包含DSAP(destination service access point,目的服务访问点)、SSAP(source service access point,源服务访问点)和控制字段。
当DSAP和SSAP取特定值:0xff和0xaa时,会分别产生两个变种:Netware-以太网帧和以太网-SNAP帧;其他的取值均为纯802.3帧。
-----------------------------------------------------------------------------------------------
| 前序 | 帧起始定界符 | 目的地址 | 源地址 | 长度 | 数据 | FCS |
-----------------------------------------------------------------------------------------------
| \
| \
| \
| \
-------------------------------------- \
| DSAP | SSAP | 控制 | 信息 |
---------------------------------------
一、Netware-以太网帧
Netware-以太网帧对IEEE802.3的数据字段进行了专门分隔以便传输NetWare类型的数据。实际使用的帧类型是在系统设置时通过将NetWare与特定类型的帧绑写而定义的。下图显示了Netware-以太网帧格式。图中的IPX=0xffff,也就是说,以太网帧中的DSAP=SSAP=0xff时,802.3帧就变成了Netware-以太网帧,用来承载NetWare类型的数据。由于不再有LLC字段,所以这种帧通常称为简化802.3。
对那些使用或考虑使用NetWare的人,在涉及帧类型时应该小心:Novell使用术语以太网-802.3,因此如果将NetWare设置为以太网-802.2帧,网络实际上是符合以太网-802.3标准的,也就是说,有LLC结构的。
-----------------------------------------------------------------------------------------------
| 前序 | 帧起始定界符 | 目的地址 | 源地址 | 长度 | 数据 | FCS |
-----------------------------------------------------------------------------------------------
| \
| \
-----------------------
| IPX头 | 信息 |
------------------------
二、以太网-SNAP帧
以太网-SNAP帧与Netware-以太网帧不同,可以用于传输多种协议。因为在以太网-SNAP帧中包含以太网类型字段,故AppleTalk Phase II、NetWare及TCP/IP协议均能传输。因此,SNAP可以被看作一种扩展,它允许厂商创建自己的以太网传输协议。以太网-SNAP标准由IEEE802.1委员会制定以保证IEEE802.3局域网和以太网之间的互操作性。
下图显示了以太网-SNAP帧格式。尽管这种帧格式是基于IEEE802.3帧格式的,但它并不使用DSAP和SSAP信箱机制和控制字段。相反,在这些字段中使用特定的值表示该帧是SNAP帧。
-------------------------------------------------------------------------------------
| 前序 |定界符 | 目的地址 | 源地址 | 长度 | 数据 | FCS |
-------------------------------------------------------------------------------------
| \
| \
| \
| \
| \
| \
------------------------------------------------
|DSAP|SSAP|控制|机构代码|类型|信息|
------------------------------------------------
十六进制值AA被放置在DSAP和SSAP字段,而十六进制值03被放置在控制字段,这指明传输的是SNAP帧。将十六进制值03放置在控制字段表明使用无编码格式,这是SNAP帧支持的唯一一种格式。
机构代码字段指明在后续的以太网类型字段中放置的是由哪一个机构分配的值。在机构代码字段中的十六进制值00-00-00指明施乐公司分配了以太网类型字段的值。通过使用以太网-SNAP帧,可以按与原始的以太网帧类似的方式获得支持多协议的能力,原始以太网设置类型字段的目的与此相同。
4 帧判定
接收工作站可以通过判断以太帧的字段正确解释帧中承载的数据。为此,应首先检查跟在源地址之后的两个字节的值。如果该值大于1500,则必定是Ethernet II帧;否则该帧或者是纯IEEE802.3帧,或者是这种帧的变种。此时,必须检查更多的字节。
如果下面的两个字节取值十六进制FF:FF,则该帧是NetWare-以太网,这是因为在IPX头结构中前两个字节的校验和字段取值十六进制FF:FF;如果这两个字节取值为十六进制AA:AA,则表示是以太网-SANP帧;此外,这两个字节的任何其它取值均指示该帧纯802.3帧。
5 IPX的四种以太帧封装格式
介绍了上面的四种以太帧的格式,现在以IPX报文为例,介绍如何利用四种以太帧的格式进行封装。
一、Ethernet II封装格式
-------------------------------------------------------------------------------------
| 前序 | 目的地址 | 源地址 | 0x8137 | IPX 数据报 | FCS |
-------------------------------------------------------------------------------------
二、Netware-以太网帧
--------------------------------------------------------------------------------------------------------
| 前序 | 帧起始定界符 | 目的地址 | 源地址 | 长度 | IPX 数据报 | FCS |
---------------------------------------------------------------------------------------------------------
三、以太网-SNAP帧
---------------------------------------------------------------------------------------------------------------------------
|前序|定界符|目的地址|源地|长度|0xAA|0xAA |0x03|0x000000 |0x8137| IPX 报文 | FCS |
---------------------------------------------------------------------------------------------------------------------------
四、纯802.3帧
---------------------------------------------------------------------------------------------------------------------------
|前序|定界符|目的地址|源地|长度| 0xe0 | 0xe0 | 0x03 | IPX 报文 | FCS |
---------------------------------------------------------------------------------------------------------------------------
1 以太网相关背景
以太网这个术语通常是指由DEC,Intel和Xerox公司在1982年联合公布的一个标准,它是当今TCP/IP采用的主要的局域网技术,它采用一种称作CSMA/CD的媒体接入方法。几年后,IEEE802委员会公布了一个稍有不同的标准集,其中802.3针对整个CSMA/CD网络,802.4针对令牌总线网络,802.5针对令牌环网络;此三种帧的通用部分由802.2标准来定义,也就是我们熟悉的802网络共有的逻辑链路控制(LLC)。由于目前CSMA/CD的媒体接入方式占主流,因此本文仅对以太网和IEEE 802.3的帧格式作详细的分析。
在TCP/IP世界中,以太网IP数据报文的封装在RFC 894中定义,IEEE802.3网络的IP数据报文封装在RFC 1042中定义。标准规定:
1)主机必须能发送和接收采用RFC 894(以太网)封装格式的分组;
2)主机应该能接收RFC 1042(IEEE 802.3)封装格式的分组;
3)主机可以发送采用RFC 1042(IEEE 802.3)封装格式的分组。如果主机能同时发送两种类型的分组数据,那么发送的分组必须是可以设置的,而且默认条件下必须是RFC 894(以太网)。
最常使用的封装格式是RFC 894定义的格式,俗称Ethernet II或者Ethernet DIX。下面,我们就以Ethernet II称呼RFC 894定义的以太帧,以IEEE802.3称呼RFC 1042定义的以太帧。
2 帧格式
Ethernet II和IEEE802.3的帧格式分别如下。
Ethernet II帧格式:
----------------------------------------------------------------------------------------------
| 前序 | 目的地址 | 源地址 | 类型 | 数据 | FCS |
----------------------------------------------------------------------------------------------
| 8 byte | 6 byte | 6 byte | 2 byte | 46~1500 byte | 4 byte|
IEEE802.3一般帧格式
--------------------------------------------------------------------------------------------------------------
| 前序 | 帧起始定界符 | 目的地址 | 源地址 | 长度 | 数据 | FCS |
------------------------------------------------------------------------------------------------------------
| 7 byte | 1 byte | 2/6 byte | 2/6 byte | 2 byte | 46~1500 byte | 4 byte |
Ethernet II和IEEE802.3的帧格式比较类似,主要的不同点在于前者定义的2字节的类型,而后者定义的是2字节的长度;所幸的是,后者定义的有效长度值与前者定义的有效类型值无一相同,这样就容易区分两种帧格式了。
一、 前序字段
前序字段由8个(Ethernet II)或7个(IEEE802.3)字节的交替出现的1和0组成,设置该字段的目的是指示帧的开始并便于网络中的所有接收器均能与到达帧同步,另外,该字段本身(在Ethernet II中)或与帧起始定界符一起(在IEEE802.3中)能保证各帧之间用于错误检测和恢复操作的时间间隔不小于9.6毫秒。
二、 帧起始定界符字段
该字段仅在IEEE802.3标准中有效,它可以被看作前序字段的延续。实际上,该字段的组成方式继续使用前序字段中的格式,这个一个字节的字段的前6个比特位置由交替出现的1和0构成。该字段的最后两个比特位置是11,这两位中断了同步模式并提醒接收后面跟随的是帧数据。
当控制器将接收帧送入其缓冲器时,前序字段和帧起始定界符字段均被去除。类似地当控制器发送帧时,它将这两个字段(如果传输的是IEEE802.3帧)或一个前序字段(如果传输的是真正的以太网帧)作为前缀加入帧中。
三、 目的地址字段
目的地址字段确定帧的接收者。两个字节的源地址和目的地址可用于IEEE802.3网络,而6个字节的源地址和目的地址字段既可用于Ethernet II网络又可用于IEEE802.3网络。用户可以选择两字节或六字节的目的地址字段,但对IEEE802.3设备来说,局域网中的所有工作站必须使用同样的地址结构。目前,几乎所有的802.3网络使用6字节寻址,帧结构中包含两字节字段选项主要是用于使用16比特地址字段的早期的局域网。
四、 源地址字段
源地址字段标识发送帧的工作站。和目前地址字段类似,源地址字段的长度可以是两个或六个字节。只有IEEE802.3标准支持两字节源地址并要求使用的目的地址。Ethernet II和IEEE802.3标准均支持六个字节的源地址字段。当使用六个字节的源地址字段时,前三个字节表示由IEEE分配给厂商的地址,将烧录在每一块网络接口卡的ROM中。而制造商通常为其每一网络接口卡分配后字节。
五、 类型字段
两字节的类型字段仅用于Ethernet II帧。该字段用于标识数据字段中包含的高层协议,也就是说,该字段告诉接收设备如何解释数据字段。在以太网中,多种协议可以在局域网中同时共存,例如:类型字段取值为十六进制0800的帧将被识别为IP协议帧,而类型字段取值为十六进制8137的帧将被识别为IPX和SPX传输协议帧。因此,在Ethernet II的类型字段中设置相应的十六进制值提供了在局域网中支持多协议传输的机制。
在IEEE802.3标准中类型字段被替换为长度字段,因而Ethernet II帧和IEEE802.3帧之间不能兼容。
六、 长度字段
用于IEEE802.3的两字节长度字段定义了数据字段包含的字节数。不论是在Ethernet II还是IEEE 802.3标准中,从前序到FCS字段的帧长度最小必须是64字节。最小帧长度保证有足够的传输时间用于以太网网络接口卡精确地检测冲突,这一最小时间是根据网络的最大电缆长度和帧沿电缆长度传播所要求的时间确定的。基于最小帧长为64字节和使用六字节地址字段的要求,意味着每个数据字段的最小长度为46字节。唯一的例外是吉比特以太网。在1000Mbit/s的工作速率下,原来的802.3标准不可能提供足够的帧持续时间使电缆长度达到100米。这是因为在1000Mbit/s的数据率下,一个工作站在发现网段另一端出现的任何冲突之前已经处在帧传输过程中的可能性很高。为解决这一问题,设计了将以太网最小帧长扩展为512字节的负载扩展方法。
对除了吉比特以太网之外的所有以太网版本,如果传输数据少于46个字节,应将数据字段填充至46字节。不过,填充字符的个数不包括在长度字段值中。同时支持以太网和IEEE802.3帧格式的网络接口卡通过这一字段的值区分这两种帧。也就是说,因为数据字段的最大长度为1500字节,所以超过十六进制数05DC的值说明它不是长度字段(IEEE802.3).而是类型字段(Ethernet II)。
七、 数据字段
如前所述,数据字段的最小长度必须为46字节以保证帧长至少为64字节,这意味着传输一字节信息也必须使用46字节的数据字段:如果填入该该字段的信息少于46字节,该字段的其余部分也必须进行填充。数据字段的最大长度为1500字节。
八、 校验序列字段
既可用于Ethernet II又可用于IEE802.3标准的帧校验序列字段提供了一种错误检测机制,每一个发送器均计算一个包括了地址字段、类型/长度字段和数据字段的循环冗余校验(CRC)码。发送器于是将计算出的CRC填入四字节的FCS字段。
虽然IEEE802.3标准必然要取代Ethernet II,但由于二者的相似以及Ethernet II作为IEEE802.3的基础这一事实,我们将这两者均看作以太网。
3 以太网帧结构的变种格式
以太网帧结构的变种,仅涉及到IEEE802.3帧。下图描述了IEEE802.3帧数据部分的结构,这个结构就是IEEE802.2定义的LLC(逻辑链路控制),LLC用来识别信息包中所承载的协议。LLC报头包含DSAP(destination service access point,目的服务访问点)、SSAP(source service access point,源服务访问点)和控制字段。
当DSAP和SSAP取特定值:0xff和0xaa时,会分别产生两个变种:Netware-以太网帧和以太网-SNAP帧;其他的取值均为纯802.3帧。
-----------------------------------------------------------------------------------------------
| 前序 | 帧起始定界符 | 目的地址 | 源地址 | 长度 | 数据 | FCS |
-----------------------------------------------------------------------------------------------
| \
| \
| \
| \
-------------------------------------- \
| DSAP | SSAP | 控制 | 信息 |
---------------------------------------
一、Netware-以太网帧
Netware-以太网帧对IEEE802.3的数据字段进行了专门分隔以便传输NetWare类型的数据。实际使用的帧类型是在系统设置时通过将NetWare与特定类型的帧绑写而定义的。下图显示了Netware-以太网帧格式。图中的IPX=0xffff,也就是说,以太网帧中的DSAP=SSAP=0xff时,802.3帧就变成了Netware-以太网帧,用来承载NetWare类型的数据。由于不再有LLC字段,所以这种帧通常称为简化802.3。
对那些使用或考虑使用NetWare的人,在涉及帧类型时应该小心:Novell使用术语以太网-802.3,因此如果将NetWare设置为以太网-802.2帧,网络实际上是符合以太网-802.3标准的,也就是说,有LLC结构的。
-----------------------------------------------------------------------------------------------
| 前序 | 帧起始定界符 | 目的地址 | 源地址 | 长度 | 数据 | FCS |
-----------------------------------------------------------------------------------------------
| \
| \
-----------------------
| IPX头 | 信息 |
------------------------
二、以太网-SNAP帧
以太网-SNAP帧与Netware-以太网帧不同,可以用于传输多种协议。因为在以太网-SNAP帧中包含以太网类型字段,故AppleTalk Phase II、NetWare及TCP/IP协议均能传输。因此,SNAP可以被看作一种扩展,它允许厂商创建自己的以太网传输协议。以太网-SNAP标准由IEEE802.1委员会制定以保证IEEE802.3局域网和以太网之间的互操作性。
下图显示了以太网-SNAP帧格式。尽管这种帧格式是基于IEEE802.3帧格式的,但它并不使用DSAP和SSAP信箱机制和控制字段。相反,在这些字段中使用特定的值表示该帧是SNAP帧。
-------------------------------------------------------------------------------------
| 前序 |定界符 | 目的地址 | 源地址 | 长度 | 数据 | FCS |
-------------------------------------------------------------------------------------
| \
| \
| \
| \
| \
| \
------------------------------------------------
|DSAP|SSAP|控制|机构代码|类型|信息|
------------------------------------------------
十六进制值AA被放置在DSAP和SSAP字段,而十六进制值03被放置在控制字段,这指明传输的是SNAP帧。将十六进制值03放置在控制字段表明使用无编码格式,这是SNAP帧支持的唯一一种格式。
机构代码字段指明在后续的以太网类型字段中放置的是由哪一个机构分配的值。在机构代码字段中的十六进制值00-00-00指明施乐公司分配了以太网类型字段的值。通过使用以太网-SNAP帧,可以按与原始的以太网帧类似的方式获得支持多协议的能力,原始以太网设置类型字段的目的与此相同。
4 帧判定
接收工作站可以通过判断以太帧的字段正确解释帧中承载的数据。为此,应首先检查跟在源地址之后的两个字节的值。如果该值大于1500,则必定是Ethernet II帧;否则该帧或者是纯IEEE802.3帧,或者是这种帧的变种。此时,必须检查更多的字节。
如果下面的两个字节取值十六进制FF:FF,则该帧是NetWare-以太网,这是因为在IPX头结构中前两个字节的校验和字段取值十六进制FF:FF;如果这两个字节取值为十六进制AA:AA,则表示是以太网-SANP帧;此外,这两个字节的任何其它取值均指示该帧纯802.3帧。
5 IPX的四种以太帧封装格式
介绍了上面的四种以太帧的格式,现在以IPX报文为例,介绍如何利用四种以太帧的格式进行封装。
一、Ethernet II封装格式
-------------------------------------------------------------------------------------
| 前序 | 目的地址 | 源地址 | 0x8137 | IPX 数据报 | FCS |
-------------------------------------------------------------------------------------
二、Netware-以太网帧
--------------------------------------------------------------------------------------------------------
| 前序 | 帧起始定界符 | 目的地址 | 源地址 | 长度 | IPX 数据报 | FCS |
---------------------------------------------------------------------------------------------------------
三、以太网-SNAP帧
---------------------------------------------------------------------------------------------------------------------------
|前序|定界符|目的地址|源地|长度|0xAA|0xAA |0x03|0x000000 |0x8137| IPX 报文 | FCS |
---------------------------------------------------------------------------------------------------------------------------
四、纯802.3帧
---------------------------------------------------------------------------------------------------------------------------
|前序|定界符|目的地址|源地|长度| 0xe0 | 0xe0 | 0x03 | IPX 报文 | FCS |
---------------------------------------------------------------------------------------------------------------------------