linux添加ppp支持
2009-10-25 11:16:00 heiniaoyuyouling 阅读数 3301
浅析基于ppp的linux下脚本拨号上网
2009年05月27日 星期三 下午 11:56

既然是拨号上网,就不能不提到ppp(point-to-point protocol)协议.ppp协议提供了一种通过串行点对点联接传输数据报的方式.它由三部份组成:一种在串行封装数据报的方式,扩展联接控制协议LCP,和用来建立和配置不同网络层协议的家族网络控制协议NCP.封装方案由内核驱动代码来提供.pppd(ppp daemon)提供基本的LCP,认证支持,和建立和配置IP的网络控制协议NCP.一个ppp会话分为四个步骤:连接建立、连接质量控制、网络层协议配置、连接终止;提供了密码认证协议(PAP)或者邀请握手认证协议(CHAP)来保证连接安全.使用PPP你可以把你的 Linux PC连接到一台ppp服务器上并存取该服务器所连接的网络资源就如同你是直接连接在该网络上一般。你也可以把你的Linux PC设为一台ppp服务器,这样一来其它电脑就可以拨入你的电脑并且存取在你区域网络里的资源。
  当然,对于我们最终用户来讲,它是一个server/client模型的应用。本文主要讨论客户端怎样拨号上网,毕竟对于桌面系统的用户,ppp是日常生活的一个重要组成部分。在这里我想大家可能对windows下的拨号适配器的简单易用深表"敬佩",在这里我不想对其进行具体讨论,微软公司提供的TAPI可以让每一个windows下的程序员编写一个拨号程序不是一件困难的事,而在linux下呢?无论是gnome下的wvdial还是kde下的kppp,他们与纯脚本ppp-on相比不过是更直接,更易操作,称他们为图形化的拨号脚本并不为过,因为他们最终都是调用pppd这个功能强大大却不好驾驭的程序。有人告诉我kppp与windows下的拨号适配器功能差不多,不过我要告诉你kppp对pppd程序的依赖程度大过kppp作为一个独立的拨号程序,甚至/etc/ppp/options下的选项值对kppp的影响也是不可忽视的。
关于linux下脚本拨号的过程其实可适用于linux下所有的拨号过程,当然实际过程没有这么简单,如果有兴趣,请阅读源码)
1.由pppd程序调用chat会话程序
2.chat会话程序负责拨号,启动服务器端的pppd程序,验证身份,然后chat会话程序结束
3.由pppd程序继续chat会话程序的工作,与服务器端的pppd程序进行握手,建立ppp连接
ppp-on脚本包含有pppd程序,而ppp-on-dialer脚本含有chat会话程序,如果说pppd程序完成 的是连接建立、连接质量控制、网络层协议配置、连接终止,那么chat程序完成的是明文(textword)的验证,如果是拨入的服务器端需要密码认证协议(PAP)或者邀请握手认证协议(CHAP)来保证连接安全,那么还须在/etc/ppp目录下配置pap-secrets或chap-secrets文件。
关于ppp-on,ppp-on-dialer纯脚本拨号的配置
一个完整的ppp-on文件如下:(这里的实例及ppp-on-dialer文件均以163直通车为例)
TELEPHONE=163 # ISP提供的上网电话号码
ACCOUNT=163 # 账号名称
PASSWORD=163 # 登录密码
LOCAL_IP=0.0.0.0 # 本地IP地址,0.0.0.0表示由ISP动态分配
REMOTE_IP=0.0.0.0 # 远端IP地址,一般为0.0.0.0
NETMASK=255.255.255.0 # 子网掩码
export TELEPHONE ACCOUNT PASSWORD /
DIALER_SCRIPT=/etc/ppp/ppp-on-dialer /
exec /usr/sbin/pppd lock modem crtscts /dev/ttyS0 115200 /
asyncmap 0 kdebug 4 /
$LOCAL_IP:$REMOTE_IP noipdefault netmask $NETMASK defaultroute /
connect $DIALER_SCRIPT&
这个文件需要注意的地方:
a.注意"/"表示一行完整的结束。
b.尽量把kdebug的级别设置高一些,因为根据kdebug的级别来确定文件/var/log/messages的详细程度。
一个完整的ppp-on-dialer文件如下:
exec chat -v /
TIMEOUT 3 /
ABORT '/nBUSY/r' /
ABORT '/nNO ANSWER/r' /
ABORT '/nRINGING/r/n/r/nRINGING/r' /
ABORT '/nUsername/Password Incorrect/r'/ 此行可缩短由于账号密码不正确的验证时间
'' /rAT /
'OK- /c-OK' ATH0 /
TIMEOUT 30 /
OK ATDT163 /
sername:--sername: 163 /
assword: 163 /
大家说以上配置对吗?文件配置是对的,但是问题不少。我还是以实际问题来做具体分析吧(前提:无论外猫内猫均已装好,检查命令:echo "echo ATDT 163">/dev/modem),在/etc/ppp目录下键入了./ppp-on命令后,出现如下错误:
1.TR的亮,无拨号音。
解决办法:
首先检查ppp-on-dialer文件的权限,设为chmod 7 ppp-on-dialer
然后查看ppp-on-dialer文件,每行后面的 "/"是否存在
最后查看倒数第三行ok ATDT$TELEPHONE的电话号码是否设置正确,注意这里需设为实际电话号码,不是变量
2.在/var/log/messages文件中出现如下提示:
21:13:32 ken pppd[657]: CCP terminated by peer
21:13:32 ken pppd[657]: Compression disabled by peer.
或直接出现connect scripts fail提示(反复N次均为如下提示)
注意:在ppp-on-dialer文件的chat -v表示通过syslogd将客户端与服务器端建立连结的会话信息写入了/var/log/messages文件,如果你要查看这个会话信息,请键入tail -f /var/log/messages或者tailf /var/log/messages,这些信息对于正确配置拨号脚本文件很有用.
解决办法:
首先检查账号密码是否正确
然后就可能是chat会话程序本身的问题,大家看一下面一个例子:
成都天府热线163在minicom下的提示:
***********************************************
*Quidway A8010 Internet Server
*welcome!!
***********************************************
please input username:
please input password:
成都天府热线169在minicom下的提示:
*** Welcome To TianFu Online EeYing01-11 ! ***
login:
password:
大家可能注意到有什么不同了吧!也就是不同拨号服务器对于账号密码输入提示的不同,用过windows拨号终端的朋友可能会知道,那么windows拨号为什么没有这个问题,因为这是chat程序本身的问题:不能根据拨号服务器对于账号密码的提示不同而send账号和密码,解决办法:用minicom去得到正确的提示,根具提示修改ppp-on-dialer文件最后两行的配置,这里以成都天府热线163,169在minicom下的提示为例:
163:
sername:--sername: 163 /
assword: 163 /
169:
ogin:--ogin: liujien /
assword: liujien /
这样就完了吗,没有,这里的配置还要根据你的isp的要求(hint),用minicom N次去得到正确的提示,不过你还要冒着你的isp修改账号密码提示的风险,所以我劝你放弃chat会话程序吧。因为kppp,wvdial都不存在这个问题.chat会话程序是force,而wvdial,kppp却是guess.带着这个问题我读了ppp-2.4.1源码的说明文件,其实作者已在ppp-2.3.11版就已提供了PLUGINS PASSPROMPT(注:ppp-2.3.10版已提供插件支持,大家用redhat6.2自带了ppp-2.3.11的RPM包,至于插件一般的国内的LINUX网站上提供的ppp源码包都附带有),这个插件提供给第三方程序将账号密码发送给你的isp的调用功能。相关内容的英文如下:
A new `passprompt' plugin is included, thanks to Alan Curry, which makes it possible for pppd to call an external program to get the PAP password to send to the peer.
那么到底如何使用这个plugin呢?在包含pppd.h头文件的目录下编译passprompt.c文件
gcc -c -O passprompt.c
gcc -shared -o passprompt.o
大家就可得到一个passprompt.so的共享链接文件,将之拷贝到/etc/ppp/plugins目录下,修改/etc/ppp/options文件,加入一行plugin /etc/ppp/plugins/passprompt.so,然后你就可修改ppp-on文件的将DIALER_SCRIPT指向你所要指定的脚本文件,可自编程序或者在网上去下载一个第三方程序。
我给大家提供了一个简单方法,大家可安装wvdial拨号程序,然后在gnome下将/etc/wvdial.conf文件配置好,在/etc/ppp目录下新建一个脚本,命名为wvdial,内容如下wvdial 163 (163是你所要拨号的电话号码),然后chmod 7 wvdial,修改ppp-on文件,如:DIALER_SCRIPT=/etc/ppp/wvdial /
3.客户端已得到一个ip地址(用ifconfig 命令即可看到),通过域名无法浏览网页,通过ip地址可以。
解决办法:
一般的办法:去查isp给你提供的手册,得到域名服务器的ip地址,修改/etc/resolv.conf文件如下:nameserver 61.139.2.69(我以成都163为例),还可以在windows下用ipconfig /all命令也能得到dns服务器地址,因为windows的拨号程序默认设置为:自动获得dns服务器地址。
软件作者给我们提供的办法:
what was new in ppp-2.3.6.
**************************
Added new option `usepeerdns', thanks to Nick Walker . If the peer supplies DNS addresses, these will be written to /etc/ppp/resolv.conf. The ip-up script can then be used to add these addresses to /etc/resolv.conf if desired (see the ip-up.local.add and ip-down.local.add files in the scripts directory).
软件作者在ppp-2.3.6版即提供了类似于windows 拨号程序的选项:usepeerdns,如果你的isp提供dns服务器地址,将在/etc/ppp/resolv.conf文件及/etc/resolv.conf文件中写入主要域名服务器地址和辅助域名服务器地址,如下:
nameserver 61.139.2.69
nameserver 202.103.4.5
如何设置:修改/etc/ppp/options文件,添加一行"usepeerdns"
后记:
在这里笔者抛砖引玉,对linux脚本拨号上网并没有作太多深入的探讨,只是就围绕几个常见的问题进行了分析并提供了比较简单的解决办法.希望大家能够多读一些软件作者给我们提供的英文说明文件,因为国内的有些资料太过陈旧,不要没有耐心去读man pages,他们很有用,不过去读一读某些网站的文章是一个不错的选择。如果大家对我的文章有不同的看法,请给我写信不吝赐教,谢谢.

