⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 icmpresponderp.nc

📁 tinyos-2.x.rar
💻 NC
字号:
/*
 * "Copyright (c) 2008 The Regents of the University  of California.
 * All rights reserved."
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose, without fee, and without written agreement is
 * hereby granted, provided that the above copyright notice, the following
 * two paragraphs and the author appear in all copies of this software.
 *
 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
 * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
 * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
 *
 */

#include <lib6lowpan.h>
#include <6lowpan.h>
#include <ip_malloc.h>
#include <Statistics.h>
#include "in_cksum.h"
#include "PrintfUART.h"
#include "ICMP.h"

extern uint8_t multicast_prefix[8];

module ICMPResponderP {
  provides interface ICMP;
  provides interface ICMPPing[uint16_t client];
  provides interface Statistics<icmp_statistics_t>;

  uses interface IP;
  uses interface IPAddress;

  uses interface Leds;

  uses interface Timer<TMilli> as Solicitation;
  uses interface Timer<TMilli> as Advertisement;
  uses interface Timer<TMilli> as PingTimer;
  uses interface LocalTime<TMilli>;
  uses interface Random;

  uses interface IPRouting;

} implementation {

  icmp_statistics_t stats;
  uint32_t solicitation_period;
  uint32_t advertisement_period;
  uint16_t nd_seqno = 0;

  uint16_t ping_seq, ping_n, ping_rcv, ping_ident;
  struct in6_addr ping_dest;

#ifdef PRINTFUART_ENABLED
#undef dbg
#define dbg(X, fmt, args ...) printfUART(fmt, ## args)
#endif

  command uint16_t ICMP.cksum(struct split_ip_msg *msg, uint8_t nxt_hdr) {
    return msg_cksum(msg, nxt_hdr);
  }


  command void ICMP.sendSolicitations() {
    uint16_t jitter = (call Random.rand16()) % TRICKLE_JITTER;
    if (call Solicitation.isRunning()) return;
    solicitation_period = TRICKLE_PERIOD;
    call Solicitation.startOneShot(jitter);
  }

  command void ICMP.sendAdvertisements() {


    uint16_t jitter = (call Random.rand16()) % TRICKLE_JITTER;
    if (call Advertisement.isRunning()) return;
    advertisement_period = TRICKLE_PERIOD;
    call Advertisement.startOneShot(jitter);
  }

  command void ICMP.sendTimeExceeded(struct ip6_hdr *hdr, unpack_info_t *u_info, uint16_t amount_here) {
    uint8_t i_hdr_buf[sizeof(struct icmp6_hdr) + 4];
    struct split_ip_msg *msg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg));
    struct generic_header g_hdr[3];
    struct icmp6_hdr *i_hdr = (struct icmp6_hdr *)i_hdr_buf;

    if (msg == NULL) return;

    dbg("ICMPResponder", "send time exceeded\n");

    msg->headers = NULL;
    msg->data = u_info->payload_start;
    msg->data_len = amount_here;

    // make sure to include the udp header if necessary
    if (u_info->nxt_hdr == IANA_UDP) {
      g_hdr[2].hdr.udp = (struct udp_hdr *)u_info->transport_ptr;
      g_hdr[2].len = sizeof(struct udp_hdr);
      g_hdr[2].next = NULL;
      
      // since the udp headers are included in the offset we need to
      // add that length so the payload length in the encapsulated
      // packet will be correct.
      hdr->plen = htons(ntohs(hdr->plen) + sizeof(struct udp_hdr));
      msg->headers = &g_hdr[2];
    }
    // the fields in the packed packet is not necessarily the same as
    // the fields in canonical packet which was packed.  This is due
    // to the insertion of transient routing headers.
    hdr->nxt_hdr = u_info->nxt_hdr;
    hdr->plen = htons(ntohs(hdr->plen) - u_info->payload_offset);

    // the IP header is part of the payload
    g_hdr[1].hdr.data = (void *)hdr;
    g_hdr[1].len = sizeof(struct ip6_hdr);
    g_hdr[1].next = msg->headers;
    msg->headers = &g_hdr[1];

    // and is preceeded by the icmp time exceeded message
    g_hdr[0].hdr.data = (void *)i_hdr;
    g_hdr[0].len = sizeof(struct icmp6_hdr) + 4;
    g_hdr[0].next = msg->headers;
    msg->headers = &g_hdr[0];

    ip_memcpy(&msg->hdr.ip6_dst, &hdr->ip6_src, 16);
    call IPAddress.getIPAddr(&msg->hdr.ip6_src);

    i_hdr->type = ICMP_TYPE_ECHO_TIME_EXCEEDED;
    i_hdr->code = ICMP_CODE_HOPLIMIT_EXCEEDED;
    i_hdr->cksum = 0;
    ip_memclr((void *)(i_hdr + 1), 4);

    msg->hdr.nxt_hdr = IANA_ICMP;

    i_hdr->cksum = htons(call ICMP.cksum(msg, IANA_ICMP));

    call IP.send(msg);

    ip_free(msg);
  }
  /*
   * Solicitations
   */ 
  void sendSolicitation() {
    struct split_ip_msg *ipmsg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg) + sizeof(rsol_t));
    rsol_t *msg = (rsol_t *)(ipmsg + 1);

    if (ipmsg == NULL) return;

    BLIP_STATS_INCR(stats.sol_tx);

    msg->type = ICMP_TYPE_ROUTER_SOL;
    msg->code = 0;
    msg->cksum = 0;
    msg->reserved = 0;

    ipmsg->headers = NULL;
    ipmsg->data = (void *)msg;
    ipmsg->data_len = sizeof(rsol_t);
    
    // this is required for solicitation messages
    ipmsg->hdr.hlim = 0xff;


    call IPAddress.getLLAddr(&ipmsg->hdr.ip6_src);
    ip_memclr((uint8_t *)&ipmsg->hdr.ip6_dst, 16);
    ipmsg->hdr.ip6_dst.s6_addr16[0] = htons(0xff02);
    ipmsg->hdr.ip6_dst.s6_addr16[7] = htons(2);

    msg->cksum = call ICMP.cksum(ipmsg, IANA_ICMP);

    call IP.send(ipmsg);

    ip_free(ipmsg);
  }

  void sendPing(struct in6_addr *dest, uint16_t seqno) {
    struct split_ip_msg *ipmsg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg) + 
                                                                  sizeof(icmp_echo_hdr_t) + 
                                                                  sizeof(nx_uint32_t));
    icmp_echo_hdr_t *e_hdr = (icmp_echo_hdr_t *)ipmsg->next;
    nx_uint32_t *sendTime = (nx_uint32_t *)(e_hdr + 1);

    if (ipmsg == NULL) return;
    ipmsg->headers = NULL;
    ipmsg->data = (void *)e_hdr;
    ipmsg->data_len = sizeof(icmp_echo_hdr_t) + sizeof(nx_uint32_t);

    e_hdr->type = ICMP_TYPE_ECHO_REQUEST;
    e_hdr->code = 0;
    e_hdr->cksum = 0;
    e_hdr->ident = ping_ident;
    e_hdr->seqno = seqno;
    *sendTime = call LocalTime.get();

    memcpy(&ipmsg->hdr.ip6_dst, dest->s6_addr, 16);
    call IPAddress.getIPAddr(&ipmsg->hdr.ip6_src);

    e_hdr->cksum = call ICMP.cksum(ipmsg,IANA_ICMP);

    call IP.send(ipmsg);
    ip_free(ipmsg);
  }

  /*
   * Router advertisements
   */ 
  void handleRouterAdv(void *payload, uint16_t len, struct ip_metadata *meta) {
    
    radv_t *r = (radv_t *)payload;
    pfx_t  *pfx = (pfx_t *)(r->options);
    rqual_t *beacon = (rqual_t *)(pfx + 1);

    if (len > sizeof(radv_t) + sizeof(pfx_t) && 
        beacon->type == ICMP_EXT_TYPE_BEACON) {

      printfUART("beacon seqno: %i my seqno: %i\n", beacon->seqno, nd_seqno);

      if (beacon->seqno > nd_seqno || 
          (nd_seqno > 0 && beacon->seqno == 0) ||
          !call IPRouting.hasRoute()) {
        call IPRouting.reset();
        nd_seqno = beacon->seqno;
      }

      if (beacon->seqno == nd_seqno) {
        call IPRouting.reportAdvertisement(meta->sender, r->hlim,
                                           meta->lqi, beacon->metric);
        // push out the seqno update
        // call Advertisement.stop();
        // call ICMP.sendAdvertisements();

        if (pfx->type != ICMP_EXT_TYPE_PREFIX) return;

        call IPAddress.setPrefix((uint8_t *)pfx->prefix);
      }


      dbg("ICMPResponder", " * beacon cost: 0x%x\n", beacon->metric);
    } else {
        dbg("ICMPResponder", " * no beacon cost\n");
    }


    // TODO : get short address here...
  }

  void sendAdvertisement() {
    struct split_ip_msg *ipmsg = (struct split_ip_msg *)ip_malloc(sizeof(struct split_ip_msg) + 
                                                                  sizeof(radv_t) + 
                                                                  sizeof(pfx_t) +
                                                                  sizeof(rqual_t));
    uint16_t len = sizeof(radv_t);
    radv_t *r = (radv_t *)(ipmsg + 1);
    pfx_t *p = (pfx_t *)r->options;
    rqual_t *q = (rqual_t *)(p + 1);

    if (ipmsg == NULL) return;
    // don't sent the advertisement if we don't have a valid route
    if (!call IPRouting.hasRoute()) {
      ip_free(ipmsg);
      return;
    }
    BLIP_STATS_INCR(stats.adv_tx);

    r->type = ICMP_TYPE_ROUTER_ADV;
    r->code = 0;
    r->hlim = call IPRouting.getHopLimit();
    r->flags = 0;
    r->lifetime = 1;
    r->reachable_time = 0;
    r->retrans_time = 0;

    ipmsg->hdr.hlim = 0xff;
    
    if (globalPrefix) {
      len += sizeof(pfx_t);
      p->type = ICMP_EXT_TYPE_PREFIX;
      p->length = sizeof(pfx_t) >> 3;
      p->pfx_len = 64;
      memcpy(p->prefix, call IPAddress.getPublicAddr(), 8);
    }

    len += sizeof(rqual_t);
    q->type = ICMP_EXT_TYPE_BEACON;
    q->length = sizeof(rqual_t) >> 3;;
    q->metric = call IPRouting.getQuality();
    q->seqno = nd_seqno;

    call IPAddress.getLLAddr(&ipmsg->hdr.ip6_src);
    ip_memclr((uint8_t *)&ipmsg->hdr.ip6_dst, 16);
    ipmsg->hdr.ip6_dst.s6_addr16[0] = htons(0xff02);
    ipmsg->hdr.ip6_dst.s6_addr16[7] = htons(1);

    //dbg("ICMPResponder", "My Address: [0x%x] [0x%x] [0x%x] [0x%x]\n", ipmsg->hdr.src_addr[12], ipmsg->hdr.src_addr[13], ipmsg->hdr.src_addr[14], ipmsg->hdr.src_addr[15]);
    dbg("ICMPResponder", "adv hop limit: 0x%x\n", r->hlim);

    if (r->hlim >= 0xf0) {
      ip_free(ipmsg);
      return;
    }

    ipmsg->data = (void *)r;
    ipmsg->data_len = len;
    ipmsg->headers = NULL;

    r->cksum = 0;
    r->cksum = call ICMP.cksum(ipmsg, IANA_ICMP);

    call IP.send(ipmsg);
    ip_free(ipmsg);
  }


  event void IP.recv(struct ip6_hdr *iph,
                     void *payload, 
                     struct ip_metadata *meta) {
    icmp_echo_hdr_t *req = (icmp_echo_hdr_t *)payload;
    uint16_t len = ntohs(iph->plen);
    BLIP_STATS_INCR(stats.rx);
  
    // for checksum calculation
    printfUART ("icmp type: 0x%x code: 0x%x cksum: 0x%x ident: 0x%x seqno: 0x%x len: 0x%x\n",
                req->type, req->code, req->cksum, req->ident, req->seqno, len);

    switch (req->type) {
    case ICMP_TYPE_ROUTER_ADV:
      handleRouterAdv(payload, len, meta);
      BLIP_STATS_INCR(stats.adv_rx);
      break;
    case ICMP_TYPE_ROUTER_SOL:
      // only reply to solicitations if we have established a default route.
      if (call IPRouting.hasRoute()) {
          call ICMP.sendAdvertisements();
      }
      BLIP_STATS_INCR(stats.sol_rx);
      break;
    case ICMP_TYPE_ECHO_REPLY:
      {
        nx_uint32_t *sendTime = (nx_uint32_t *)(req + 1);
        struct icmp_stats p_stat;
        p_stat.seq = req->seqno;
        p_stat.ttl = iph->hlim;
        p_stat.rtt = (call LocalTime.get()) - (*sendTime);
        signal ICMPPing.pingReply[req->ident](&iph->ip6_src, &p_stat);
        ping_rcv++;
        BLIP_STATS_INCR(stats.echo_rx);
      }
      break;
    case ICMP_TYPE_ECHO_REQUEST:
      {
        // send a ping reply.
        struct split_ip_msg msg;
        msg.headers = NULL;
        msg.data = payload;
        msg.data_len = len;

        memcpy(&msg.hdr.ip6_dst, &iph->ip6_src, 16);      
        call IPAddress.setSource(&msg.hdr);
        
        req->type = ICMP_TYPE_ECHO_REPLY;
        req->code = 0;
        req->cksum = 0;
        req->cksum = call ICMP.cksum(&msg, IANA_ICMP);
        
        // remember, this can't really fail in a way we care about
        call IP.send(&msg);
        BLIP_STATS_INCR(stats.echo_tx);
        break;
      }
    default:
      BLIP_STATS_INCR(stats.unk_rx);
    }
  }


  event void Solicitation.fired() {
    sendSolicitation();
    dbg("ICMPResponder", "solicitation period: 0x%x max: 0x%x seq: %i\n", solicitation_period, TRICKLE_MAX, nd_seqno);
    solicitation_period <<= 1;
    if (solicitation_period < TRICKLE_MAX) {
      call Solicitation.startOneShot(solicitation_period);
    } else {
      signal ICMP.solicitationDone();
    }
  }

  event void Advertisement.fired() {
    dbg("ICMPResponder", "==> Sending router advertisement\n");
    sendAdvertisement();
    advertisement_period <<= 1;
    if (advertisement_period < TRICKLE_MAX) {
      call Advertisement.startOneShot(advertisement_period);
    }
  }


  
  command error_t ICMPPing.ping[uint16_t client](struct in6_addr *target, uint16_t period, uint16_t n) {
    if (call PingTimer.isRunning()) return ERETRY;
    call PingTimer.startPeriodic(period);

    memcpy(&ping_dest, target, 16);
    ping_n = n;
    ping_seq = 0;
    ping_rcv = 0;
    ping_ident = client;
    return SUCCESS;
  }

  event void PingTimer.fired() {
    // send a ping request
    if (ping_seq == ping_n) {
      signal ICMPPing.pingDone[ping_ident](ping_rcv, ping_n);
      call PingTimer.stop();
      return;
    }
    sendPing(&ping_dest, ping_seq);
    ping_seq++;
  }



  command void Statistics.get(icmp_statistics_t *statistics) {
    memcpy(statistics, &stats, sizeof(icmp_statistics_t));
  }
  
  command void Statistics.clear() {
    ip_memclr((uint8_t *)&stats, sizeof(icmp_statistics_t));
  }

  default event void ICMPPing.pingReply[uint16_t client](struct in6_addr *source, 
                                                         struct icmp_stats *ping_stats) {
  }

  default event void ICMPPing.pingDone[uint16_t client](uint16_t n, uint16_t m) {

  }

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -