USB 3G上网卡讲解之三
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上网卡讲解之三相关推荐
- USB 3G上网卡讲解之一
转载了一个比较详细的关于USB 3G上网卡的讲解,原文地址: http://blog.chinaunix.net/uid-20786208-id-3157021.html USB 3G卡热插拔那些事1 ...
- 使用USB 3G上网卡+树莓派搭建接受短信自动转发邮箱的服务
背景:人在国外刚下飞机 咳咳,人在国外,国内很多网络,电话服务都需要短信验证,一直以来都用的双卡手机来解决这个问题.最近换了单卡手机,琢磨着3g上网卡应该可以接受短信,再配合7D24H运行的树莓派 ...
- 3G上网卡2_编程自动切换模式学习笔记
为什么要切换模式: 3G上网卡自带程序,接到PC后先作为移动硬盘使用,安装程序后切换为modem 如何自动切换模式 1. 编写控制程序自动使用各种型号3G上网卡 a. usb_modeswitch - ...
- 中兴AC2746 usb接口的3G上网卡
嵌入式linux是2.6.24版的.主机是AT9261(arm926ej-s内核)的开发板. 买是市面上常见的中兴AC2746 usb接口的3G上网卡.在windows下使用极方便,可是在linux下 ...
- openwrt使用3G上网卡
尊敬的大大.感谢你抽空指导我 我的设备是db120 mu350 和广东无限卡 版本是OpenWrt Backfire 10.03.336 DIY full 一. 没有安装到kmod-us ...
- 联通3g上网卡 linux驱动,驱动天空 - 网络设备 - 联通3G上网卡WCDMA
2015/3/6 14:19:001451 ·D-Link DWM-157联通3G上网卡 网络协议:[3G]UMTS,HSPA+:[2G]GSM,EDGE,GPRS 传输速率:下行最大14.4Mbps ...
- 3G上网卡在Liunx系统上实现上网的过程
1 前言 最近因项目需要将3G 上网卡挂接到Linux的网关平台,经过一段时间的研究,基本将整个挂 接过程弄清,在此贴出来与大家共享 2 正文 首先,我们来了解一下3G上网卡的组成: USB+USB ...
- Linux中移植3G上网卡
本文所用到的源码下载地址如下: libusb-1.0.9.tar.bz2 下载地址点击这里! usb-modeswitch-2.0.1.tar.bz2 下载地址点击这里! usb- ...
- FL2440 3G上网卡拨号上网,并实现mdev自动挂载
___________________________________ 主机操作系统:Centos 6.5 交叉编译器环境:arm-linux-gcc-4.5.4 开发板平台: FL2440 ...
最新文章
- Halcon与QT的联合编程(1)
- 兑吧:游戏化玩转用户运营的三驾马车
- 一位同学想通过用计算机编程解决韩信点兵,高中信息技术《算法与程序设计模块》练习题...
- python准备_python环境准备
- PHP的mysqli操作DB
- 5G改变物联网解决方案的6种方式
- thymeleaf 学习笔记
- linux中xjvf指令,linux解压缩命令小结
- 利用envi对landsat8数据进行处理
- docker 安装 jdk,配置环境变量
- Golang基本数据类型的相互转换
- php 数组重复最多,PHP获取数组中重复最多元素的简单示例
- Sun Java认证
- 【学术篇】2.28测试T2 线段 拓扑排序
- linux内核类型lagency,使用u盘安装linux(manjaro)时Grub报错
- PCB 18种特殊走线的画法与技巧!
- C语言——逻辑运算符
- idea如何连接夜神模拟器
- catia今天突然打不开了_catia打不开的解答
- python求零点极点增益_传递函数的零点、极点怎么解释,有什么用?
热门文章
- AGM AG1280 CPLD
- multisim 或门74ls32
- 应届生论坛求职分享:最好的莫过于如愿以偿(阿里、去哪儿网、360、华为、中兴offer都到碗里来)
- 利用GIZA++和Moses生成双向对齐文件
- python刷票 黑科技_抢火车票这个事吧,其实我也能做!(python黑科技)
- 中建材信息再转型背后:驶入数字化时代新蓝海
- 计算机地图综合制图实验报告,计算机地图制图实验报告071.doc
- JavaScript—jQuery
- iOS 开发----个人开发者帐号升级为公司开发者帐号
- docker制作个人博客