2013-12-30 11:30:08 sunyuyangg123 阅读数 2207

转载地址:http://www.th7.cn/system/lin/201305/38931.shtml

1.总述

    Linux中用户空间的网络编程,是以socket为接口,一般创建一个sockfd = socket(family,type,protocol),之后以该sockfd为参数,进行各种系统调用来实现网络通信功能。其中family指明使用哪种协议域(如INET、UNIX等),protocol指明该协议域中具体哪种协议(如INET中的TCP、UDP等),type表明该接口的类型(如STREAM、DGRAM等),一般设protocol=0,那么就会用该family中该type类型的默认协议(如INET中的STREAM默认就是TCP协议)。

    Linux中利用module机制,层次分明地实现了这套协议体系,并具有很好的扩展性,其基本模块构成如下:

    先看右边,顶层的socket模块提供一个sock_register()函数,供各个协议域模块使用,在全局的net_family[]数组中增加一项;各个协议域模块也提供一个类似的register_xx_proto()函数,供各个具体的协议使用,在该协议域私有的xx_proto[]数组中增加一项。这两个数组中的存放的都是指针,指向的数据结构如下图所示:

    很明显它们是用来创建不同类型的socket接口的,且是一种分层次的创建过程,可想而知,顶层socket_create()完成一些共有的操作,如分配内存等,然后调用下一层create;协议域内的create()完成一些该协议域内共有的初始化工作;最后具体协议中的create()完成协议特有的初始化。具体的下一节讲。

    再来看上图右边的,也是顶层socket模块提供的4个函数,前两个一般由具体协议模块调用,由于协议栈与应用层的交互,具体的后面会讲到。后两个一般有协议域模块调用,用于底层设备与协议栈间的交互。但这也不绝对,如在PPPOE协议中,这4个函数都由具体协议模块调用,这是因为PPPOX协议域内的共有部分不多,各个协议间几乎独立。这4个函数的功能及所用到的数据结构,在后面具体用到时会详细说明。

