USB 3G卡热插拔那些事4——pppd

在上一节中我们知道3G卡设备驱动已经加载好了,并且和ttyUSB*已经绑定成功,意味着我们可以拨号了,和3G卡内部3G模块通信了,而我们知道3G模块通信是tty设备,通过串行设备,这里和3G卡的两种工作模式相吻合—modem模式.
首先我们这里先给出3G工作原理图:

我们万事俱备只欠东风了,就是pppd拨号了,当然pppd的源码自己可以去网上下载最新的,自己编译(这里我们只说linux环境的).安装好pppd程序后,我们运行pppd拨号,当然在拨号前我们需要配置下我们的pppd才能完美的工作,才能真正为我们对于的tty驱动和3g驱动运作起来.
主要看pppd运行参数文件/etc/ppp/options(这个参数文件名字,看开发者自己是可以修改的)该文件指定pppd运行的参数,若运行pppd时通过命令行指定参数同时出现时,则选择/etc/ppp/options中的配置.下面我们就看相关的参数:(这里贴上我的配置)

#Copyright (c) 2017 tangbin
#set debug ,send message to /var/log/messages
debug
#To keep pppd on the terminal
nodetach  #若指定updetach则拨号成功后放入后台运行,若为nodetach,则在前台执行
lock  #创建一个锁定文件,其他程序在发现存在这个文件后,就能得知相应的串口已经被使用
#set seriral
/dev/ttyUSB3  #指定连接使用的设备
# set baudrate
115200    #传输速率
user "tangbin"
password "tangbin"
# set flowrate
crtscts  #硬件流控,无硬件流控为nocrtscts
show-password
usepeerdns  #使用服务器端协商的DNS就可以设置参数usepeerdns
noauth
noipdefault  #不使用默认IP就可以加入参数noipdefault
novj  #选中这个选项,将关闭双方的Van Jacobson形式TCP/IP报文头压缩
novjccomp  #选中这个选项,将关闭Van Jacobson形式TCP/IP报文头压缩中的连接ID压缩。Pppd将忽略来自Van Jacobson形式压缩TCP/IP报文头中的连接ID字节,也不要求对方这样做。
noccp  #关闭压缩控制协议协商
# Accept the peer's idea of our local IP address
ipcp-accept-local
# ipcp-accept-remote
ipcp-accept-remote  #pppd将会接受彼端对於它的IP位址的意见,即使远端的IP位址已经在某个选项中指定
connect '/usr/sbin/chat -s -v -f /etc/ppp/peers/wcdma-chat-connect'
disconnect '/usr/sbin/chat -s -v -f /etc/ppp/peers/wcdma-chat-disconnect'

这些信息我们都可以从pppd源码包的帮助文件中获取信息,pppd/tty.c中的函数connect_tty()将会执行这个脚本。主要是对客户端的拨号的应答。
connect '/usr/sbin/chat -s -v -f /etc/ppp/peers/wcdma-chat-connect'
在pppd运行开始,要初始化tty. 就是调用tty_init()
下面给出pppd相关代码:

    /** Initialize each protocol.*/for (i = 0; (protp = protocols[i]) != NULL; ++i)(*protp->init)(0);/** Initialize the default channel.*/tty_init();

展开tty_init():

void tty_init()
{add_notifier(&pidchange, maybe_relock, 0);the_channel = &tty_channel;xmit_accm[3] = 0x60000000;
}

我们看到里面the_channel = &tty_channel;的操作,struct channel *the_channel;(main.c中)是一个全局变量.

