我们在上一篇文章也说到,链路建立阶段是PPP状态转移中的一个非常重要的阶段,我们今天就单独对这个阶段中所涉及的LCP报文进行较为细致的分析。 LCP数据报文是在链路建立阶段被交换的,它作为PPP的净载荷被封装在PPP数据帧的信息域中。在链路建立阶段的整个过程中信息域的内容是在变化的,它包括很多种类型的报文,所以这些报文也要通过相应的字段来区分,请见附图一 PPP数据帧的协议域固定填充0xC021。 代码域的长度为一个字节,主要是用来标识LCP数据报文的类型的。在链路建立阶段时,接收方收到LCP数据报文的代码域无法识别时,就会向对端发送一个LCP的代码拒绝报文(Code-Reject报文)。 标识域也是一个字节,其目的是用来匹配请求和响应报文。一般而言在进入链路建立阶段时,通信双方无论哪一端都会连续发送几个配置请求报文(Config-Request报文),而这几个请求报文的数据域可能是xx一样的,而仅仅是它们的标识域不同罢了。通常一个配置请求报文的ID是从0x01开始逐步加1的,当对端接收到该配置请求报文后,无论使用何种报文(回应报文可能是Config-Ack、Config-Nak和Config-Reject三种报文中的一种)来回应对方,但必须要求回应报文中的ID(标识域)要与接收报文中的ID一致,当通信设备收到回应后就可以将该回应与发送时的进行比较来决定下一步的操作。 长度域的内容 = 总字节数据(代码域+标志域+长度域+数据域)。长度域所指示字节数之外的字节将被当作填充字节而忽略掉,而且该域的内容不能超过MRU的值。 数据域的内容根据不同的LCP数据报文的内容也是不一样的。 下面说一下LCP包括的几种报文类型,见附图二,不同的报文在标识域中所填充的内容也不同。 LCP报文主要分为1、链路配置报文;2、链路终止报文;3、链路维护报文。 链路配置报文主要包括Config-Request、Config-Ack、Config-Nak和Config-Reject四种报文。 当通信双方需要建立链路时,无论哪一方都需要发送Config-Request报文并携带每一端自已所希望协商的配置参数选项。 当接收方收到Config-Request报文时,会在剩下的三种类型的报文中选择一种来响应对方的请求报文,到底选择哪种报文来响应对方需依据以下两个条件: 不能xx识别配置参数选项的类型域,我们知道一个Config-Request报文中会同时携带多个配置参数选项,而对于一个支持PPP协议的通信设备也不一定会支持上表中所有列出的配置选项,即使支持,也可能在实际应用中关闭掉某些选项功能。(例如:当使用PPP协议通信的一端可能将一些无用的配置选项都关闭了,而仅支持0x01和0x03两个配置参数选项,因此当对方发送的Config-Request报文中含有0x04配置选项时,对于本端而言这个配置参数选项就无法识别,也即是不支持这个配置参数选项的协商)。 如果能支持xx识别配置参数选项,但接收端也可能不认可Config-Request报文中配置参数选项数据域中的内容(例如:当一端发送魔术字配置参数选项中的魔术字为全0,而对端认为应该为其它值,这种情况就属于不支持配置参数选项中的内容)。 所以依据上面的两个条件,我们就可以明确在回应对方配置请求报文时,采用何种报文回应。 当接收Config-Request报文的一端能识别发送过来的所有配置参数选项且认可所有配置参数选项数据域的内容时,接收端将会给对端回一个Config-Ack报文并将配置请求报文中的配置参数选项原封不动的放置在Config-Ack报文的数据域内(根据协议的规定是不可改变配置参数选项的顺序)。当配置请求报文的发送端收到Config-Ack报后,则会从当前阶段进入到下一个阶段。 当接收Config-Request报文的一端能识别发送端所发送过来的所有配置参数选项,但对部分配置参数选项数据域中的内容不认可时,接收端将会给对端回应一个Config-Nak报文,(注意,是能够识别,只是对部分参数内容不认可,所以不是Config-Reject报文)该报文中只携带不认可的配置参数选项,而这些配置参数选项的数据内容为本端希望的值。然而当接收端收到Config-Nak报文后,会重新发送Config-Request报文,而这个Config-Request报文与上一次所发送的Config-Request报文区别在于那些被对端不认可的配置参数选项的内容被填写到刚刚协商完后再次发送的Config-Request报文中(Config-Nak报文发送回来的那些配置参数选项)。 当接收Config-Request报文的一端不能识别所有的发送端发送过来的配置参数选项时,此时接收端将会向对端回一个Config-Reject报文,该报文中的数据域只携带那些不能识别的配置参数选项(当配置参数选项的类型域不识别时)。当对端接收到Config-Reject报文后,同样会再次发送一个Config-Request报文,这个配置请求报文与上一次发送的区别在于将不可识别的那些配置参数选项给删除了。 链路终止报文分为Terminate-Request和Terminate-Reply两种报文。LCP报文中提供了一种机制来关闭一个点对点的连接,想要关断链路的一端会持续发送Terminate-Request报文,直到收到一个Terminate-Reply为止。接收端一旦收到了一个Terminate-Request报文后,必须回应一个Terminate-Reply报文,同时等待对端先将链路断开后,再完成本端的所有断开的操作。 LCP的链路终止报文的数据域与链路配置报文的数据域不一样,链路终止报文中无需携带各配置参数选项。对于链路终止报文也同样需要ID一致,当接收到Terminate-Reply报文才会做链路终止操作。 {zh1}说一下魔术字的含义,这是在链路建立过程中比较重要的一个参数,这个参数是在Config-Request里面被协商的,主要的作用是防止环路,如果在双方不协商魔术字的情况下,某些LCP的数据报文需要使用魔术字时,那么只能是将魔术字的内容填充为全0;反之,则填充为配置参数选项协商后的结果。 魔术字在目前所有的设备当中都是需要进行协商的,它被放在Config-Request的配置选项参数中进行发送,而且需要由自身的通信设备独立产生,协议为了避免双方可能产生同样的魔术字,从而导致通信出现不必要的麻烦,因此要求由设备采用一些随机方法产生一个{dywe}的魔术字。一般来说魔术字的选择会采用设备的系列号、网络硬件地址或时钟。双方产生相同魔术字的可能性不能说是没有的,但应尽量避免,通常这种情况是发产在相同厂商的设备进行互连时,因为一个厂商所生产的设备产生魔术字的方法是一样的。 我们知道魔术字产生的作用是用来帮助检测链路是否存在环路,当接收端收到一个Config-Request报文时,会将此报文与上一次所接收到的Config-Request进行比较,如果两个报文中所含的魔术字不一致的话,表明链路不存在环路。但如果一致的话,接收端认为链路可能存在环路,但不一定存在环路,还需进一步确认。此时接收端将发送一个Config-Nak报文,并在该报文中携带一个重新产生的魔术字,而且此时在未接收到任何Config-Request或Config-Nak报文之前,接收端也不会发送任何的Config-Request报文。这时我们假设可能会有以下两种情况发生: 1. 链路实际不存在环路,而是由于对方在产生魔术字时与接收端产生的一致,但实际这种情况出现的概率是很小的。当Config-Nak被对端接收到后,应该发送一个Config-Request报文(此报文中的魔术字为Nak报文中的),当对端接收到后,与上次比较,由于接收端已经在Nak报文中产生了一个不同的魔术字,此时接收端收到的Config-Request报文中的魔术字与上次配置请求报文中不一样,所以接收端可断定链路不存在环路。 2. 链路实际上确实存在环路,一段时间后Config-Nak报文会返回到发送该报文的同一端。这时接收端比较这个Config-Nak报文与上一次发出去的一样,因此链路存在环路的可能性又增大了。我们知道当一端收到了一个Config-Nak报文时,又会发送一个Config-Request报文(该报文中的魔术字与Config-Nak中的一致),这样又回到了最初的状态,在这条链路上就会不断的出现Config-Request、Config-Nak报文,因此这样周而复始下去,接收端就会认为PPP链路存在环路的可能性在不断增加,当达到一定数量级时,就可认为此链路存在环路。(注意,不是{dy}次受到相同的魔术字就判断有环路的) 但在实际应用中根据不同设备实现PPP协议的方法,我们在链路环路检测时可采用两种方法。{dy}种机制就是如上面所述的,这个过程不断地重复,最终可能会给LCP状态机发一个Down事件,这时可能会使LCP的状态机又回到初始化阶段,又开始新一轮的协商。当然对于某些设备还会采用第二种机制,就是不产生任何事件去影响当前LCP的状态机,而是停留在请求发送状态。但这时认为链路有环路的一端设备需要不断的向链路上发送Echo-Request报文来检测链路环路是否被解除,当接收端收到Echo-Reply报文时,就认为链路环路被解除,从而就可能进行后续的PPP的过程。 具体的例子可以参见附图三。 好了,基本上通过3篇PPP闲谈,我们可以比较彻底的了解PPP协议的工作机制和特点,其实,会者不难,协议都是人制订的,只有简单易用的协议才会最终保留下来,就像TCP/IP打败OSI一样。所以,只要静下心来,没有什么高深的。可能这3篇文章里面有部分个人理解错误的地方,希望大家可以多提意见,大家共同进步。 |