2.socket插口创建

    首先来看一下最终创建好的socket插口由哪些部分组成,该结构是相当庞大的,这里只给出框架:

  1. 基本属性有state(listen、accept等),flags标志(blocked等),type类型,这里family和protocol都没有了,因为它们再创建时使用过了,已经被融入到socket结构中。
  2. File指针指向一个file结构,在Linux中一个socket也被抽象为一个文件,所以在应用层一般通过标准的文件操作来操作它。
  3. Ops指向一个struct proto_ops结构,它是每种协议特有的,应用层的系统调用,最终映射到网络栈中具体协议的操作方法。
  4. Sk指向一个struct sock结构,而该结构在分配空间时,多分配了一点以作为该协议的私有部分,这里包含了该协议的具体信息,内容相当多。首先是一个struct sock_common结构,包含了协议的基本信息;然后是一个sk_prot_create指针,指向一个struct proto结构体,该结构体就是第一节中所述的,用proto_regsiter()注册到内核中的,它包含应用层到协议栈的交互操作和信息(也可以说成是App à transport layer的交互信息);然后还有一个sk_backlog_rcv函数指针,所指函数在协议栈处理完接收到的包之后调用,一般仅是把数据包放到该socket的接收队列中,等待APP读取;最后协议的私有部分里存放该协议的私有信息,如pppoe的sessionID、daddr,tcp的连接4元组等,这些信息很重要,利用它们来区分同一个协议中的多个socket。

 

创建的总体过程,第一节已讲过了,下面以pppoe为例,描述一个socket插口的具体创建过程:

之前所述的关键点这里几乎都涉及到了,要注意的是这里的struct proto结构非常简单,因为PPPOE协议几乎没有传输层,所以不需要有太多的中间操作,仅需要一个obj_size来指明struct sock结构后需分配的私有结构大小,关于私有结构的内容,一般在connect操作时才能初始化。

创建好socket之后,其中的fops,proto_ops,sk_backlog_rcv等操作是如何作用,来实现网络通信的功能?这是后面要讲述的内容。

3.主动过程

    主动过程即在应用层中通过系统调用,触发socket完成某种动作,有些系统调用和标准的文件操作类似,因此可以直接用sockfd的fops来描述,如read、write、ioctl等,有些则是socket接口特有的,需重新定义系统调用接口,Linux中用SYSCALL_DEFINEn()宏来定义系统调用接口,如bind、accept等。这些系统调用一般都很简单,最终都会去调用socket内部proto_ops中的接口函数。

    如下图所示,在socket层,并不是所有的文件操作都适用于socket,因此其特有的socket_file_ops中只指定了部分函数;另外还封装了几个系统调用,是我们熟悉的bind、listen、connect、accept。这些系统调用接口都是静态的,它们一般经过简单的处理,就调用具体socket中的proto_ops操作。

    在协议栈中,主要是socket特有的proto_ops操作,但对于一些复杂的协议,如TCP,还需要其它一些操作来支持,这些接口都放在struct sock中的struct proto中。PPPOE协议比较简单,不需要struct proto的操作来支持,但其中的obj_size仍然重要,如前所述。

 

    如上图所示,PPPOE协议中,并不是所有协议操作都需要,如bind、accept等,下面选几个来详细看一下socket的主动过程的工作。

    Ioctl系统调用:ioctl是通过标准的文件操作来调用的,具体如下图所示:

其中顶层sock_ioctl中,对于一些特殊情况,如VLAN、BRIDGE等,它们并不是要对socket插口本身操作,而是要调用VLAN、BRIDGE模块中的创建函数,这看起来有点格格不入,但为了操作方便,且保证网络相关的操作都封装在socket中,这么做也是不得已。

在pppoe_ioctl中,根据cmd进行相应操作,其中有一个值得注意的,就是PPPIOCGCHAN选项,它使得该pppoe_socket成为一个特殊的channel,这主要是pppoe为了给ppp协议提供服务而特有的,与网络协议栈关系不大,以后会具体看。

Read系统调用:read也是标准的文件操作,但要注意,在网络栈中,read并不是接收过程,而仅是从该sock的接收队列中取出skb,提交给应用层,如下图所示。而这些skb是如何获得的,那是一个复杂的被动过程,下面再讲。

Connect系统调用:connect是socket.c中封装的一个系统特用,其代码也很简单,最终调用协议栈中的pppoe_connect接口,该接口函数是pppoe协议中一个非常重要的操作,具体如下图所示:

    首先先一下通配地址的问题,这是network programming中一个基本问题,因为各个协议用到的地址结构不同,在应用层,为了方便可读性,可以用协议特有的地址结构,只要符标准的模式即可(即第一个元素为family),然后强制转换成sockaddr*类型,传递给通用的系统调用接口。在最终调用协议模块中的接口函数时,再转换回来。

    再看pppoe_connect中,首先由sock结构指针得到pn指针,它们是分配在一起的(如前所述),这很容易得到,同时还得到pppoe_net结构的指针(它是该协议中全局共有的)。然后把用户传递进来的addr的数据放到socket中来,并且执行一个set_item函数,该函数主要根据addr信息,把该socket指针放到协议全局的pppoe_net结构中(这一步对接收过程很重要,后面会细讲)。最后初始化了该socket中特有的chan结构,并调用ppp_register_net_channel(),这主要为ppp服务,以后再看。

4.发送流程

    这也是一个主动过程,在协议体系中,它是一个比较重要的过程,所以单独列出来。Socket框架中,发送过程是通过标准的文件操作write完成的, socket的write操作为sock_aio_write(),最终会调用proto_ops->sendmsg()函数,即pppoe模块中的pppoe_sendmsg(),如下图所示:

    首先从sock中获得相关信息,最重要的当然是dev设备,因为pppoe的设备是选定的(由useraddr提供),而有些协议如IP,则会根据协议地址,有协议栈自动选择dev。然后分配skb,并准备其中的package,这是每个协议的关键,由于pppoe协议很简单,只需要设置好一个pppoe header即可。最后直接调用dev_queue_xmit(skb),通过设备将该package发送出去。

5.网络协议栈结构小结

    这里想讲一下的是,pppoe到底是什么层的协议,链路层。而通过上面的描述,更准确的说法应该是,pppoe是一个完整的协议,是从应用层到设备之间的协议模块,从这个意义上来讲,它和INET域中的协议是等价的。如下图所示:

    这里讲的协议是从应用层往下直到物理设备的完整过程,有些协议具有一定的相似性,(如TCP、UDP,还包括裸IP等都以IP协议为基础),则把它们归为一个协议域内。至于协议分层,则是概念上的,如PPPOE协议的主要功能体现在链路层,则一般称它为链路层协议, 而狭义上称TCP、UDP为传输层协议(而前面讲的广义上的TCP、UDP则是包括传输层、以IP为基础的网络层、链路层的完整协议)。

    有点饶人,不过没关系,只要理解协议栈的功能就是从socket接口得到数据,封装成一定的包结构,最终由物理设备发送出去(接收过程反过来)。至于具体的实现,则是由具体协议的特点决定的,对于一些复杂协议,分层方式则是一种比较好的选择。

    而其中有些协议会比较特殊,如之前讲的VLAN,它甚至从来都不会进入到协议栈,仅在设备驱动层,就被转化成以太网协议,协议栈中根本不需要为它准备处理接口。再如比较典型的ICMP协议,它既可以是一个完整的协议,被应用层调用(如典型的Ping程序),也可以只作为TCP的附属协议(只被TCP处理,对应用层不可见)。这里的PPPOE与此很类似,本文讲述了其作为完整协议的工作方式,另外它也可以作为PPP协议的底层基础,在下一篇中会讲述其具体的实现方法。

