PPP interface for lwIP

//原文 地址 :http://www.nongnu.org/lwip/2_0_x/group__ppp.html


/*  //协议说明,2017年6月29日14:19:18,suozhang

PPP interface for lwIP

Author: Sylvain Rochet

Table of Contents:

1 - Supported PPP protocols and features
2 - Raw API PPP example for all protocols
3 - PPPoS input path (raw API, IRQ safe API, TCPIP API)
4 - Thread safe PPP API (PPPAPI)
5 - Notify phase callback (PPP_NOTIFY_PHASE)
6 - Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x

1 Supported PPP protocols and features
======================================

Supported Low level protocols:
* PPP over serial using HDLC-like framing, such as wired dialup modems
  or mobile telecommunications GPRS/EDGE/UMTS/HSPA+/LTE modems
* PPP over Ethernet, such as xDSL modems
* PPP over L2TP (Layer 2 Tunneling Protocol) LAC (L2TP Access Concentrator),
  IP tunnel over UDP, such as VPN access

Supported auth protocols:
* PAP, Password Authentication Protocol
* CHAP, Challenge-Handshake Authentication Protocol, also known as CHAP-MD5
* MSCHAPv1, Microsoft version of CHAP, version 1
* MSCHAPv2, Microsoft version of CHAP, version 2
* EAP, Extensible Authentication Protocol

Supported address protocols:
* IPCP, IP Control Protocol, IPv4 addresses negotiation
* IP6CP, IPv6 Control Protocol, IPv6 link-local addresses negotiation

Supported encryption protocols:
* MPPE, Microsoft Point-to-Point Encryption

Supported compression or miscellaneous protocols, for serial links only:
* PFC, Protocol Field Compression
* ACFC, Address-and-Control-Field-Compression
* ACCM, Asynchronous-Control-Character-Map
* VJ, Van Jacobson TCP/IP Header Compression

*/

/*  //2 Raw API PPP example for all protocols
=======================================

As usual, raw API for lwIP means the lightweight API which *MUST* only be used
for NO_SYS=1 systems or called inside lwIP core thread for NO_SYS=0 systems.

*/

/* Globals  全局变量
 * Globals  全局变量
 * =======
 */

/* The PPP control block */
ppp_pcb *ppp;

/* The PPP IP interface */
struct netif ppp_netif;

/* //PPP status callback  状态回调函数
 * PPP status callback  状态回调函数
 * ===================
 *
 * PPP status callback is called on PPP status change (up, down, …) from lwIP
 * core thread
 */

