Пример #1
0
/**
 * Send a MLD message (report or done).
 *
 * An IPv6 hop-by-hop options header with a router alert option
 * is prepended.
 *
 * @param group the group to report or quit
 * @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done)
 */
static void
mld6_send(struct mld_group *group, u8_t type)
{
  struct mld_header * mld_hdr;
  struct pbuf * p;
  ip6_addr_t * src_addr;

  /* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */
  p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM);
  if ((p == NULL) || (p->len < (sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr)))) {
    /* We couldn't allocate a suitable pbuf. drop it. */
    if (p != NULL) {
      pbuf_free(p);
    }
    MLD6_STATS_INC(mld6.memerr);
    return;
  }

  /* Move to make room for Hop-by-hop options header. */
  if (pbuf_header(p, -IP6_HBH_HLEN)) {
    pbuf_free(p);
    MLD6_STATS_INC(mld6.lenerr);
    return;
  }

  /* Select our source address. */
  if (!ip6_addr_isvalid(netif_ip6_addr_state(group->netif, 0))) {
    /* This is a special case, when we are performing duplicate address detection.
     * We must join the multicast group, but we don't have a valid address yet. */
    src_addr = IP6_ADDR_ANY;
  } else {
    /* Use link-local address as source address. */
    src_addr = netif_ip6_addr(group->netif, 0);
  }

  /* MLD message header pointer. */
  mld_hdr = (struct mld_header *)p->payload;

  /* Set fields. */
  mld_hdr->type = type;
  mld_hdr->code = 0;
  mld_hdr->chksum = 0;
  mld_hdr->max_resp_delay = 0;
  mld_hdr->reserved = 0;
  ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address));

#if CHECKSUM_GEN_ICMP6
  mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
    src_addr, &(group->group_address));
