1、PPP程序基本流程PPP程序基本流程图PPPD程序用到的几个重要的结构体:typedef struct fsm int unit; /* Interface unit number */ int protocol; /* Data Link Layer Protocol field value */ int state; /* State */ int flags; /* Contains option bits */ u_char id; /* Current id */ u_char reqid; /* Current request id */ u_char seen_ack; /* H
2、ave received valid Ack/Nak/Rej to Req */ int timeouttime; /* Timeout time in milliseconds */ int maxconfreqtransmits; /* Maximum Configure-Request transmissions */ int retransmits; /* Number of retransmissions left */ int maxtermtransmits; /* Maximum Terminate-Request transmissions */ int nakloops;
3、/* Number of nak loops since last ack */ int rnakloops; /* Number of naks received */ int maxnakloops; /* Maximum number of nak loops tolerated */ struct fsm_callbacks *callbacks; /* Callback routines */ char *term_reason; /* Reason for closing protocol */ int term_reason_len; /* Length of term_reas
4、on */ fsm;typedef struct fsm_callbacks void (*resetci) /* Reset our Configuration Information */ _P(fsm *); int (*cilen) /* Length of our Configuration Information */ _P(fsm *); void (*addci) /* Add our Configuration Information */ _P(fsm *, u_char *, int *); int (*ackci) /* ACK our Configuration In
5、formation */ _P(fsm *, u_char *, int); int (*nakci) /* NAK our Configuration Information */ _P(fsm *, u_char *, int, int); int (*rejci) /* Reject our Configuration Information */ _P(fsm *, u_char *, int); int (*reqci) /* Request peers Configuration Information */ _P(fsm *, u_char *, int *, int); voi
6、d (*up) /* Called when fsm reaches OPENED state */ _P(fsm *); void (*down) /* Called when fsm leaves OPENED state */ _P(fsm *); void (*starting) /* Called when we want the lower layer */ _P(fsm *); void (*finished) /* Called when we dont want the lower layer */ _P(fsm *); void (*protreject) /* Calle
7、d when Protocol-Reject received */ _P(int); void (*retransmit) /* Retransmission is necessary */ _P(fsm *); int (*extcode) /* Called when unknown code received */ _P(fsm *, int, int, u_char *, int); char *proto_name; /* String name for protocol (for messages) */ fsm_callbacks;typedef struct char *na
8、me; /* name of the option */ enum opt_type type; void *addr; char *description; unsigned int flags; void *addr2; int upper_limit; int lower_limit; const char *source; short int priority; short int winner; option_t;struct protent u_short protocol; /* PPP protocol number */ /* Initialization procedure
9、 */ void (*init) _P(int unit); /* Process a received packet */ void (*input) _P(int unit, u_char *pkt, int len); /* Process a received protocol-reject */ void (*protrej) _P(int unit); /* Lower layer has come up */ void (*lowerup) _P(int unit); /* Lower layer has gone down */ void (*lowerdown) _P(int
10、 unit); /* Open the protocol */ void (*open) _P(int unit); /* Close the protocol */ void (*close) _P(int unit, char *reason); /* Print a packet in readable form */ int (*printpkt) _P(u_char *pkt, int len, void (*printer) _P(void *, char *, .), void *arg); /* Process a received data packet */ void (*
11、datainput) _P(int unit, u_char *pkt, int len); bool enabled_flag; /* 0 iff protocol is disabled */ char *name; /* Text name of protocol */ char *data_name; /* Text name of corresponding data protocol */ option_t *options; /* List of command-line options */ /* Check requested options, assign defaults
12、 */ void (*check_options) _P(void); /* Configure interface for demand-dial */ int (*demand_conf) _P(int unit); /* Say whether to bring up link for this pkt */ int (*active_pkt) _P(u_char *pkt, int len);struct channel /* set of options for this channel */ option_t *options; /* find and process a per-
13、channel options file */ void (*process_extra_options) _P(void); /* check all the options that have been given */ void (*check_options) _P(void); /* get the channel ready to do PPP, return a file descriptor */ int (*connect) _P(void); /* were finished with the channel */ void (*disconnect) _P(void);
14、/* put the channel into PPP mode */ int (*establish_ppp) _P(int); /* take the channel out of PPP mode, restore loopback if demand */ void (*disestablish_ppp) _P(int); /* set the transmit-side PPP parameters of the channel */ void (*send_config) _P(int, u_int32_t, int, int); /* set the receive-side P
15、PP parameters of the channel */ void (*recv_config) _P(int, u_int32_t, int, int); /* cleanup on error or normal exit */ void (*cleanup) _P(void); /* close the device, called in children after fork */ void (*close) _P(void);PPP的状态转换图:对程序流程的基本框架的说明因为程序是利用protent结构指针指向当前所在协议层的方法来实现的因此,每一层都要经历几个阶段,直到本层达
16、到OPENED状态时才可进入下一阶段来实现下一阶段的协议。所以对每一层的协议都有相同的函数指针,只是函数指针指向的协议不同而已。整个程序的主体实现是从主函数的LCP_OPEN()开始的,在这个函数里,调用了有限状态机FSM_OPEN(),而在FSM_OPEN()中,callback指针指向了starting,于是就到了LCP_STARTING()函数来实现一个OPEN事件从而使得PPP状态准备从DEAD到ESTABLISHED的转变。接下来,回到主函数,下面一步是调用START_LINK(),在此函数中会把一个串口设备作为PPP的接口,并把状态转变为ESTABLISHED,然后调用lcp_lo
17、werup()来告诉上层底层已经UP,lcp_lowerup()中调用FSM_LOWERUP()来发送一个configure-request请求,再把当前状态设置为REQSENT状态,至此,第一个LCP协商的报文已经发送出去。while (phase != PHASE_DEAD) handle_events(); get_input(); if (kill_link) lcp_close(0, User request); if (asked_to_quit) bundle_terminating = 1; if (phase = PHASE_MASTER) mp_bundle_termina
18、ted(); if (open_ccp_flag) if (phase = PHASE_NETWORK | phase = PHASE_RUNNING) ccp_fsm0.flags = OPT_RESTART; /* clears OPT_SILENT */ (*ccp_protent.open)(0); 接下来的流程实现主要就是在这个while循环中实现了。之前说过了我们已经发送了第一个配置协商报文,所以handle_events()主要就是做等待接收数据包的时间处理了,在handle_events()里主要调用了两个函数一个是wait_input(),他的任务是等待并判断是否超时。还有一
19、个是calltimeout()他主要是做超时的处理。当等待并未超时而且有数据包过来,则调用整个PPPD中最重要的函数get_input()函数。他主要接收过来的数据包并做出相应的动作。接下来就get_input()函数进行详细的说明。 首先对包进行判断,丢弃所有不在LCP阶段和没有OPENED状态的包,然后protop指针指向当前协议的input函数。于是就进入了LCP_INPUT(),同理LCP_INPUT()调用了FSM_INPUT()对收到的包进行代码域的判断,判断收到的是什么包。假设比较顺利,我们收到的是CONFACK的包,于是调用fsm_rconack()函数,在此函数中根据当前自身
20、的状态来决定下一步的状态如何改变,这里我们假设也很顺利,已经发送完了configure-ack,因此我们把FSM当前状态变成了OPENED状态,并把callback指针指向UP.所以我们马上就调用LCP_UP()在那里我们又调用了LINK_ESTABLISHED()函数来进入认证的协商,或者如果没有认证则直接进入网络层协议。当然这里我们还是要认证的所有在LINK_ESTABLISHED()里我们选择是利用何种认证方式是PAP,还是EAP,还是CHAP.假设我们这里采用CHAP而且是选择CHAP WITH PEER,意思是等待对端先发送CHALLENGE挑战报文。于是我们又调用了chap_wit
21、h_peer()函数,并等待接收挑战报文。于是从新又来到handle_events()等待接收。再利用get_input()来接收包,在get_input()里这次调用chap_input(),再调用FSM_INPUT(),在那里我们再对包的代码域进行判断,这次判断出是CHAP_CHALLENGE包,则我们要调用chap_respons()函数来回应对端,继续等待对方的报文,再次利用CHAP_INPUT(),FSM_INPUT()来判断,如果是SUCCESS,则调用handle_status(),在这个函数里调用success_chap_with_peer函数(),从而进入网络层阶段,调用ne
22、twork_phase()函数。网络层的互动是从start_networks()开始的,如果在网络层阶段同时有CCP协议(压缩控制协议)则进行压缩控制协议的协商,然后再进入正式的IPCP的协商,而IPCP的协商主要也是通过protop指针指向IPCP_OPEN()开始的。而IPCP_OPEN()则是调用了FSM_OPEN(),在这里,首先发送一个configure-request包,然后和之前一样等待接收。经过几个交互后最后调用NP_UP()完成网络层的协商,至此PPP链路可以承载网络层的数据包了。选项的协商以LCP为例,它使用了lcp_options 结构,并定义了该结构的四个变量lcp_w
23、antoptions,lcp_gotoptions,lcp_allowoptions,lcp_hisoptions,分别用来表示我们想要请求的选项,对方ack的选项,我们允许对方请求的选项,我们ack对方的选项。lcp_options结构中每个域的含义见附录。pppd根据lcp_wantoptions生成发送的选项请求,根据lcp_allowoptions决定接受还是拒绝接收到的选项请求。pppd在lcp_init函数中对lcp_wantoptions和lcp_allowoptions进行赋值。在状态机的发送函数中,在当前状态不为REQSENT,ACKRCVD,ACKSENT的情况下,调用状态机的reset函数把lcp_wantoptions赋值给lcp_gotoptions来组装选项。选项的组装是靠状态机的回调函数指针addci完成的,对于LCP就是lcp_addci,组装好选项后发送数据是通过调用fsm_sdata实现的。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1