/* PPP status callback example */
static void status_cb(ppp_pcb *pcb, int err_code, void *ctx)
{
  struct netif *pppif = ppp_netif(pcb);
  LWIP_UNUSED_ARG(ctx);

  switch(err_code)
  {
    case PPPERR_NONE:
    {
        #if LWIP_DNS
              const ip_addr_t *ns;
        #endif /* LWIP_DNS */
              printf("status_cb: Connected\n");
        #if PPP_IPV4_SUPPORT
              printf("   our_ipaddr  = %s\n", ipaddr_ntoa(&pppif->ip_addr));
              printf("   his_ipaddr  = %s\n", ipaddr_ntoa(&pppif->gw));
              printf("   netmask     = %s\n", ipaddr_ntoa(&pppif->netmask));
        #if LWIP_DNS
              ns = dns_getserver(0);
              printf("   dns1        = %s\n", ipaddr_ntoa(ns));
              ns = dns_getserver(1);
              printf("   dns2        = %s\n", ipaddr_ntoa(ns));
        #endif /* LWIP_DNS */
        #endif /* PPP_IPV4_SUPPORT */
        #if PPP_IPV6_SUPPORT
              printf("   our6_ipaddr = %s\n", ip6addr_ntoa(netif_ip6_addr(pppif, 0)));
        #endif /* PPP_IPV6_SUPPORT */
              break;
    }
    case PPPERR_PARAM:
    {
      printf("status_cb: Invalid parameter\n");
      break;
    }
    case PPPERR_OPEN:
    {
      printf("status_cb: Unable to open PPP session\n");
      break;
    }
    case PPPERR_DEVICE:
    {
      printf("status_cb: Invalid I/O device for PPP\n");
      break;
    }
    case PPPERR_ALLOC:
    {
      printf("status_cb: Unable to allocate resources\n");
      break;
    }
    case PPPERR_USER:
    {
      printf("status_cb: User interrupt\n");
      break;
    }
    case PPPERR_CONNECT:
    {
      printf("status_cb: Connection lost\n");
      break;
    }
    case PPPERR_AUTHFAIL:
    {
      printf("status_cb: Failed authentication challenge\n");
      break;
    }
    case PPPERR_PROTOCOL:
    {
      printf("status_cb: Failed to meet protocol\n");
      break;
    }
    case PPPERR_PEERDEAD:
    {
      printf("status_cb: Connection timeout\n");
      break;
    }
    case PPPERR_IDLETIMEOUT:
    {
      printf("status_cb: Idle Timeout\n");
      break;
    }
    case PPPERR_CONNECTTIME:
    {
      printf("status_cb: Max connect time reached\n");
      break;
    }
    case PPPERR_LOOPBACK:
    {
      printf("status_cb: Loopback detected\n");
      break;
    }
    default:
    {
      printf("status_cb: Unknown error code %d\n", err_code);
      break;
    }
  }

/*
 * This should be in the switch case, this is put outside of the switch
 * case for example readability.
 */

  if (err_code == PPPERR_NONE) {
    return;
  }

  /* ppp_close() was previously called, don‘t reconnect */
  if (err_code == PPPERR_USER) {
    /* ppp_free(); -- can be called here */
    return;
  }

  /*
   * Try to reconnect in 30 seconds, if you need a modem chatscript you have
   * to do a much better signaling here ;-)
   */
  ppp_connect(pcb, 30);
  /* OR ppp_listen(pcb); */
}

/* 需要包含 头文件
 * Creating a new PPPoS session
 * ============================
 *
 * In lwIP, PPPoS is not PPPoSONET, in lwIP PPPoS is PPPoSerial.
 */

#include "netif/ppp/pppos.h"

/* PPP协议串口 输出 回调函数
 * PPPoS serial output callback
 *
 * ppp_pcb, PPP control block
 * data, buffer to write to serial port
 * len, length of the data buffer
 * ctx, optional user-provided callback context pointer
 *
 * Return value: len if write succeed
 */
static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx)
{
  return uart_write(UART, data, len);
}

/* 创建一个 PPPoS 通信 接口
 * Create a new PPPoS interface
 *
 * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
 * output_cb, PPPoS serial output callback
 * status_cb, PPP status callback, called on PPP status change (up, down, …)
 * ctx_cb, optional user-provided callback context pointer  用户自定义  回调函数指针
 */
ppp = pppos_create(&ppp_netif,output_cb, status_cb, ctx_cb);

/* 需要包含 头文件
 * Creating a new PPPoE session
 * ============================
 */

#include "netif/ppp/pppoe.h"

/* //创建一个 PPPoE 接口
 * Create a new PPPoE interface
 *
 * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
 * ethif, already existing and setup Ethernet interface to use
 * service_name, PPPoE service name discriminator (not supported yet)
 * concentrator_name, PPPoE concentrator name discriminator (not supported yet)
 * status_cb, PPP status callback, called on PPP status change (up, down, …)
 * ctx_cb, optional user-provided callback context pointer
 */
ppp = pppoe_create(&ppp_netif,&ethif,service_name, concentrator_name,status_cb, ctx_cb);

/*
 * Creating a new PPPoL2TP session
 * ===============================
 */

#include "netif/ppp/pppol2tp.h"

/* //创建一个 PPPoL2TP 接口
 * Create a new PPPoL2TP interface
 *
 * ppp_netif, netif to use for this PPP link, i.e. PPP IP interface
 * netif, optional already existing and setup output netif, necessary if you
 *        want to set this interface as default route to settle the chicken
 *        and egg problem with VPN links
 * ipaddr, IP to connect to
 * port, UDP port to connect to (usually 1701)
 * secret, L2TP secret to use
 * secret_len, size in bytes of the L2TP secret
 * status_cb, PPP status callback, called on PPP status change (up, down, …)
 * ctx_cb, optional user-provided callback context pointer
 */
