前面我们已经打下了BLIP+RPL的基础,本次例程将全部使用 并添加UART的pppd拨号实现边界路由器;这个例程是核心中的核心;使用它我们可以查看网络路由表而不是再只是通过抓包来自己分析;使用它访问其他的zigbee节点,如下一篇带来的实验CoAPServer;
例程目录:tinyos-main-release_tinyos_2_1_2\apps\cc2538_Test\PppRouter
Makefile文件:前面的介绍大家应该已经清楚了写法,现在开始省略
PppRouterC.nc文件:
- #include <iprouting.h>
-
- #include "ppp.h"
-
- configuration PppRouterC {
- } implementation {
- components PppRouterP;
-
- components MainC;
- PppRouterP.Boot -> MainC;
-
- components LedsC as LedsC;
- PppRouterP.Leds -> LedsC;
-
- components PppDaemonC;
- PppRouterP.PppControl -> PppDaemonC;
-
- components PppIpv6C;
- PppDaemonC.PppProtocol[PppIpv6C.ControlProtocol] -> PppIpv6C.PppControlProtocol;
- PppDaemonC.PppProtocol[PppIpv6C.Protocol] -> PppIpv6C.PppProtocol;
- PppIpv6C.Ppp -> PppDaemonC;
- PppIpv6C.LowerLcpAutomaton -> PppDaemonC;
-
- PppRouterP.Ipv6LcpAutomaton -> PppIpv6C;
- PppRouterP.PppIpv6 -> PppIpv6C;
- PppRouterP.Ppp -> PppDaemonC;
-
- #if defined(PLATFORM_TELOSB) || defined(PLATFORM_EPIC)
- components PlatformHdlcUartC as HdlcUartC;
- #else
- components DefaultHdlcUartC as HdlcUartC;
- #endif
- PppDaemonC.HdlcUart -> HdlcUartC;
- PppDaemonC.UartControl -> HdlcUartC;
-
- // SDH : don't bother including the PppPrintfC by default
- // components PppPrintfC, PppC;;
- // PppPrintfC.Ppp -> PppDaemonC;
- // PppDaemonC.PppProtocol[PppPrintfC.Protocol] -> PppPrintfC;
- // PppPrintfC.Ppp -> PppC;
-
- components IPStackC, IPForwardingEngineP, IPPacketC;
- IPForwardingEngineP.IPForward[ROUTE_IFACE_PPP] -> PppRouterP.IPForward;
- PppRouterP.IPControl -> IPStackC;
- PppRouterP.ForwardingTable -> IPStackC;
- PppRouterP.IPPacket -> IPPacketC;
-
- #ifdef RPL_ROUTING
- components RPLRoutingC, RplBorderRouterP;
- PppRouterP.RootControl -> RPLRoutingC;
- RplBorderRouterP.ForwardingEvents -> IPStackC.ForwardingEvents[ROUTE_IFACE_PPP];
- RplBorderRouterP.IPPacket -> IPPacketC;
- #endif
-
- // UDP shell on port 2000
- components UDPShellC;
-
- // prints the routing table
- components RouteCmdC;
-
- #ifdef IN6_PREFIX
- components StaticIPAddressTosIdC; // Use TOS_NODE_ID in address
- //components StaticIPAddressC; // Use LocalIeee154 in address
- #else
- components Dhcp6C;
- components Dhcp6ClientC;
- PppRouterP.Dhcp6Info -> Dhcp6ClientC;
- #endif
- }
注意 components UDPShellC;
components RouteCmdC;这两个组件,自行去查看底层代码,原来测试命令中的route,heip等是他们定义的,参考他们的写法自己可以定义其他命令,如温度等
PppRouterP.nc文件:
- <span style="font-family: Arial, Helvetica, sans-serif;">/*********************************************************************************************************************************************************</span>
- *实验7----zigbee 边界路由实验
- *节点需求数 >= 2
- *编译命令make cc2538cb blip id.xx (xx为1~65533)
- *测试命令:
- *1,sudo /usr/bin/pppd-hack/sbin/pppd debug passive noauth nodetach 115200 /dev/ttyUSB0 nocrtscts nocdtrcts lcp-echo-interval 0 noccp noip ipv6 ::23,::24 连接边界路由
- *2,新打开shell,执行sudo ifconfig ppp0 add fec0::100/64
- *3,3.1和3.2为两种测试方法,采取一种即可
- * 3.1执行nc6 -u fec0::1 2000
- * route
- * ping6 ff02::xx(xx为1~65533,且为烧写的测试节点号
- * 3.2
- * ping6 ff02::xx(xx为1~65533,且为烧写的测试节点号
- * 也可以参考\apps\cc2538_Test\PppRouter下的README.blip进行测试,但是注意第一步命令pppd的区别
- * 更多命令支持请参考tinyos-main-release_tinyos_2_1_2\tos\lib\net\blip\shell的UDPShellP.nc文件,如help等,也可以自己添加入传感器等等
- ********************************************************************************************************************************************************/
-
- #include <stdio.h>
- #include <lib6lowpan/ip.h>
- #include <lib6lowpan/nwbyte.h>
- #include <lib6lowpan/ip_malloc.h>
- #include <dhcp6.h>
-
- #include "pppipv6.h"
- #include "blip_printf.h"
-
- module PppRouterP {
- provides {
- interface IPForward;
- }
- uses {
- interface Boot;
- interface Leds;
- interface SplitControl as IPControl;
- interface SplitControl as PppControl;
- interface LcpAutomaton as Ipv6LcpAutomaton;
- interface PppIpv6;
- interface Ppp;
-
- interface ForwardingTable;
- interface RootControl;
- interface Dhcp6Info;
- interface IPPacket;
- }
-
- } implementation {
-
- event void PppIpv6.linkUp() {}
- event void PppIpv6.linkDown() {}
-
- event void Ipv6LcpAutomaton.transitionCompleted (LcpAutomatonState_e state) { }
- event void Ipv6LcpAutomaton.thisLayerUp () { }
- event void Ipv6LcpAutomaton.thisLayerDown () { }
- event void Ipv6LcpAutomaton.thisLayerStarted () { }
- event void Ipv6LcpAutomaton.thisLayerFinished () { }
-
- event void PppControl.startDone (error_t error) { }
- event void PppControl.stopDone (error_t error) { }
-
- event void IPControl.startDone (error_t error) {
- struct in6_addr dhcp6_group;
-
- // add a route to the dhcp group on PPP, not the radio (which is the default)
- inet_pton6(DH6ADDR_ALLAGENT, &dhcp6_group);
- call ForwardingTable.addRoute(dhcp6_group.s6_addr, 128, NULL, ROUTE_IFACE_PPP);
-
- // add a default route through the PPP link
- call ForwardingTable.addRoute(NULL, 0, NULL, ROUTE_IFACE_PPP);
- }
- event void IPControl.stopDone (error_t error) { }
-
- event void Boot.booted() {
- error_t rc;
-
- #ifndef PRINTFUART_ENABLED
- rc = call Ipv6LcpAutomaton.open();
- rc = call PppControl.start();
- #endif
- #ifdef RPL_ROUTING
- call RootControl.setRoot();
- #endif
- #ifndef IN6_PREFIX
- call Dhcp6Info.useUnicast(FALSE);
- #endif
-
- call IPControl.start();
- }
-
- event error_t PppIpv6.receive(const uint8_t* data,
- unsigned int len) {
- struct ip6_hdr *iph = (struct ip6_hdr *)data;
- void *payload = (iph + 1);
- call Leds.led0Toggle();
- signal IPForward.recv(iph, payload, NULL);
- return SUCCESS;
- }
-
- command error_t IPForward.send(struct in6_addr *next_hop,
- struct ip6_packet *msg,
- void *data) {
- size_t len = iov_len(msg->ip6_data) + sizeof(struct ip6_hdr);
- error_t rc;
- frame_key_t key;
- const uint8_t* fpe;
- uint8_t* fp;
-
- if (!call PppIpv6.linkIsUp())
- return EOFF;
-
- // get an output frame
- fp = call Ppp.getOutputFrame(PppProtocol_Ipv6, &fpe, FALSE, &key);
- if ((! fp) || ((fpe - fp) < len)) {
- if (fp) {
- call Ppp.releaseOutputFrame(key);
- }
- call Leds.led2Toggle();
- return ENOMEM;
- }
-
- // copy the header and body into the frame
- memcpy(fp, &msg->ip6_hdr, sizeof(struct ip6_hdr));
- iov_read(msg->ip6_data, 0, len, fp + sizeof(struct ip6_hdr));
- rc = call Ppp.fixOutputFrameLength(key, fp + len);
- if (SUCCESS == rc) {
- rc = call Ppp.sendOutputFrame(key);
- }
-
- call Leds.led1Toggle();
-
- return rc;
- }
-
- event void Ppp.outputFrameTransmitted (frame_key_t key,
- error_t err) { }
-
- }
阅读代码可以发现PRINTFUART_ENABLED不要开启,不然ppp模块是编译去除的;
源码是pppd的例程部分和发送数据接收数据的处理
RplBorderRouterP.nc文件:
- #include <lib6lowpan/ip.h>
- #include <iprouting.h>
- #include <RPL.h>
-
- module RplBorderRouterP {
- uses {
- interface ForwardingEvents;
- interface IPPacket;
- }
- } implementation {
-
- event bool ForwardingEvents.initiate(struct ip6_packet *pkt,
- struct in6_addr *next_hop) {
- return TRUE;
- }
-
- event bool ForwardingEvents.approve(struct ip6_packet *pkt,
- struct in6_addr *next_hop) {
- int off;
- uint8_t nxt = IPV6_HOP;
- if (pkt->ip6_inputif == ROUTE_IFACE_PPP)
- return FALSE;
-
- /* remove any RPL options in the hop-by-hop header by converting
- them to a PadN option */
- off = call IPPacket.findHeader(pkt->ip6_data, pkt->ip6_hdr.ip6_nxt, &nxt);
- if (off < 0) return TRUE;
- call IPPacket.delTLV(pkt->ip6_data, off, RPL_HBH_RANK_TYPE);
-
- return TRUE;
- }
-
- event void ForwardingEvents.linkResult(struct in6_addr *dest, struct send_info *info) {
-
- }
- }
这个components是缺省写法,大家以后可以学习他的写法来偷懒,没有编写configuration和interface文件;
文件中的事件是网络路由事件;
本例程带有测试视频;截图神马的就忽略了,其中的pppd命令使用自己安装的pppd_hack的原因是因为当主机是XP的时候,虚拟机使用pppd命令,出现假死,当主机是WIN8的时候,虚拟机同样的使用pppd时正常的;于是我干脆自己安装了pppd_hack,这样主机XP或WIN8就都可以了;pppd_hack虚拟机已经安装好,参考的lab11的blip测试网页安装,百度网盘也有安装包;
可以先烧写一个Ppprouter节点连接PC,按照视频启动pppd连接,可以输入路由表查看命令,查看本机路由;
再准备一个UDPECHO节点,编译烧写,再在虚拟机查看Ppprouter节点路由表或者登陆UDPECHO节点,查看一下它的路由表;
当然你也可以先跳过UDPECHO;我自己就基本不测试他,可以pppd连接后,直接跳过测试,进入下一部CoAPServer节点实验实行ping6测试,coap的led控制!