#endif /* CHECKSUM_GEN_ICMP6 */

  /* Add hop-by-hop headers options: router alert with MLD value. */
  ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD);

  /* Send the packet out. */
  MLD6_STATS_INC(mld6.xmit);
  ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address),
      MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, group->netif);
  pbuf_free(p);
}
Пример #2
0
static void
pxping_icmp6_callback(struct pong6 *pong)
{
    DWORD nreplies;
    ICMPV6_ECHO_REPLY *reply;
    struct pbuf *p;
    struct icmp6_echo_hdr *icmph;
    size_t icmplen;
    ip6_addr_t src;
    int mapped;

    nreplies = Icmp6ParseReplies(pong->buf, (DWORD)pong->bufsize);
    if (nreplies == 0) {
        DWORD error = GetLastError();
        if (error == IP_REQ_TIMED_OUT) {
            DPRINTF2(("pong6: %p timed out\n", (void *)pong));
        }
        else {
            DPRINTF(("pong6: %p: Icmp6ParseReplies: error %d\n",
                     (void *)pong, error));
        }
        return;
    }

    reply = (ICMPV6_ECHO_REPLY *)pong->buf;

    mapped = pxremap_inbound_ip6(&src, (ip6_addr_t *)reply->Address.sin6_addr);
    if (mapped == PXREMAP_FAILED) {
        return;
    }

    /*
     * Reply data follows ICMPV6_ECHO_REPLY structure in memory, but
     * it doesn't tell us its size.  Assume it's equal the size of the
     * request.
     */
    icmplen = sizeof(*icmph) + pong->reqsize;
    p = pbuf_alloc(PBUF_IP, (u16_t)icmplen, PBUF_RAM);
    if (RT_UNLIKELY(p == NULL)) {
        return;
    }

    icmph = (struct icmp6_echo_hdr *)p->payload;
    icmph->type = ICMP6_TYPE_EREP;
    icmph->code = 0;
    icmph->chksum = 0;
    icmph->id = pong->reqicmph.id;
    icmph->seqno = pong->reqicmph.seqno;

    memcpy((u8_t *)p->payload + sizeof(*icmph),
           pong->buf + sizeof(*reply), pong->reqsize);

    icmph->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len,
                                      &src, &pong->reqsrc);
    ip6_output_if(p, /* :src */ &src, /* :dst */ &pong->reqsrc,
                  LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6,
                  pong->netif);
    pbuf_free(p);
}
Пример #3
0
void
icmp6_proxy_input(struct pbuf *p, struct netif *inp)
{
  struct icmp6_hdr *icmp6hdr;

  ICMP6_STATS_INC(icmp6.recv);

  /* Check that ICMPv6 header fits in payload */
  if (p->len < sizeof(struct icmp6_hdr)) {
    /* drop short packets */
    pbuf_free(p);
    ICMP6_STATS_INC(icmp6.lenerr);
    ICMP6_STATS_INC(icmp6.drop);
    return;
  }

  icmp6hdr = (struct icmp6_hdr *)p->payload;
  if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(),
                        ip6_current_dest_addr()) != 0) {
    /* Checksum failed */
    pbuf_free(p);
    ICMP6_STATS_INC(icmp6.chkerr);
    ICMP6_STATS_INC(icmp6.drop);
    return;
  }

  switch (icmp6hdr->type) {

  case ICMP6_TYPE_EREQ:
    if (ping6_proxy_accept_callback != NULL) {
      (*ping6_proxy_accept_callback)(ping6_proxy_accept_arg, p);
      return;
    }
    ICMP6_STATS_INC(icmp6.drop);
    break;

  case ICMP6_TYPE_EREP:
    /* ignore silently */
    ICMP6_STATS_INC(icmp6.drop);
    break;

  default:
    ICMP6_STATS_INC(icmp6.drop);
    break;
  }

  pbuf_free(p);
}
Пример #4
0
/**
 * Send the raw IP packet to the given address. Note that actually you cannot
 * modify the IP headers (this is inconsistent with the receive callback where
 * you actually get the IP headers), you can only specify the IP payload here.
 * It requires some more changes in lwIP. (there will be a raw_send() function
 * then.)
 *
 * @param pcb the raw pcb which to send
 * @param p the IP payload to send
 * @param ipaddr the destination address of the IP packet
 *
 */
err_t
raw_sendto(struct raw_pcb *pcb, struct pbuf *p, const ip_addr_t *ipaddr)
{
  err_t err;
  struct netif *netif;
  ipX_addr_t *src_ip;
  struct pbuf *q; /* q will be sent down the stack */
  s16_t header_size;
  const ipX_addr_t *dst_ip = ip_2_ipX(ipaddr);

  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));

  header_size = (
#if LWIP_IPV6
    PCB_ISIPV6(pcb) ? IP6_HLEN :
#endif /* LWIP_IPV6 */
    IP_HLEN);

  /* not enough space to add an IP header to first pbuf in given p chain? */
  if (pbuf_header(p, header_size)) {
    /* allocate header in new pbuf */
    q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
    /* new header pbuf could not be allocated? */
    if (q == NULL) {
      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n"));
      return ERR_MEM;
    }
    if (p->tot_len != 0) {
      /* chain header q in front of given pbuf p */
      pbuf_chain(q, p);
    }
    /* { first pbuf q points to header pbuf } */
    LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
  }  else {
    /* first pbuf q equals given pbuf */
    q = p;
    if(pbuf_header(q, -header_size)) {
      LWIP_ASSERT("Can't restore header we just removed!", 0);
      return ERR_MEM;
    }
  }

  netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip);
  if (netif == NULL) {
    LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
    ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip);
    /* free any temporary header pbuf allocated by pbuf_header() */
    if (q != p) {
      pbuf_free(q);
    }
    return ERR_RTE;
  }

#if IP_SOF_BROADCAST
#if LWIP_IPV6
  if (!PCB_ISIPV6(pcb))