/** This struct contains pointers to a set of procedures for* doing operations on a "channel".  A channel provides a way* to send and receive PPP packets - the canonical example is* a serial port device in PPP line discipline (or equivalently* with PPP STREAMS modules pushed onto it).*/
struct channel {/* set of options for this channel */option_t *options;/* find and process a per-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));/* we're finished with the channel */void (*disconnect) __P((void));/* 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 PPP 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));
};extern struct channel *the_channel;

在ppp.h中定义,并声明.
下面看看如何初始化的

struct channel tty_channel = {tty_options,&tty_process_extra_options,&tty_check_options,&connect_tty,&disconnect_tty,&tty_establish_ppp,&tty_disestablish_ppp,&tty_do_send_config,&tty_recv_config,&cleanup_tty,&tty_close_fds
};

同理这里我们只关注&connect_tty, 这个初始化在tty.c中.

/** connect_tty - get the serial port ready to start doing PPP.* That is, open the serial port, set its speed and mode, and run* the connector and/or welcomer.*/
int connect_tty()
{char *connector;int fdflags;
#ifndef __linux__struct stat statbuf;
#endifchar numbuf[16];/** Get a pty master/slave pair if the pty, notty, socket,* or record options were specified.*/strlcpy(ppp_devnam, devnam, sizeof(ppp_devnam));pty_master = -1;pty_slave = -1;real_ttyfd = -1;if (using_pty || record_file != NULL) {if (!get_pty(&pty_master, &pty_slave, ppp_devnam, uid)) {error("Couldn't allocate pseudo-tty");status = EXIT_FATAL_ERROR;
            return -1;}set_up_tty(pty_slave, 1);}/** Lock the device if we've been asked to.*/status = EXIT_LOCK_FAILED;if (lockflag && !privopen) {if (lock(devnam) < 0)goto errret;locked = 1;}/** Open the serial device and set it up to be the ppp interface.* First we open it in non-blocking mode so we can set the* various termios flags appropriately.  If we aren't dialling* out and we want to use the modem lines, we reopen it later* in order to wait for the carrier detect signal from the modem.*/ got_sigterm = 0;connector = doing_callback? callback_script: connect_script;if (devnam[0] != 0) {for (;;) {/* If the user specified the device name, become theuser before opening it. */int err, prio;...

这里我们要特别注意/**/中的注释部分. 就是在这里我们的ppp和tty联系了起来,才真正work. 当然还加载了前面的脚本文件,来获取必要的配置信息.
tty_init()完成后,就是来和ppp内核协议通信来建立必要的ppp网络接口,以供上层应用程序用

     /** If we're doing dial-on-demand, set up the interface now.*/if (demand) {/** Open the loopback channel and set it up to be the ppp interface.*/fd_loop = open_ppp_loopback();set_ifunit(1);/** Configure the interface and mark it up, etc.*/demand_conf();}

在open_ppp_loopback()这个函数中调用 make_ppp_unit()建立ppp0接口(当然这个接口名我们也可以自定义)

  /** make_ppp_unit - make a new ppp unit for ppp_dev_fd.* Assumes new_style_driver.*/
static int make_ppp_unit()
{int x, flags;if (ppp_dev_fd >= 0) {dbglog("in make_ppp_unit, already had /dev/ppp open?");close(ppp_dev_fd);}ppp_dev_fd = open("/dev/ppp", O_RDWR);if (ppp_dev_fd < 0)fatal("Couldn't open /dev/ppp: %m");flags = fcntl(ppp_dev_fd, F_GETFL);if (flags == -1|| fcntl(ppp_dev_fd, F_SETFL, flags | O_NONBLOCK) == -1)warn("Couldn't set /dev/ppp to nonblock: %m");ifunit = req_unit;x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);if (x < 0 && req_unit >= 0 && errno == EEXIST) {warn("Couldn't allocate PPP unit %d as it is already in use", req_unit);ifunit = -1;x = ioctl(ppp_dev_fd, PPPIOCNEWUNIT, &ifunit);}if (x < 0)error("Couldn't create new ppp unit: %m");return x;
}

这里我们看到open函数打开了/dev/ppp ,然后发送一个ioctl给ppp协议
在ppp协议里

  static struct file_operations ppp_device_fops = {.owner      = THIS_MODULE,.read       = ppp_read,.write      = ppp_write,.poll       = ppp_poll,.ioctl      = ppp_ioctl,.open       = ppp_open,.release    = ppp_release
};

ppp_ioctl调用ppp_unattached_ioctl(),在这个函数里

    switch (cmd) {case PPPIOCNEWUNIT:/* Create a new ppp unit */if (copy_from_user(&req, p, sizeof req))break;ppp = ppp_create_interface(req.unit, &err, req.ifname);

ppp_create_interface来真正创建这个接口,以供将来应用程序使用.
既然tty和ppp都初始化了,也建立了某种联系,并且能一起协同工作了,那么我们还犹豫什么?
当然是start_link了
start_link(0);
在这个函数里我们才真正调用我们上面长篇大论的connect_tty().
建立连接的过程分两个阶段:LCP,PCAP.
pppd建立连接过程中chat辅助程序起到不可磨灭的作用.
pppd运行后作为一个守护进程来运行,它必然有监控程序,而这个就是handle_events.
有人认为我这里说这么多是扯淡,我感觉不是,为什么呢,虽然我们一般人直接用pppd拨号就可以,但是很多人并不知道为什么,为什么就把pppd、ppp协议、tty、3G模块联系起来的.这里分析下我想功夫不会是白费的.如果一旦出现问题,那么我们很容易定位问题的所在,知其然还要知其所以然.以后我们应该讲讲ppp相关的数据包收发流程.

USB 3G卡热插拔那些事5——PPP协议

或许我们把pppd拨号原理讲完已经万事大吉了,但是这里我想还是需要再说说ppp协议,我们知道3G拨号上网是通过ppp协议,利用的是ppp帧格式,就说3G卡吧,我知道3G卡首先是通过usb接口连接到设备,ppp–>tty–>Gsm/cdma/wcdma,我们在看Gsm/cdma/wcdma的驱动函数的时候,我们会发现usb相关的收发函数,为什么呢?因为在是通过usb接口连接的,那么在设备收发的时候,必须是urb包的形式才能被识别,然后才是Gsm/cdma/wcdma模块驱动,它是串行接口传输.所以在ppp协议到tty部分其实我们不用太关注其他的事情,用正常的理解就可以了.但是到了Gsm/cdma/wcdma模块的驱动部分就复杂了,为什么这么说,首先我们知道它关联了串行驱动tty,还有usb驱动.从硬件上它有一个usb转串的芯片.
前面说了这么多,那么我们就来分析下ppp协议,网上和书上已经有很多相关资料,我这里就偷工减料了^^
首先可以参考《tcp/ip协议卷1》、《linux网络体系结构-linux内核中网络协议的设计与实现》还可以参考网上一些前辈的文章加速理解.

链路控制协议LCP(Link Control Protocol);
网络控制协议NCP(Network Control Protocol);
认证协议:口令验证协议PAP(Password Authentication Protocol)和挑战握手验证协议CHAP(Challenge-Handshake Authentication Protocol)。



1、LCP协商,协商内容包括除RFC1661中所定义的选项之外,还要考虑PPPOA和PPPOE协议中规定的内容。
2、LCP协商过 后就到了Establish阶段,开始PAP或CHAP认证。PAP为两次握手认证,口令为明文。PAP认证过程如下:发送用户名同口令到认证方,认证方查看是否有此用户,口令是否正确,然后发送相应的响应。CHAP为三次握手认证,口令为密文(密钥)CHAP认证由认证方发送一些随机产生的报文,交给被认证方,被认证方用自己的口令字用MD5算法进行加密,传回密文,认证方用自己保存的口令字及随机报文用MD5算法加密,比较二者的密文,根据比较结果返回响应的响应。
3、认证成功即进行Network阶段协商(NCP),在IP接入中主要是IPCP协商(如IP地址和DNS地址的协商等)。任何阶段的协商失败都将导致链路的拆除。
4、协商成功,则链路建立成功,可以开始传输网络层数据报文。


1、PPP协议组成:
a) 链路控制协议(LCP-Link Control Protocol),完成线路的启动、测试、任选参数的协商和最终线路断开功能
b) 认证协议,最常用的包括口令验证协议PAP(Password Authentication Protocol)和挑战握手验证协议CHAP(Challenge-Handshake Authentication Protocol)
c) 用户认证,主要通过LCP协商采用何种认证协议,但认证协议本身不是PPP协议的范围
d) IP控制协议IPCP(网络控制协议(NCP)),最常用的NCP协议为。它的一个重要功能就是动态分配IP地址;
2、认证方式
2.1口令验证协议(PAP)
PAP是一种简单的明文验证方式。NAS(网络接入服务器,Network Access Server)要求用户提供用户名和口令,PAP以明文方式返回用户信息。很明显,这种验证方式的安全性较差,第三方可以很容易的获取被传送的用户名和口令,并利用这些信息与NAS建立连接获取NAS提供的所有资源。所以,一旦用户密码被第三方窃取,PAP无法提供避免受到第三方攻击的保障措施。
2.2挑战-握手验证协议(CHAP)
CHAP是一种加密的验证方式,能够避免建立连接时传送用户的真实密码。NAS向远程用户发送一个挑战口令(challenge),其中包括会话ID和一个任意生成的挑战字串(arbitrary challengestring)。远程客户必须使用MD5单向哈希算法(one-way hashing algorithm)返回用户名和加密的挑战口令,会话ID以及用户口令,其中用户名以非哈希方式发送。
CHAP对PAP进行了改进,不再直接通过链路发送明文口令,而是使用挑战口令以哈希算法对口令进行加密。因为服务器端存有客户的明文口令,所以服务器可以重复客户端进行的操作,并将结果与用户返回的口令进行对照。CHAP为每一次验证任意生成一个挑战字串来防止受到再现攻击(replay attack)。在整个连接过程中,CHAP将不定时的向客户端重复发送挑战口令,从而避免第3方冒充远程客户(remote client impersonation)进行攻击。
目前大多数模拟拨号连接都采用PPP做为数据链路协议,主要有下面特点:
错误检测
自动协商网络层地址
CHAP or PAP 认证
数据压缩
符合ISO标准
PPP和串行线路Internet协议(SLIP)常常使人混淆,SLIP仅仅支持IP协议,PPP支持IP、IPX、以及AppleTalk等多协议。
PPP将数据链路层为为3个子层:
NCP 建立和协商网络层协议及相应的地址
LCP 建立链路、认证用户和检测链路质量
HDLC 在链路上封装数据包
表2-1 概述PPP及其子层
OSI层 常见协议
第3层 IP、IPX、AppleTalk
第2层 NCP、LCP、HDLC
第1层 EIA/TIA-232、X.24、V.23、V.35和ISDN等
PPP的大多数扩展功能如数据纠错及支持多种网络协议等,都是由LCP和NCP来控制的。LCP用于配置和测试数