6.被动过程-接收流程

    接收过程是一个被动过程,在屋里设备层,它往往是由中断触发,其实现的复杂度也较发送过程高很多。在协议栈中,其实现也同样与发送过程很不对称。因为发送时,本身主机拥有控制权,而接收时,是一个数据包对多个接收模块(一对多),只能从数据包中的信息中一点一点分析,并去寻找接收模块。

    先给出接收流程的框架,再逐步去分析其实现。如下图所示:

    先不看橙色部分,一个接收流程由物理设备的中断触发,设备驱动程序进行相应处理,得到协议栈中标准的数据结构sk_buff(简称skb),并根据一个特殊的全局数据结构packet_type,将数据交给相应的协议;协议根据自身设计特点对skb数据进行处理,并通过全局变量xx_net_id和各个协议私有的特殊数据结构xx_net,寻找到该数据包对应的应用层socket插口,并将其放在该socket插口的接收队列中;最后应用层在某个时刻会通过read系统调用读取该数据(如第3节所讲)。

6.1设备驱动层的处理

    设备驱动层的接收过程在之前的篇章中已经讲过了,一般是由硬件中断触发,然后或是采用中断模式、或是采用NAPI模式,总之其根本任务就是:根据设备的特点(先验知识,如以太网设备驱动事先就是知道以太网帧的基本结构的),将接收到的裸数据转换成协议栈所认识的标准结构skb(从而实现底层设备对上层的透明性),然后提交给相应的协议。很明显问题有两个,skb是什么样的,要准备什么?怎么知道提交给谁?

    准备skb结构。首先来看一下sk_buff的构成,如下图所示。Skb只是一个控制结构,实际的数据放在一个data_buf中,并由skb中一些列参数索引,具体见下图右所示,这之中有些参数是在分配data_buf、copy数据时就决定的,如head、end、data、tail等;有些则要经过一定的识别才能得到,如mac_header一般在设备驱动中得到,而network_header、transport_header则要到协议栈中才知道,且各个协议的处理各不相同,如PPPOE协议根本不需要只需要指明network_header,而TCP协议则有复杂的头部信息。最终由skb->data指针和头部长可得到app_data的位置,因此应用层可以只读取应用数据即可。

    Skb中另外一些参数也相当重要,如vlan_tci用于指明vlan的id,其用法在前面已讲过。dev参数则是要贯穿整个流程的,因为该庞大结构中的多个信息会在整个网络系统中用到,要注意的是该参数由设备驱动程序决定,一般就是接收的物理设备,但在Linux中,网络设备是由net_device结构指示的,一个物理设备可有多个协议设备,这在VLAN、BRIDGE中很明显,其实在PPP协议中,这也是一个关键点,后面会讲到。Sk参数指示了该数据包属于哪个应用层socket插口,它由具体协议根据特定方法得到,后面会讲到。Protocol参数是本节的重点,它由mac_header中的字节决定。

    设备驱动程序只关心mac_header,即数据包最初始的部分。前面也提到了,这需要一定的先验知识,如ethernet设备驱动,它先验的指导以太网头部由DMAC、SMAC和两字节的协议构成,下面是一个RTL8012驱动的接收片段(~/dev/net/Ethernet/realtek/apt.c):

    提交协议栈。主要就是根据skb->protocol参数,当然还需要另一个重要的数据结构packet_type。

    设备驱动中最后提交过程有netif_skb_receive()函数完成,它会遍历系统中所有的packet_type,找到protocol和dev(这个是啥意思)都相同,就调用该ptype中的func函数,如ip_packet中的func为ip_rcv()函数,这样skb就到了协议栈中。

    系统中所有全局的packet_type构成一个list,并由全局变量ptype_all索引,另外还提供ptype_base[]全局数组,将type相同的packet_type单独成链,为遍历提供方便。

    这些全局的packet_type结构是从哪来的,这就要看第一节图中,左边4个函数中的一个dev_add_packet(struct packet_type*)。协议模块在加载时,调用该函数,将自己特有的packet_type结构注册进内核中,而其中的(*func)则有协议自己定义。

    最后要注意的是,打开if_ether.h文件,可以看到现在已定义的协议protocol有_P_IP、_P_ARP、_P_8021Q、_P_PPP_SES、_P_PPP_DIS等,如果根据传统的分层协议来看它们,会觉得很乱,有网络层的、链路层的、甚至同一种协议还有两个,但如果用第5节的概念来看,则很容易理解。再看由什么模块注册,TCP、UDP都是以IP协议为基础,只要有INET协议域模块注册一个即可,而ARP虽然也属于INET域,但它却必须自己有一个packet_type,PPPOE协议虽然只是一个协议,但却有两个阶段,所以它有两个不同的packet_tpye。可见这种实现是很灵活的,根据具体协议的特点决定。

6.2协议栈接收处理

    协议栈的处理由各协议决定,如TCP协议的处理过程是相当复杂的,而这里的pppoe的处理却非常简单,但由它却可以避开细节,更清楚地看到流程的梗概,如下图所示:

    可以看到pppoe协议的处理过程几乎没有,仅是设置了skb的network_header, transport_header,然后就利用get_item()函数找到它所属的socket插口,直接把它提交给上层。如上图右所示,是典型的TCP接收流程,是相当复杂的,其中TCP与IP的接头处还需用到额外的私有数据结构。

    提交函数sk_backlog_rcv,即这里的pppoe_rcv_core(sk,skb)函数,首先判断是否为ppp通道的数据,若是则提交给ppp协议。一般正常情况下,直接用sock_queue_rcv_skb(sk,skb)函数将它放在socket的接收队列中。

    匹配应用层接口:协议栈在对数据包进行处理后,需要确定该包属于哪个socket插口,这个过程在内核中有一套完整的机制来完成,其框架如下图所示:

    首先内核有个全局结构net_generic,其中一个最重要的元素是指针数组。然后每个协议module加载时,会调用register_pernet_device(struct pernet_operations*)(见第一节图),pernet_operations结构中最关键的两个参数,一个是size,它指示内核为该模块分配一个私有数据结构(如pppoe即为struct pppoe_net),另一个是xx_net_id,它指示由net_generic.ptr[xx_net_id]来指向该数据结构,这样每个协议模块中,就可以根据自己的xx_net_id很容易寻找到内核分配给自己的私有结构。最后协议的私有模块中一般也有一个指针数组,用以索引属于它的各个socket。

    工作流程就很清楚了,具体的工作方式还要看两个函数,