#endif /* LWIP_IPV6 */
  {
    /* broadcast filter? */
    if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) {
      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
      /* free any temporary header pbuf allocated by pbuf_header() */
      if (q != p) {
        pbuf_free(q);
      }
      return ERR_VAL;
    }
  }
#endif /* IP_SOF_BROADCAST */

  if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
    /* use outgoing network interface IP address as source address */
    src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip);
#if LWIP_IPV6
    if (src_ip == NULL) {
      if (q != p) {
        pbuf_free(q);
      }
      return ERR_RTE;
    }
#endif /* LWIP_IPV6 */
  } else {
    /* use RAW PCB local IP address as source address */
    src_ip = &pcb->local_ip;
  }

#if LWIP_IPV6
  /* If requested, based on the IPV6_CHECKSUM socket option per RFC3542,
     compute the checksum and update the checksum in the payload. */
  if (PCB_ISIPV6(pcb) && pcb->chksum_reqd) {
    u16_t chksum = ip6_chksum_pseudo(p, pcb->protocol, p->tot_len, ipX_2_ip6(src_ip), ipX_2_ip6(dst_ip));
    LWIP_ASSERT("Checksum must fit into first pbuf", p->len >= (pcb->chksum_offset + 2));
    SMEMCPY(((u8_t *)p->payload) + pcb->chksum_offset, &chksum, sizeof(u16_t));
  }
#endif

  NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
  err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif);
  NETIF_SET_HWADDRHINT(netif, NULL);

  /* did we chain a header earlier? */
  if (q != p) {
    /* free the header */
    pbuf_free(q);
  }
  return err;
}
Пример #5
0
/**
 * Process an input ICMPv6 message. Called by ip6_input.
 *
 * Will generate a reply for echo requests. Other messages are forwarded
 * to nd6_input, or mld6_input.
 *
 * @param p the mld packet, p->payload pointing to the icmpv6 header
 * @param inp the netif on which this packet was received
 */
void
icmp6_input(struct pbuf *p, struct interface *inp)
{
  struct icmp6_hdr *icmp6hdr;
  struct pbuf * r;
  ip6_addr_t * reply_src;

  ICMP6_STATS_INC(icmp6.recv);

  /* Check that ICMPv6 header fits in payload */
  if (p->len < sizeof(struct icmp6_hdr)) {
    /* drop short packets */
    pbuf_free(p);
    ICMP6_STATS_INC(icmp6.lenerr);
    ICMP6_STATS_INC(icmp6.drop);
    return;
  }

  icmp6hdr = (struct icmp6_hdr *)p->payload;

#if LWIP_ICMP6_CHECKSUM_CHECK
  if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(),
                        ip6_current_dest_addr()) != 0) {
    /* Checksum failed */
    pbuf_free(p);
    ICMP6_STATS_INC(icmp6.chkerr);
    ICMP6_STATS_INC(icmp6.drop);
    return;
  }
#endif /* LWIP_ICMP6_CHECKSUM_CHECK */

  switch (icmp6hdr->type) {
  case ICMP6_TYPE_NA: /* Neighbor advertisement */
  case ICMP6_TYPE_NS: /* Neighbor solicitation */
  case ICMP6_TYPE_RA: /* Router advertisement */
  case ICMP6_TYPE_RD: /* Redirect */
  case ICMP6_TYPE_PTB: /* Packet too big */
    nd6_input(p, inp);
    return;
    break;
  case ICMP6_TYPE_RS:
#if LWIP_IPV6_FORWARD
    /* TODO implement router functionality */
#endif
    break;
#if LWIP_IPV6_MLD
  case ICMP6_TYPE_MLQ:
  case ICMP6_TYPE_MLR:
  case ICMP6_TYPE_MLD:
    mld6_input(p, inp);
    return;
    break;
#endif
  case ICMP6_TYPE_EREQ:
#if !LWIP_MULTICAST_PING
    /* multicast destination address? */
    if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
      /* drop */
      pbuf_free(p);
      ICMP6_STATS_INC(icmp6.drop);
      return;
    }