ppp = pppol2tp_create(&ppp_netif,struct netif *netif, ip_addr_t *ipaddr, u16_t port,u8_t *secret, u8_t secret_len,ppp_link_status_cb_fn link_status_cb, void *ctx_cb);

/*  初始化 PPP  客户端 连接 为默认值
 * Initiate PPP client connection
 * ==============================
 */

/* Set this interface as default route */
ppp_set_default(ppp);

/*
 * Basic PPP client configuration. Can only be set if PPP session is in the
 * dead state (i.e. disconnected). We don‘t need to provide thread-safe
 * equivalents through PPPAPI because those helpers are only changing
 * structure members while session is inactive for lwIP core. Configuration
 * only need to be done once.
 */

/*
    * 基础 的PPP客户端 配置。一定能被设置在PPP 死亡 状态时,我们不需要提供线程安全
    * 通过PPPAPI等价物因为这些助手只是改变
    * 结构而lwIP会话不活跃的核心成员。配置
    * 只需要做一次。
*/

/* Ask the peer for up to 2 DNS server addresses. */
//请求 DNS 服务器 地址
ppp_set_usepeerdns(ppp, 1);

/* Auth configuration, this is pretty self-explanatory */
// 登陆用户 和  密码
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");

/*
 * Initiate PPP negotiation, without waiting (holdoff=0), can only be called
 * if PPP session is in the dead state (i.e. disconnected).
 */

 // 初始化 PPP 协商,没有等待(holdoff =0 )一定能被调用 如果 PPP 是死亡状态(即连接不成功)
u16_t holdoff = 0;
ppp_connect(ppp, holdoff);

/* 初始化  PPP server 监听
 * Initiate PPP server listener
 * ============================
 */

/*
 * Basic PPP server configuration. Can only be set if PPP session is in the
 * dead state (i.e. disconnected). We don‘t need to provide thread-safe
 * equivalents through PPPAPI because those helpers are only changing
 * structure members while session is inactive for lwIP core. Configuration
 * only need to be done once.
 */
ip4_addr_t addr;

/* Set our address */
IP4_ADDR(&addr, 192,168,0,1);
ppp_set_ipcp_ouraddr(ppp, &addr);

/* Set peer(his) address */
IP4_ADDR(&addr, 192,168,0,2);
ppp_set_ipcp_hisaddr(ppp, &addr);

/* Set primary DNS server */
IP4_ADDR(&addr, 192,168,10,20);
ppp_set_ipcp_dnsaddr(ppp, 0, &addr);

/* Set secondary DNS server */
IP4_ADDR(&addr, 192,168,10,21);
ppp_set_ipcp_dnsaddr(ppp, 1, &addr);

/* Auth configuration, this is pretty self-explanatory */
ppp_set_auth(ppp, PPPAUTHTYPE_ANY, "login", "password");

/* Require peer to authenticate */
ppp_set_auth_required(ppp, 1);

/*
 * Only for PPPoS, the PPP session should be up and waiting for input.
 *
 * Note: for PPPoS, ppp_connect() and ppp_listen() are actually the same thing.
 * The listen call is meant for future support of PPPoE and PPPoL2TP server
 * mode, where we will need to negotiate the incoming PPPoE session or L2TP
 * session before initiating PPP itself. We need this call because there is
 * two passive modes for PPPoS, ppp_set_passive and ppp_set_silent.
 */
ppp_set_silent(pppos, 1);

/*
 * Initiate PPP listener (i.e. wait for an incoming connection), can only
 * be called if PPP session is in the dead state (i.e. disconnected).
 */
ppp_listen(ppp);

/* 关闭 PPP  连接
 * Closing PPP connection
 * ======================
 */

/*
 * Initiate the end of the PPP session, without carrier lost signal
 * (nocarrier=0), meaning a clean shutdown of PPP protocols.
 * You can call this function at anytime.
 */
u8_t nocarrier = 0;
ppp_close(ppp, nocarrier);
/*
 * Then you must wait your status_cb() to be called, it may takes from a few
 * seconds to several tens of seconds depending on the current PPP state.
 */