就不看细节了,仅看两个函数的原型就能明白,其中pn参数就是上面所述的用全局结构net_generic和各协议私有xx_net_id获得的。Set_item()函数在connect时调用(参见第3节),它根据pppox_sock中的sessionID、remoteMAC(这两个参数由*useraddr传入,详见下一篇协议分析),根据一个hash算法得到一个hashInt值,然后用pn->hash_ptr[hashInt]指向该socket结构。那反过来,接收时由这两个参数(由数据包的协议头中获得)得到hashInt,便能很容易找到对应的socket了。

    各个协议使用的方法及参数都不同,但思路都一样,就是依据协议本身特有的参数(如TCP中的连接4元组),在socket创建、或连接的时候(接收数据之前),根据一定的算法,将它的指针放在该协议私有的xx_net中,这样接收时就可以由数据报的协议参数找到它了。

6.3命名空间namespace

上述的socket索引方法有个绕弯的地方:就是每个协议私有的xx_net结构可以直接由协议模块本身分配,索引起来也方便,不要用到全局的net_generic。而目前内核所用的方法,其实是为了另外的目的,那就是命名空间namespace。也就是虚拟多用户的一套机制,具体的也没细看,好像目前内核整个namespace还没有全部完成。

network的命名空间问题主要在于,每个协议模块的xx_net私有结构不仅是一个,而是由内核全局决定的,即每注册一个新的用户(有点像虚拟机机制),就分配一个新的xx_net结构,这样多用户间可以用参数相同的socket连接,但却指向不同的socket。

    可以看到前面所述的很多内容中,都会有个net参数,就是为了这个作用,主要实现函数在namespace.c中。

7.总结

    主要结合pppoe协议,学习了Linux中网络栈的实现。由于pppoe协议本身很简单,代码量少,更容易抓住协议实现的梗概。Linux网络栈,继承Unix,采用socket插口作为主线,主要包括创建、协议连接、主动过程、匹配机制、被动过程等内容。

    要注意的是,实际应用中,很少有直接利用pppoe协议通信的,而是把它作为ppp协议的底层基础来用,而这需要协议实现中的一些技巧来支持,下一篇中讲述。


-----------------------------------------------------------------------

 其实PPP不像是一种协议,而更像是一种应用,可以把它看成一个拨号上网的应用软件,拨号成功后,本地主机就可以正常上网了,可以使用TCP/IP等协议,而完全感觉不到PPP的存在。而实际上PPP在网络协议栈中增加了不少东西,但对上层透明。另外PPP一般需要底层工具来支持,如之前讲的PPPoE。

    Pppoe协议的实现在协议栈中,且其底层有实际的物理设备(或者vlan设备)支持,关键就在于pppoe协议可以直通应用层(如上一篇所讲),也可以半途连接ppp0设备。而ppp协议的实现主要在设备ppp0的驱动中,这是一个虚拟设备,没有物理设备的支持,且保持对上层是透明。

1.代码概述

    Ppp是一个应用程序,其代码在ppp软件包中,其中主体部分最终编译成pppd文件,另外还有很多支持部件(plugin),如pppoe、pppoa等,在子文件夹plugin中,最终编译成rp-pppoe.so、pppoa.so文件。

    在内核中,对此的支持主要也有两部分,一个是ppp模块(注意这不是最终的ppp网络设备,而是一个字符设备,主要对构建维护ppp连接提供支持),另一部份是pppoe协议模块(其实还包括裸packet协议模块),如下图左所示:

    如上图右所示,是pppd程序的main流程,首先是从argv(或者从file中)中获得plugin信息,并加载;然后执行一个for循环,主要是为了处理ppp连接意外中断、或设备暂时中断的情况下,可以重新启动连接;与ppp协议相关的部分是通过start_link(0)启动一个ppp连接,然后执行while循环,处理各种ppp信息;最后要说明的是,真正的数据通信是在建立的ppp连接中进行的,与这里的pppd没有关系,而ppp连接中的信息却可以发送到这里的while循环中来,具体实现后面会描述。

    由于整个代码比较复杂,没有去详细看,只就其中一些关键点做一些了解。

2. plugin机制实现

    Ppp有很多种类型的plugin,如pppoe、pppoa等,这些plugin最终被编译成多个xx.so文件,并提供一个通用的struct channel{}接口,如下图左所示。一般的pppd命令如下:

Pppd …… plugin rp-pppoe.so eth0 ……

和常见的命令结构一样,由option+arg的方式构成,上述的命令中体现了两个选项,一个是plugin,其参数为rp-pppoe.so,另一个是eth0,没有参数。

    在pppd程序中,选项option由一个特殊的结构来描述,如下图右所示:

上述的两个选项对应的option_t结构分别为:

{"plugin",o_special,(void*)loadplugin,"load a plugin module into pppd",……}

{"device-name",o_wild,(void*)&PPPoEDevnameHook,"pppoe device name",……}

在option_from_args()函数中,主要通过parse_option()函数来处理args选项参数,其中首先利用find_option()函数来识别选项,并找到对应的option_t结构,一般采用name匹配方法,如"plugin",有些则特殊,如"device-name"。然后调用process_option()函数来处理。

    Plugin选项对应的处理函数为loadplugin(),该函数利用标准库函数dlopen(),打开plugin文件rp-pppoe.so,然后再利用标准库函数dlsym(),找到其中的plugin_init()函数。这种方法适用于这样的情况:由多种动态连接库供应用程序选择,且每个动态库(.so)中都定义了一个名称相同的函数。Plugin_init()函数的处理很简单,就是把自身库特有的选项加入到全局选项表中去,上述的第二个选项{"device-name",……"pppoe device name"}就是此时加入的,当然不同的动态库中的plugin_init()函数中,加入的选项各不相同。

    这样就好理解第二个选项了,其处理函数是rp-pppoe.so中的私有函数PPPoEDevnameHook(arg,argv,1),该函数是加载pppoe-plugin的关键:

该函数首先利用socket的ioctl函数,判断所给interface是否为以太网接口;然后将设备名和pppoe_channel分别赋给pppd程序空间中的devname和the_channel;最后对PPPoE模块进行一些简单的初始化。

    这样之后,pppd程序就可以利用pppoe模块了,其它模块也一样。对于pppd而言,它不关心各种模块实现的细节,而只是调用各模块提供的统一接口the_channel。

3.创建ppp连接通道

    前面讲了,各种plugin模块提供给pppd的调用接口都相同,只是实现细节不一样,下面主要以pppoe为例,描述如何创建一个ppp连接通道。回到第1节图中的main()函数流程,可以看到创建连接是通过调用lcp_open(0),start_link(0)来完成的。具体细节就不看了,大致的流程是:Lcp_open()会创建一个ppp_netdev,如ppp0,而start_link()函数则会创建一个pppoe的连接,作为ppp0设备的传输通道,如下图所示。

    "/dev/ppp"是一个字符设备ppp_chrdev,其对应的内核代码在ppp_generic.c中,对它的操作都通过标准的文件操作ppp_file_ops来调用,其中ioctl操作中,PPPIOCNEWUNIT选项对应于创建一个新的网络设备net_device(ppp_netdev),该设备的私有空间为一个struct ppp结构,而其网络操作由ppp_netdev_ops来调用,这些特有的结构和操作决定了ppp_netdev设备的功能与特性,后面还会详细描述。

    Start_link()函数中,首先调用the_channel->connect()函数,对于PPPOE-plugin来说,就是创建一个PF_PPPOE的socket接口,并调用该socket的标准connect操作,该操作在前一篇的第3节中已描述,除了处理协议地址外,还有一个关键操作就是ppp_register_net_channel(po->chan)。然后继续调用the_channel->establish_ppp(devfd),对于PPPOE-plugin,该函数为generic_establish_ppp(fd),它的操作很简单,但很关键,就是调用ioctl(fd,PPPIOCGCHAN,…),该操作在前一篇的第3节已描述,就是设置socket插口的state|=BOUND,使得它接收到的数据包都转交给ppp_netdev。

    经过一些列创建操作后,系统模型如下图所示:

4.补充PPPOE协议本身

    对于一个协议,其最具代表性的就是它的帧结构,pppoe的帧结构如下图所示:

联系connect调用,需要用户提供pppoeaddr(其中包括dev、sessionID、remoteMAC),才能创建一个可通信的socket连接,我们称为pppoe的session连接。而怎么获得pppoeaddr呢?这其实是pppoe的发现阶段,其实现一般采用PF_PACKET协议,自己设置裸数据包为pppoe-discovery格式,具体流程如下图所示:

5.收发代码细节

    PPP协议的的数据包结构如第4节图所示,其中pppoe的负载即为PPP协议头+PPP数据,而PPP数据可以是一个完整的通用协议包,如IP包。本文开头处的图很好地描述了PPP协议所需要做的工作,以及整个协议体系的构成、分布情况。

    首先给出整个收发流程的框架图,如下:

    ppp模块可以通过网络接口或者文件接口来操作,它们最终都通过底层pppoe_channel来完成数据通信,联系第一节中main()函数流程中的while循环,它实际上就是通过文件接口,来监控ppp连接。

    pppoe在协议栈中实现,但它用一个特殊的socket插口来服务于ppp,该socket(即第3节所述的connect插口)只对pppd程序可见,且从不直接用它来发送数据,只是利用它注册的chan为ppp发送数据,而它收到的数据都通过ppp_input()递交给ppp。这些并不会影响pppoe协议栈的工作,其他应用程序可以创建其它AF_PPPOE的socket插口,进行正常的pppoe通信。

5.1发送流程

    发送流程代码如下图所示:

    pppd程序通过对/dev/ppp字符设备的操作,最终由ppp_chan实现与对端的数据通信,数据格式有ppp协议自己决定,主要用于维护ppp连接。

    主要看一下ppp的网络设备,它有自己独立的net_device结构、IP地址等,对上层而言就像一个普通的设备,IP协议中的路由可以选择该设备。该设备的驱动程序是实现ppp协议的主要地方,它对skb进行push操作,添加ppp的协议头,最后调用pppoe_chan将数据包发送出去。注意pppoe_chan_ops和pppoe_ops没有太大区别,都要设置pppoe的协议头,只是pppoe_chan_ops接收到的skb是上层协议栈的,需要一个push操作,而pppoe_ops是自己分配skb。

    数据包格式如下图所示:

5.2接收流程

    接收流程代码如下图所示:

    发送时逐层插入协议头,而接收时,一般不需要删除协议头(那样需要额外的put(skb)操作),而仅改变skb->network/transport_header即可。为了实现对上层的透明,接收流程的最后,重新设置dev为该ppp0,proto为ppp负载数据的协议,然后调用netif_rx(skb)重新启动接收流程,这样该skb就仿佛是从ppp0设备接收到的。

    整个过程中,数据包几乎不变,仅是skb的相应字段改变,如上所述。

2013-01-07 22:04:07 rain0993 阅读数 773

什么是PPP

PPP是一种网络中最为基础的协议。PPP协议(Point-to-Point Protocol)是一种数据链路层协议,它是为在同等单元之间传输数据包这样的简单链路而设计的。这种链路提供全双工操作,并按照顺序传递数据包。PPP为基于各种主机、网桥和路由器的简单连接提供一种共通的解决方案。

PPP协议包括以下三个部分:

1. 数据帧封装方法。

2. 链路控制协议LCP(Link Control Protocol):它用于对封装格式选项的自动协商,建立和终止连接,探测链路错误和配置错误。

3. 针对不同网络层协议的一族网络控制协议NCP(Network Control Protocol): PPP协议规定了针对每一种网络层协议都有相应的网络控制协议,并用它们来管理各个协议不同的需求。

PPP认证方式
  1. 口令验证协议(PAP)
  PAP 是一种简单的明文验证方式。NAS(网络接入服务器,Network Access Server)要求用户提供用户名和口令,PAP以明文方式返回用户信息。

  2. 挑战-握手验证协议(CHAP) 
   CHAP是一种加密的验证方式,能够避免建立连接时传送用户的真实密码。NAS向远程用户发送一个挑战口令(challenge),其中包括会话ID和 一个任意生成的挑战字串(arbitrary challenge string)。远程客户必须使用MD5单向哈希算法(one-way hashing algorithm)返回用户名和加密的挑战口令,会话ID以及用户口令,称为Secret Password,其中用户名以非哈希方式发送。