#endif /* LWIP_MULTICAST_PING */

    /* Allocate reply. */
    r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM);
    if (r == NULL) {
      /* drop */
      pbuf_free(p);
      ICMP6_STATS_INC(icmp6.memerr);
      return;
    }

    /* Copy echo request. */
    if (pbuf_copy(r, p) != ERR_OK) {
      /* drop */
      pbuf_free(p);
      pbuf_free(r);
      ICMP6_STATS_INC(icmp6.err);
      return;
    }

    /* Determine reply source IPv6 address. */
#if LWIP_MULTICAST_PING
    if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
      reply_src = ip6_select_source_address(inp, ip6_current_src_addr());
      if (reply_src == NULL) {
        /* drop */
        pbuf_free(p);
        pbuf_free(r);
        ICMP6_STATS_INC(icmp6.rterr);
        return;
      }
    }
    else
#endif /* LWIP_MULTICAST_PING */
    {
      reply_src = ip6_current_dest_addr();
    }

    /* Set fields in reply. */
    ((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
    ((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
    ((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
        IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());

    /* Send reply. */
    ICMP6_STATS_INC(icmp6.xmit);
    ip6_output_if(r, reply_src, ip6_current_src_addr(),
        LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp);
    pbuf_free(r);

    break;
  default:
    ICMP6_STATS_INC(icmp6.proterr);
    ICMP6_STATS_INC(icmp6.drop);
    break;
  }

  pbuf_free(p);
}
Пример #6
0
/**
 * Send an ICMPv6 packet in response to an incoming packet.
 *
 * @param p the input packet for which the response should be sent,
 *          p->payload pointing to the IPv6 header
 * @param code Code of the ICMPv6 header
 * @param data Additional 32-bit parameter in the ICMPv6 header
 * @param type Type of the ICMPv6 header
 */
static void
icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
{
  struct pbuf *q;
  struct icmp6_hdr *icmp6hdr;
  ip6_addr_t *reply_src, *reply_dest;
  ip6_addr_t reply_src_local, reply_dest_local;
  struct ip6_hdr *ip6hdr;
  struct interface *netif;

  /* ICMPv6 header + IPv6 header + data */
  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
                 PBUF_RAM);
  if (q == NULL) {
    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
    ICMP6_STATS_INC(icmp6.memerr);
    return;
  }
  LWIP_ASSERT("check that first pbuf can hold icmp 6message",
             (q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));

  icmp6hdr = (struct icmp6_hdr *)q->payload;
  icmp6hdr->type = type;
  icmp6hdr->code = code;
  icmp6hdr->data = data;

  /* copy fields from original packet */
  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
          IP6_HLEN + LWIP_ICMP6_DATASIZE);

  /* Get the destination address and netif for this ICMP message. */
  if ((ip_current_netif() == NULL) ||
      ((code == ICMP6_TE_FRAG) && (type == ICMP6_TYPE_TE))) {
    /* Special case, as ip6_current_xxx is either NULL, or points
     * to a different packet than the one that expired.
     * We must use the addresses that are stored in the expired packet. */
    ip6hdr = (struct ip6_hdr *)p->payload;
    /* copy from packed address to aligned address */
    ip6_addr_copy(reply_dest_local, ip6hdr->src);
    ip6_addr_copy(reply_src_local, ip6hdr->dest);
    reply_dest = &reply_dest_local;
    reply_src = &reply_src_local;
    netif = ip6_route(reply_src, reply_dest);
    if (netif == NULL) {
      /* drop */
      pbuf_free(q);
      ICMP6_STATS_INC(icmp6.rterr);
      return;
    }
  }
  else {
    netif = ip_current_netif();
    reply_dest = ip6_current_src_addr();

    /* Select an address to use as source. */
    reply_src = ip6_select_source_address(netif, reply_dest);
    if (reply_src == NULL) {
      /* drop */
      pbuf_free(q);
      ICMP6_STATS_INC(icmp6.rterr);
      return;
    }
  }

  /* calculate checksum */
  icmp6hdr->chksum = 0;
  icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
    reply_src, reply_dest);

  ICMP6_STATS_INC(icmp6.xmit);
  ip6_output_if(q, reply_src, reply_dest, LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, netif);
  pbuf_free(q);
}
Пример #7
0
/*********************************************************************************************************
** 函数名称: __inetPing6Prepare
** 功能描述: 构造 ping 包
** 输 入  : icmp6hdrEcho  数据
**           pip6addrDest  目标 IP
**           iDataSize     数据大小
**           pcNetif       网络接口名 (NULL 表示自动确定接口)
**           pusSeqRecv    需要判断的 seq
** 输 出  : ERROR
** 全局变量: 
** 调用模块: 
*********************************************************************************************************/
static INT  __inetPing6Prepare (struct icmp6_echo_hdr   *icmp6hdrEcho, 
                                struct ip6_addr         *pip6addrDest,
                                INT                      iDataSize, 
                                CPCHAR                   pcNetif,
                                UINT16                  *pusSeqRecv)
{
    static u16_t    usSeqNum = 1;
    REGISTER INT    i;
    
#if CHECKSUM_GEN_ICMP6
           INT      iError;
    struct ip6_addr ip6addrSrc;
    struct pbuf     pbuf;
    struct netif   *netif;
#endif                                                                  /*  CHECKSUM_GEN_ICMP6          */
    
    SYS_ARCH_DECL_PROTECT(x);

    icmp6hdrEcho->type = ICMP6_TYPE_EREQ;
    icmp6hdrEcho->code = 0;
    
    *pusSeqRecv = usSeqNum;
    
    icmp6hdrEcho->chksum = 0;
    icmp6hdrEcho->id     = 0xAFAF;                                      /*  ID                          */
    icmp6hdrEcho->seqno  = htons(usSeqNum);
    
    /*
     *  填充数据
     */
    for(i = 0; i < iDataSize; i++) {
        ((PCHAR)icmp6hdrEcho)[sizeof(struct icmp6_echo_hdr) + i] = (CHAR)(i % 256);
    }
    
#if CHECKSUM_GEN_ICMP6
    LOCK_TCPIP_CORE();
    if (pcNetif) {
        netif = netif_find((PCHAR)pcNetif);
        if (netif == LW_NULL) {
            UNLOCK_TCPIP_CORE();
            fprintf(stderr, "Invalid interface.\n");
            return  (PX_ERROR);
        }
    } else {
        netif = LW_NULL;
    }
    iError = __inetPing6FindSrc(netif, pip6addrDest, &ip6addrSrc);
    UNLOCK_TCPIP_CORE();
    
    if (iError == -1) {
        fprintf(stderr, "You must determine net interface.\n");
        return  (PX_ERROR);
    
    } else if (iError == -2) {
        fprintf(stderr, "Unreachable destination.\n");
        return  (PX_ERROR);
    }
    
    pbuf.next    = LW_NULL;
    pbuf.payload = (void *)icmp6hdrEcho;
    pbuf.tot_len = (u16_t)(iDataSize + sizeof(struct icmp6_echo_hdr));
    pbuf.len     = pbuf.tot_len;
    pbuf.type    = PBUF_ROM;
    pbuf.flags   = 0;
    pbuf.ref     = 1;
    
    icmp6hdrEcho->chksum = ip6_chksum_pseudo(&pbuf, IP6_NEXTH_ICMP6, pbuf.tot_len,
                                             &ip6addrSrc, pip6addrDest);
#endif                                                                  /*  CHECKSUM_GEN_ICMP6          */
    
    SYS_ARCH_PROTECT(x);
    usSeqNum++;
    SYS_ARCH_UNPROTECT(x);
    
    return  (ERROR_NONE);
}