//你必须等待 status_cb() 被调用以后,他 可能需要根据当前的状态来做决定 这个过程可能需要 10S左右
/*
 * Freeing a PPP connection
 * ========================
 */

/*
 * Free the PPP control block, can only be called if PPP session is in the
 * dead state (i.e. disconnected). You need to call ppp_close() before.
 */
ppp_free(ppp);

/*  //PPP 数据  根据情况 "选择" 函数分析,处理接口,suozhnag,2017年6月29日14:17:13

    3 PPPoS input path (raw API, IRQ safe API, TCPIP API)
    =====================================================

    Received data on serial port should be sent to lwIP using the pppos_input()
    function or the pppos_input_tcpip() function.

    接收数据从串行端口上 应该 设置 LWIP 使用  pppos_input() 接口。

    If NO_SYS is 1 and if PPP_INPROC_IRQ_SAFE is 0 (the default), pppos_input()
    is not IRQ safe and then *MUST* only be called inside your main loop.

    如果 没有系统的情况下 并且  PPP_INPROC_IRQ_SAFE 设置为0(默认),pppos_input()
    接口并不是安全 的 IRQ 那么 这个接口必须在 主循环中 调用。。

    Whatever the NO_SYS value, if PPP_INPROC_IRQ_SAFE is 1, pppos_input() is IRQ
    safe and can be safely called from an interrupt context, using that is going
    to reduce your need of buffer if pppos_input() is called byte after byte in
    your rx serial interrupt.

    无论是否使用系统运行LWIP,如果PPP_INPROC_IRQ_SAFE是1,pppos_input IRQ()是 IRQ安全,可以安全地从一个中断调用上下文,
    将减少你需要使用的缓冲区,如果pppos_input()在串行接收中断 每接收一个字节就调用一次。

    if NO_SYS is 0, the thread safe way outside an interrupt context is to use
    the pppos_input_tcpip() function to pass input data to the lwIP core thread
    using the TCPIP API. This is thread safe in all cases but you should avoid
    passing data byte after byte because it uses heavy locking (mailbox) and it
    allocates pbuf, better fill them !

    如果使用 系统 来运行 LWIP,使用pppos_input_tcpip()函数将输入数据传递给lwIP核心线程TCPIP API(外部中断上下文的线程安全的方法)。
    这是线程安全的在所有情况下,但你应该避免每接收一个字节就调用一次,因为它使用重型锁(邮箱)分配pbuf,更好的填补他们!

    if NO_SYS is 0 and if PPP_INPROC_IRQ_SAFE is 1, you may also use pppos_input()
    from an RX thread, however pppos_input() is not thread safe by itself. You can
    do that *BUT* you should NEVER call pppos_connect(), pppos_listen() and
    ppp_free() if pppos_input() can still be running, doing this is NOT thread safe
    at all. Using PPP_INPROC_IRQ_SAFE from an RX thread is discouraged unless you
    really know what you are doing, your move ;-)

    如果使用 系统 来运行 LWIP,并且PPP_INPROC_IRQ_SAFE设置为1,你可能需要使用 pppos_input()来输入数据从线程中接收,
    然而pppos_input()接口本身是不安全的。你诚挚的*BUT*你永远不应该叫pppos_connect(),pppos_listen()和ppp_free()
    如果pppos_input()仍然可以运行,这样做并不是线程安全的。使用PPP_INPROC_IRQ_SAFE从接收数据线程中是意气用事除非你知道
    你正在干什么。。2017年6月29日14:16:19,suozhang.

 */

/*
 * Fonction to call for received data
 *
 * ppp, PPP control block
 * buffer, input buffer
 * buffer_len, buffer length in bytes
 */
void pppos_input(ppp, buffer, buffer_len);

//or 两个接口 任选一个 

void pppos_input_tcpip(ppp, buffer, buffer_len);

/*  //实现 PPP 安全线程的接口,suozhang,2017年6月29日13:37:39

    4 Thread safe PPP API (PPPAPI)
    ==============================

    There is a thread safe API for all corresponding ppp_* functions, you have to
    enable LWIP_PPP_API in your lwipopts.h file, then see
    include/netif/ppp/pppapi.h, this is actually pretty obvious.

*/