linux中PPP怎样实现的

PPP 协议之下是以太网和串口等物理层,之上是IP协议等网络层。这里,对于下层,我们只讨论串口的情况,对于上层,我们只讨论TCP/IP的情况。发送 时,TCP/IP数据包经过PPP打包之后经过串口发送。接收时,从串口上来的数据经PPP解包之后上报给TCP/IP协议层。linux下ppp框架结构如下图:

image

PPP协议栈

主要负责PPP层数据的封装、压缩与解压缩.另外,它还对普通数据包和Ppp过程的数据包进行了分流,将普通数据包提交到TCP/IP协议栈,而将Ppp过程的数据包放到/dev/ppp设备队列中,等待Pppd去收取并处理.



PPP 是一个分层结构。在底层,它能使用同步媒介(如 ISDN 或同步 DDN 专线),也能适用异步媒介(如基于 Modem 拨号的 PSTN 网络)。在数据链路层,PPP 在链路建立方面提供了丰富的服务,这些服务以 LCP 协商选项的形式提供。在上层,PPP 通过 NCPs 提供对多种网络层协议的支持。PPP 对于每一种网络层协议都有一种封装格式来区别它们的报文。

什么是pppd

pppd是一个用户空间的后台服务进程(daemon。pppd实现了所有鉴权、压缩/解压和加密/解密等扩展功能的控制协议。pppd只是一个普通的用户进程,pppd与内核中的PPP协议处理模块之间通过设备文件(/dev/ppp)进行通信pppd有一个辅助工具chat,用来与GSM模组建立会话。它向串口发送AT命令,建立与GSM模组的会话,以便让PPP协议可以在串口上传输数据包。


/dev/ppp

设备文件/dev/ppp。通过read系统调用,pppd可以读取PPP协议处理模块的数据包,当然,PPP协议处理模块只会把应该由pppd处理的数据包发给pppd。通过write系统调用,pppd可以把要发送的数据包传递给PPP协议处理模块。通过ioctrl系统调用,pppd可以设置PPP协议的参数,可以建立/关闭连接。在pppd里,每种协议实现都在独立的C文件中,它们通常要实现protent接口,该接口主要用于处理数据包,和fsm_callbacks接口,该接口主要用于状态机的状态切换。数据包的接收是由main.c: get_input统一处理的,然后根据协议类型分发到具体的协议实现上。而数据包的发送则是协议实现者根据需要调用output函数完成的

发送数据

应用程序通过socket 接口发送TCP/IP数据包,这些TCP/IP数据包如何流经PPP协议处理模块,然后通过串口发送出去呢?pppd在make_ppp_unit函数调用ioctrl(PPPIOCNEWUNIT)创建一个网络接口(如ppp0),内核中的PPP协议模块在处理PPPIOCNEWUNIT时,调用register_netdev向内核注册ppp的网络接口,该网络接口的传输函数指向ppp_start_xmit。当应用程序发送数据时,内核根据IP地址和路由表,找到ppp网络接口,然后调用ppp_start_xmit函数,此时控制就转移到PPP协议处理模块了。ppp_start_xmit调用函数ppp_xmit_process去发送队列中的所有数据包,ppp_xmit_process又调用ppp_send_frame去发送单个数据包, ppp_send_frame根据设置,调用压缩等扩展处理之后,又经ppp_push调用pch->chan->ops->start_xmit发送数据包。pch->chan->ops->start_xmit是什么?它就是具体的传输方式了,比如说对于串口发送方式,则是ppp_async.c: ppp_asynctty_open中注册的ppp_async_send函数,ppp_async_sendppp_async_push函数调用tty->driver->write把数据发送串口。

接收数据

接收数据的情形又是如何的?ppp_async.c在初始化(ppp_async_init),调用tty_register_ldisc向tty注册了行规程处理接口,也就是一组回调函数,当串口tty收到数据时,它就会回调ppp_ldisc的 ppp_asynctty_receive函数接收数据。ppp_asynctty_receive调用ppp_async_input把数据buffer转换成sk_buff,并放入接收队列ap->rqueue中。ppp_async另外有一个tasklet(ppp_async_process)专门处理接收队列ap->rqueue中的数据包,ppp_async_process一直挂在接收队列ap->rqueue上,一旦被唤醒,它就调用ppp_input函数让PPP协议处理模块处理该数据包。
    在ppp_input函数中,数据被分成两路,一路是控制协议数据包,放入pch->file.rqb队列,交给pppd处理。另外一路是用户数据包,经ppp_do_recv/ppp_receive_frame进行PPP处理之后,再由netif_rx提交给上层协议处理,最后经 socket传递到应用程序。

 



2011-12-27 11:53:05 jmq_0000 阅读数 6714

什么是PPP

PPP是一种网络中最为基础的协议。PPP协议(Point-to-Point Protocol)是一种数据链路层协议,它是为在同等单元之间传输数据包这样的简单链路而设计的。这种链路提供全双工操作,并按照顺序传递数据包。PPP为基于各种主机、网桥和路由器的简单连接提供一种共通的解决方案。

PPP协议包括以下三个部分:

1. 数据帧封装方法。

2. 链路控制协议LCP(Link Control Protocol):它用于对封装格式选项的自动协商,建立和终止连接,探测链路错误和配置错误。

3. 针对不同网络层协议的一族网络控制协议NCP(Network Control Protocol): PPP协议规定了针对每一种网络层协议都有相应的网络控制协议,并用它们来管理各个协议不同的需求。

PPP认证方式
  1. 口令验证协议(PAP)
  PAP 是一种简单的明文验证方式。NAS(网络接入服务器,Network Access Server)要求用户提供用户名和口令,PAP以明文方式返回用户信息。

  2. 挑战-握手验证协议(CHAP) 
   CHAP是一种加密的验证方式,能够避免建立连接时传送用户的真实密码。NAS向远程用户发送一个挑战口令(challenge),其中包括会话ID和 一个任意生成的挑战字串(arbitrary challenge string)。远程客户必须使用MD5单向哈希算法(one-way hashing algorithm)返回用户名和加密的挑战口令,会话ID以及用户口令,称为Secret Password,其中用户名以非哈希方式发送。


linux中PPP怎样实现的

PPP 协议之下是以太网和串口等物理层,之上是IP协议等网络层。这里,对于下层,我们只讨论串口的情况,对于上层,我们只讨论TCP/IP的情况。发送 时,TCP/IP数据包经过PPP打包之后经过串口发送。接收时,从串口上来的数据经PPP解包之后上报给TCP/IP协议层。linux下ppp框架结构如下图:

image

PPP协议栈

主要负责PPP层数据的封装、压缩与解压缩.另外,它还对普通数据包和Ppp过程的数据包进行了分流,将普通数据包提交到TCP/IP协议栈,而将Ppp过程的数据包放到/dev/ppp设备队列中,等待Pppd去收取并处理.



PPP 是一个分层结构。在底层,它能使用同步媒介(如 ISDN 或同步 DDN 专线),也能适用异步媒介(如基于 Modem 拨号的 PSTN 网络)。在数据链路层,PPP 在链路建立方面提供了丰富的服务,这些服务以 LCP 协商选项的形式提供。在上层,PPP 通过 NCPs 提供对多种网络层协议的支持。PPP 对于每一种网络层协议都有一种封装格式来区别它们的报文。

什么是pppd

pppd是一个用户空间的后台服务进程(daemon。pppd实现了所有鉴权、压缩/解压和加密/解密等扩展功能的控制协议。pppd只是一个普通的用户进程,pppd与内核中的PPP协议处理模块之间通过设备文件(/dev/ppp)进行通信pppd有一个辅助工具chat,用来与GSM模组建立会话。它向串口发送AT命令,建立与GSM模组的会话,以便让PPP协议可以在串口上传输数据包。


/dev/ppp

设备文件/dev/ppp。通过read系统调用,pppd可以读取PPP协议处理模块的数据包,当然,PPP协议处理模块只会把应该由pppd处理的数据包发给pppd。通过write系统调用,pppd可以把要发送的数据包传递给PPP协议处理模块。通过ioctrl系统调用,pppd可以设置PPP协议的参数,可以建立/关闭连接。在pppd里,每种协议实现都在独立的C文件中,它们通常要实现protent接口,该接口主要用于处理数据包,和fsm_callbacks接口,该接口主要用于状态机的状态切换。数据包的接收是由main.c: get_input统一处理的,然后根据协议类型分发到具体的协议实现上。而数据包的发送则是协议实现者根据需要调用output函数完成的

发送数据

应用程序通过socket 接口发送TCP/IP数据包,这些TCP/IP数据包如何流经PPP协议处理模块,然后通过串口发送出去呢?pppd在make_ppp_unit函数调用ioctrl(PPPIOCNEWUNIT)创建一个网络接口(如ppp0),内核中的PPP协议模块在处理PPPIOCNEWUNIT时,调用register_netdev向内核注册ppp的网络接口,该网络接口的传输函数指向ppp_start_xmit。当应用程序发送数据时,内核根据IP地址和路由表,找到ppp网络接口,然后调用ppp_start_xmit函数,此时控制就转移到PPP协议处理模块了。ppp_start_xmit调用函数ppp_xmit_process去发送队列中的所有数据包,ppp_xmit_process又调用ppp_send_frame去发送单个数据包, ppp_send_frame根据设置,调用压缩等扩展处理之后,又经ppp_push调用pch->chan->ops->start_xmit发送数据包。pch->chan->ops->start_xmit是什么?它就是具体的传输方式了,比如说对于串口发送方式,则是ppp_async.c: ppp_asynctty_open中注册的ppp_async_send函数,ppp_async_sendppp_async_push函数调用tty->driver->write把数据发送串口。

接收数据

接收数据的情形又是如何的?ppp_async.c在初始化(ppp_async_init),调用tty_register_ldisc向tty注册了行规程处理接口,也就是一组回调函数,当串口tty收到数据时,它就会回调ppp_ldisc的 ppp_asynctty_receive函数接收数据。ppp_asynctty_receive调用ppp_async_input把数据buffer转换成sk_buff,并放入接收队列ap->rqueue中。ppp_async另外有一个tasklet(ppp_async_process)专门处理接收队列ap->rqueue中的数据包,ppp_async_process一直挂在接收队列ap->rqueue上,一旦被唤醒,它就调用ppp_input函数让PPP协议处理模块处理该数据包。
    在ppp_input函数中,数据被分成两路,一路是控制协议数据包,放入pch->file.rqb队列,交给pppd处理。另外一路是用户数据包,经ppp_do_recv/ppp_receive_frame进行PPP处理之后,再由netif_rx提交给上层协议处理,最后经 socket传递到应用程序。

 




2008-09-24 16:02:00 lxy9712 阅读数 425

搞了这么多年的嵌入式,还是刚开始接触Linux应用层的东东,说来惭愧!

见贤思齐焉,见不贤而内自省也!扬鞭猛追吧!

先说下目的:嵌入式MIPS上跑Linux,接CDMA模块发送数据。

根据多年的耳濡目染,怎么着也明白网络的7层模型了,呵呵。欲通过CDMA发送数据,就要用PPP协议拨通CDMA模块,而PPP协议处于7层协议中的第2层:数据链路层,物理层的东东偶就不管拉,有模块去做了,要不然花钱干嘛:)。

所谓链路层,就像局域网中的RTL8139,古董拨号的SLP,都是处于TCP/IP之下的,只要数据链路通了,其他程序还是照旧!改用socket的还用socket,UDP,TCP都还好使。

废话少说,回到关注PPP上。一顿猛搜,原来还有pppd,chat这样的好东东,哎,做底层习惯了,什么都想自己搞,看来上层也有上层的方式。

先下载ppp-2.4.4,这东东好,里面就包含了pppd和chat,首先编译。

1.执行./configure来产生makefile,主要是ppp-2.4.4支持多个操作系统,执行之后会产生正确操作系统的makefile文件。

2。由于是嵌入式上的,就要用交叉编译,所以修改makefile,把编译器改到自己的。

CC = $(CROSS_COMPILE)gcc

如果你想安装的时候不安装在本机根目录下,就要指定INSTROOT的路径,这里设为:
INSTROOT = /usr/workroom/ppp/prebuild

3。一切具备,编译,make & make install,这样就产生了完备的路径和执行文件,我们看到在INSTROOT/usr/local/sbin会多了几个文件:chat,pppd,pppstats,pppdump。

4。得到这些东东后,拿到target板上试下,pppd --help,呵呵,果然出来了。

先写到这里,下面就要调试了。

Linux PPP密码

阅读数 492

/etc/ppp/pap-secrets 

博文 来自: cnbird2008

Linux PPP详细介绍

阅读数 1211

Linux之PPP配置

阅读数 691

Linux PPP详细介绍

阅读数 806

Linux HowTo: PPP

阅读数 1070

没有更多推荐了,返回首页