据链路,工作方式如下:
第1步 链路建立阶段―――首先打开连接,然后确定相关通信参数(包括MTU、compress type、及链路认证类型。链路设置完后确认帧,然后是可选的链路质量确认阶段,LCP确定链路质量
第2步 可选(必要)的认证阶段―――两种认证方式:质询应答握手认证协议(CHAP)和密码认证协议(PAP)。PPP本身不需要认证,cisco路由器异步线路需要认证,建议使用CHAP认证方式。
第3步 网络层协议阶段―――LCP引导NCP激活和配置网络层协议。这一阶段结束后即可传输数据包。
第4步 链路终止阶段―――LCP指导NCP关闭layer 3。
LCP使用3种类型LCP数据帧完成上述步骤:
链路建立帧(Link establishment frames)―――建立链路
链路终止帧(Link terminateon frames)―――关闭链路
链路维护帧(Link maintenance frames)―――维护链路
PPP 主要由以下几部分组成:
封装:一种封装多协议数据报的方法。PPP 封装提供了不同网络层协议同时在同一链路传输的多路复用技
术。PPP 封装精心设计,能保持对大多数常用硬件的兼容性。克服了SLIP不足之处的一种多用途、点到点协
议,它提供的WAN数据链接封装服务类似于LAN所提供的封闭服务。所以,PPP不仅仅提供帧定界,而且提供
协议标识和位级完整性检查服务。
链路控制协议:PPP 提供的 LCP 功能全面,适用于大多数环境。LCP 用于就封装格式选项自动达成一致
,处理数据包大小限制,探测环路链路和其他普通的配置错误,以及终止链路。LCP 提供的其他可选功能有
:认证链路中对等单元的身份,决定链路功能正常或链路失败情况。
网络控制协议:一种扩展链路控制协议,用于建立、配置、测试和管理数据链路连接。
配置:使用链路控制协议的简单和自制机制。该机制也应用于其它控制协议,例如:网络控制协议(NCP
)。
为了建立点对点链路通信,PPP 链路的每一端,必须首先发送 LCP 包以便设定和测试数据链路。在链路
建立,LCP 所需的可选功能被选定之后,PPP 必须发送 NCP 包以便选择和设定一个或更多的网络层协议。
一旦每个被选择的网络层协议都被设定好了,来自每个网络层协议的数据报就能在链路上发送了。
链路将保持通信设定不变,直到有 LCP 和 NCP 数据包关闭链路,或者是发生一些外部事件的时候(如,
休止状态的定时器期满或者网络管理员干涉)。
PPP工作流程:
当用户拨号接入 ISP 时,路由器的调制解调器对拨号做出确认,并建立一条物理连接。 PC 机向路由器发送一系列的 LCP 分组(封装成多个 PPP 帧)。
这些分组及其响应选择一些 PPP 参数,和进行网络层配置,NCP 给新接入的 PC机分配一个临时的 IP 地址,使 PC 机成为因特网上的一个主机。
通信完毕时,NCP 释放网络层连接,收回原来分配出去的 IP 地址。接着,LCP 释放数据链路层连接。最后释放的是物理层的连接。
PPP和HDLC之间最主要的区别是,PPP是面向字符的,HDLC是面向位的。
与PPP相关的RFC:
RFC1144 TCP/IP数据包压缩
RFC1220 PPP在网桥上的扩充
RFC1334 PPP认证协议
RFC1378 PPP AppleTalk控制协议(ATCP)
RFC1552 PPP互联网数据包交换控制协议(IPXCP)
RFC1570 PPP LCP协议扩充
RFC1661 PPP协议(PPP)
RFC1662 PPP中的HDLC封装
RFC1990 PPP多链路协议(MP)
上面是我从网上摘的一些片段,大致就是这个,这里我们不再具体分析ppp协议数据包具体收发函数流程.
下面我说一下pppoe相关的,因为这里我有点困惑,才搞明白.
首先我们知道ppp协议是针对串行传输的,那么它也有它自己的固定的帧格式,当然是不能直接在以太网上传输的,比如3G拨号,它没有通过以太网口,而是通过3g模块,以串行方式把数据发出去了,最后转行成无线信号. 但是我们知道:
以太网接口(WAN)支持三种连接模式:
·自动模式:即配置接口作为DHCP客户端,使用DHCP方式获取IP地址。
·手动模式:即手动为接口配置IP地址和子网掩码。
·PPPoE:即配置接口作为PPPoE客户端。PPPoE是Point-to-Point Protocol over Ethernet的简称,它利用以太网将大量主机组成网络,通过一个远端接入设备连入因特网,并对接入的每个主机实现控制、计费功能,极高的性能价格比使PPPoE在包括小区组网建设等一系列应用中被广泛采用。
它是和3G是不同的,那么这个时候就用到了pppoe模块,它把ppp协议的帧经过处理封装到以太网帧中传输到网络中.
两者的区别基本有两点:
1.3G不经过pppoe再封装.直接串口传输.
2.wan呢,则是需要pppoe封装的,因为它物理接口是以太网.

USB 3G上网卡讲解之三相关推荐

  1. USB 3G上网卡讲解之一

    转载了一个比较详细的关于USB 3G上网卡的讲解,原文地址: http://blog.chinaunix.net/uid-20786208-id-3157021.html USB 3G卡热插拔那些事1 ...

  2. 使用USB 3G上网卡+树莓派搭建接受短信自动转发邮箱的服务

    背景:人在国外刚下飞机   咳咳,人在国外,国内很多网络,电话服务都需要短信验证,一直以来都用的双卡手机来解决这个问题.最近换了单卡手机,琢磨着3g上网卡应该可以接受短信,再配合7D24H运行的树莓派 ...

  3. 3G上网卡2_编程自动切换模式学习笔记

    为什么要切换模式: 3G上网卡自带程序,接到PC后先作为移动硬盘使用,安装程序后切换为modem 如何自动切换模式 1. 编写控制程序自动使用各种型号3G上网卡 a. usb_modeswitch - ...

  4. 中兴AC2746 usb接口的3G上网卡

    嵌入式linux是2.6.24版的.主机是AT9261(arm926ej-s内核)的开发板. 买是市面上常见的中兴AC2746 usb接口的3G上网卡.在windows下使用极方便,可是在linux下 ...

  5. openwrt使用3G上网卡

    尊敬的大大.感谢你抽空指导我 我的设备是db120 mu350 和广东无限卡 版本是OpenWrt Backfire 10.03.336 DIY full 一.        没有安装到kmod-us ...

  6. 联通3g上网卡 linux驱动,驱动天空 - 网络设备 - 联通3G上网卡WCDMA

    2015/3/6 14:19:001451 ·D-Link DWM-157联通3G上网卡 网络协议:[3G]UMTS,HSPA+:[2G]GSM,EDGE,GPRS 传输速率:下行最大14.4Mbps ...

  7. 3G上网卡在Liunx系统上实现上网的过程

    1 前言 最近因项目需要将3G 上网卡挂接到Linux的网关平台,经过一段时间的研究,基本将整个挂 接过程弄清,在此贴出来与大家共享  2 正文 首先,我们来了解一下3G上网卡的组成: USB+USB ...

  8. Linux中移植3G上网卡

    本文所用到的源码下载地址如下: libusb-1.0.9.tar.bz2         下载地址点击这里! usb-modeswitch-2.0.1.tar.bz2   下载地址点击这里! usb- ...

  9. FL2440 3G上网卡拨号上网,并实现mdev自动挂载

    ___________________________________ 主机操作系统:Centos 6.5 交叉编译器环境:arm-linux-gcc-4.5.4 开发板平台: FL2440     ...

最新文章

  1. Halcon与QT的联合编程(1)
  2. 兑吧:游戏化玩转用户运营的三驾马车
  3. 一位同学想通过用计算机编程解决韩信点兵,高中信息技术《算法与程序设计模块》练习题...
  4. python准备_python环境准备
  5. PHP的mysqli操作DB
  6. 5G改变物联网解决方案的6种方式
  7. thymeleaf 学习笔记
  8. linux中xjvf指令,linux解压缩命令小结
  9. 利用envi对landsat8数据进行处理
  10. docker 安装 jdk,配置环境变量
  11. Golang基本数据类型的相互转换
  12. php 数组重复最多,PHP获取数组中重复最多元素的简单示例
  13. Sun Java认证
  14. 【学术篇】2.28测试T2 线段 拓扑排序
  15. linux内核类型lagency,使用u盘安装linux(manjaro)时Grub报错
  16. PCB 18种特殊走线的画法与技巧!
  17. C语言——逻辑运算符
  18. idea如何连接夜神模拟器
  19. catia今天突然打不开了_catia打不开的解答
  20. python求零点极点增益_传递函数的零点、极点怎么解释,有什么用?

热门文章

  1. AGM AG1280 CPLD
  2. multisim 或门74ls32
  3. 应届生论坛求职分享:最好的莫过于如愿以偿(阿里、去哪儿网、360、华为、中兴offer都到碗里来)
  4. 利用GIZA++和Moses生成双向对齐文件
  5. python刷票 黑科技_抢火车票这个事吧,其实我也能做!(python黑科技)
  6. 中建材信息再转型背后:驶入数字化时代新蓝海
  7. 计算机地图综合制图实验报告,计算机地图制图实验报告071.doc
  8. JavaScript—jQuery
  9. iOS 开发----个人开发者帐号升级为公司开发者帐号
  10. docker制作个人博客