/* //ppp 协议 阶段状态 回调函数 ,可以用于设置LED灯 方便直观 的看到 PPP协议处于什么阶段,suozhang,2017年6月29日13:35:59

    5 Notify phase callback (PPP_NOTIFY_PHASE)
    ==========================================

    Notify phase callback, enabled using the PPP_NOTIFY_PHASE config option, let
    you configure a callback that is called on each PPP internal state change.
    This is different from the status callback which only warns you about
    up(running) and down(dead) events.

    Notify phase callback can be used, for example, to set a LED pattern depending
    on the current phase of the PPP session. Here is a callback example which
    tries to mimic what we usually see on xDSL modems while they are negotiating
    the link, which should be self-explanatory:

*/

static void ppp_notify_phase_cb(ppp_pcb *pcb, u8_t phase, void *ctx)
{
  switch (phase)
    {

      /* Session is down (either permanently or briefly) */
      case PPP_PHASE_DEAD:
        led_set(PPP_LED, LED_OFF);
        break;

      /* We are between two sessions */
      case PPP_PHASE_HOLDOFF:
        led_set(PPP_LED, LED_SLOW_BLINK);
        break;

      /* Session just started */
      case PPP_PHASE_INITIALIZE:
        led_set(PPP_LED, LED_FAST_BLINK);
        break;

      /* Session is running */
      case PPP_PHASE_RUNNING:
        led_set(PPP_LED, LED_ON);
        break;

      default:
        break;
  }
}

/* //suozhang, 在老的版本上升级 PPP 协议 说明,2017年6月29日13:31:05,suozhang

6 Upgrading from lwIP <= 1.4.x to lwIP >= 2.0.x
===============================================

PPP API was fully reworked between 1.4.x and 2.0.x releases. However porting
from previous lwIP version is pretty easy:

* Previous PPP API used an integer to identify PPP sessions, we are now
  using ppp_pcb* control block, therefore all functions changed from "int ppp"
  to "ppp_pcb *ppp"

* struct netif was moved outside the PPP structure, you have to provide a netif
  for PPP interface in pppoX_create() functions

* PPP session are not started automatically after you created them anymore,
  you have to call ppp_connect(), this way you can configure the session before
  starting it.

* Previous PPP API used CamelCase, we are now using snake_case.

* Previous PPP API mixed PPPoS and PPPoE calls, this isn‘t the case anymore,
  PPPoS functions are now prefixed pppos_ and PPPoE functions are now prefixed
  pppoe_, common functions are now prefixed ppp_.

* New PPPERR_ error codes added, check you have all of them in your status
  callback function

* Only the following include files should now be used in user application:
  #include "netif/ppp/pppapi.h"
  #include "netif/ppp/pppos.h"
  #include "netif/ppp/pppoe.h"
  #include "netif/ppp/pppol2tp.h"

  Functions from ppp.h can be used, but you don‘t need to include this header
  file as it is already included by above header files.

* PPP_INPROC_OWNTHREAD was broken by design and was removed, you have to create
  your own serial rx thread

* PPP_INPROC_MULTITHREADED option was misnamed and confusing and was renamed
  PPP_INPROC_IRQ_SAFE, please read the "PPPoS input path" documentation above
  because you might have been fooled by that

* If you used tcpip_callback_with_block() on ppp_ functions you may wish to use
  the PPPAPI API instead.

* ppp_sighup and ppp_close functions were merged using an optional argument
  "nocarrier" on ppp_close.

* DNS servers are now only remotely asked if LWIP_DNS is set and if
  ppp_set_usepeerdns() is set to true, they are now automatically registered
  using the dns_setserver() function so you don‘t need to do that in the PPP
  callback anymore.

* PPPoS does not use the SIO API anymore, as such it now requires a serial
  output callback in place of sio_write

* PPP_MAXIDLEFLAG is now in ms instead of jiffies

*/
时间: 2024-11-03 20:35:02

PPP interface for lwIP的相关文章

无线环境+一体机(52台)+联想传奇软件

最近一个项目十分恶心,反复去了好多次都没解决问题,最后在求助的情况下解决了问题,今天闲来无事进行一下总结,希望以后大家在遇到类似问题的时候会有所帮助,少走弯路. 环境如下: 无线AP:华为AP7110DN-AGN   无线控制器:华为L-AC6605-16AP 交换机:华为S5700-28P-LI-AC  路由器:华为AR0M0022BA00 配置过程如下: 路由器配置: <router>dis cu[V200R003C01SPC900]# sysname router# snmp-agent

关于glibc中的res_init()函数

/* * Set up default settings.  If the configuration file exist, the values * there will have precedence.  Otherwise, the server address is set to * INADDR_ANY and the default domain name comes from the gethostname(). * * An interrim version of this c

双链路负载分担——MSTP+VRRP+OSPF

网络拓扑如图所示: 网络地址规划:vlan 2 10.147.140.0/26 vlan 3 10.147.140.64/26  用于行政楼段: vlan 4 10.147.140.128/26 vlan 5 10.147.140.192/26 用于中控楼段: vlan 10 10.147.141.0/30 vlan 11 10.147.141.4/30 vlan 12 10.147.141.8/30 vlan 13 10.147.141.12/30 用于核心交换机到路由器互联网段. 网络协议使

IPV6地址理解及配置

 理解: IPv6单播地址的类型可有多种,包括全球单播地址.链路本地地址和站点本地地址等. 1. 全球单播地址等同于IPv4公网地址,提供给网络服务提供商. 这种类型的地址允许路由前缀的聚合,从而限制了全球路由表项的数量. 2. 链路本地地址用于邻居发现协议和无状态自动配置中链路本地上节点 之间的通信.使用链路本地地址作为源或目的地址的数据报文不会被转发 到其他链路上. 3. 站点本地地址与IPv4中的私有地址类似.使用站点本地地址作为源或目 的地址的数据报文不会被转发到本站点(相当于一个私

华为Eudemon1000E配置实例

sysname Eudemon1000E# l2tp enable l2tp domain suffix-separator @# firewall packet-filter default permit interzone local trust direction inbound firewall packet-filter default permit interzone local trust direction outbound firewall packet-filter defa

中兴1800-2S多路由拨号上网实现过程

背景:某办公楼三层约15间办公室(终端数约30个)有互联网需求,楼栋综合布线已由房建单位实施完成,所有办公室网线汇聚至2楼机房.机房现有华为MA5620 电信PON网络ONU一台,宽带拨号账号3个(每条宽带20M带宽).中兴1800-2S多业务路由器1台,中兴5250交换机1台. 方案1:由电信提供的三合一机顶盒3个,对应3个宽带帐号:在交换机上划分3个VLAN,一个VLAN对应一个宽带帐号,实现上网. 方案2:三个宽带账号全部接入中兴路由器,相当于一条60M的"专线",交换机下接入所

devices-list

转自:https://www.kernel.org/pub/linux/docs/lanana/device-list/devices-2.6.txt LINUX ALLOCATED DEVICES (2.6+ version) Maintained by Torben Mathiasen <[email protected]> Last revised: 25 January 2005 This list is the Linux Device List, the official regi

软件公司开发网络环境搭建

一.一路光纤多个公网IP设置 公司192.168.1.0/24子网用于服务器集群,192.168.0.0/24子网用于办公子网,两个子网物理上不在一块. 公司开业时,申请了电信40Mbps专线光纤,5个IP地址,网关:*.168.112.9  255.255.255.248,地址块:*.168.112.10-14,电信公司送了一个光猫,一个路由器,5个公网IP是绑定在一起的,现在需要把公网IP设置在路由器,方便以后服务器向外发布信息,方法有二: 1.从电信送的路由器上拉多条网线到H3C-MSR9

distribute-list分发列表 转自 红茶三杯sina blog

distribute-list分发列表  (2013-07-07 10:46:09) 转载▼ 标签:  distribute-list  分发列表 分类: Routing 一.工具概述 distribute-list分发列表是用于控制路由更新的一个工具,只能过滤路由信息,不能过滤LSA. 如上图,R1.R2.R3运行RIP.R2在初始情况下,会将自己的路由表更新给R1,其中假设包含三条路由1.0.2.0及3.0.现在我们可以通过在R2上部署分发列表distribute-list,使得R2在更新给