/**
 * Forwards an IPv6 packet. It finds an appropriate route for the
 * packet, decrements the HL value of the packet, and outputs
 * the packet on the appropriate interface.
 *
 * @param p the packet to forward (p->payload points to IP header)
 * @param iphdr the IPv6 header of the input packet
 * @param inp the netif on which this packet was received
 */
static void
ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp)
{
  struct netif *netif;

  /* do not forward link-local addresses */
  if (ip6_addr_islinklocal(ip6_current_dest_addr())) {
    LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n"));
    IP6_STATS_INC(ip6.rterr);
    IP6_STATS_INC(ip6.drop);
    return;
  }

  /* Find network interface where to forward this IP packet to. */
  netif = ip6_route(IP6_ADDR_ANY6, ip6_current_dest_addr());
  if (netif == NULL) {
    LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
        IP6_ADDR_BLOCK1(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK2(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK3(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK4(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK5(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK6(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK7(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK8(ip6_current_dest_addr())));
#if LWIP_ICMP6
    /* Don't send ICMP messages in response to ICMP messages */
    if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
      icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE);
    }
#endif /* LWIP_ICMP6 */
    IP6_STATS_INC(ip6.rterr);
    IP6_STATS_INC(ip6.drop);
    return;
  }
  /* Do not forward packets onto the same network interface on which
   * they arrived. */
  if (netif == inp) {
    LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n"));
    IP6_STATS_INC(ip6.rterr);
    IP6_STATS_INC(ip6.drop);
    return;
  }

  /* decrement HL */
  IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1);
  /* send ICMP6 if HL == 0 */
  if (IP6H_HOPLIM(iphdr) == 0) {
#if LWIP_ICMP6
    /* Don't send ICMP messages in response to ICMP messages */
    if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
      icmp6_time_exceeded(p, ICMP6_TE_HL);
    }
#endif /* LWIP_ICMP6 */
    IP6_STATS_INC(ip6.drop);
    return;
  }

  if (netif->mtu && (p->tot_len > netif->mtu)) {
#if LWIP_ICMP6
    /* Don't send ICMP messages in response to ICMP messages */
    if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
      icmp6_packet_too_big(p, netif->mtu);
    }
#endif /* LWIP_ICMP6 */
    IP6_STATS_INC(ip6.drop);
    return;
  }

  LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
      IP6_ADDR_BLOCK1(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK2(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK3(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK4(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK5(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK6(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK7(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK8(ip6_current_dest_addr())));

  /* transmit pbuf on chosen interface */
  netif->output_ip6(netif, p, ip6_current_dest_addr());
  IP6_STATS_INC(ip6.fw);
  IP6_STATS_INC(ip6.xmit);
  return;
}
Exemplo n.º 2
0
/**
 * Forwards an IPv6 packet. It finds an appropriate route for the
 * packet, decrements the HL value of the packet, and outputs
 * the packet on the appropriate interface.
 *
 * @param p the packet to forward (p->payload points to IP header)
 * @param iphdr the IPv6 header of the input packet
 * @param inp the netif on which this packet was received
 * @return -1 if packet is to be dropped, 0 if there's no route, 1 if forwarded
 */
static int
ip6_forward(struct pbuf *p, struct ip6_hdr *iphdr, struct netif *inp)
{
  enum { FWD_DROP = -1, FWD_PROXY = 0, FWD_FORWARDED = 1 };
  struct netif *netif;

  /* do not forward link-local addresses */
  if (ip6_addr_islinklocal(ip6_current_dest_addr())) {
    LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not forwarding link-local address.\n"));
    IP6_STATS_INC(ip6.rterr);
    IP6_STATS_INC(ip6.drop);
    return FWD_DROP;
  }

  /* Find network interface where to forward this IP packet to. */
  netif = ip6_route_fwd(ip6_current_dest_addr());
  if (netif == NULL) {
    LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: no route for %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
        IP6_ADDR_BLOCK1(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK2(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK3(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK4(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK5(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK6(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK7(ip6_current_dest_addr()),
        IP6_ADDR_BLOCK8(ip6_current_dest_addr())));
#if LWIP_CONNECTION_PROXY
    return FWD_PROXY;
#else /* !LWIP_CONNECTION_PROXY */
#if LWIP_ICMP6
    /* Don't send ICMP messages in response to ICMP messages */
    if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
      icmp6_dest_unreach(p, ICMP6_DUR_NO_ROUTE);
    }
#endif /* LWIP_ICMP6 */
    IP6_STATS_INC(ip6.rterr);
    IP6_STATS_INC(ip6.drop);
    return FWD_DROP;
#endif /* !LWIP_CONNECTION_PROXY */
  }

#if LWIP_CONNECTION_PROXY
  /* The packet is for a destination on a directly connected network.
   * Check for addresses in that address space that proxy wants to
   * remap (e.g. to host loopback address/es) and hand it off to
   * proxy */
  if (netif != netif_default
      && proxy_ip6_divert_hook != NULL
      && (*proxy_ip6_divert_hook)(netif, ip6_current_dest_addr()))
  {
    return FWD_PROXY;
  }
#endif /* LWIP_CONNECTION_PROXY */

  /* Do not forward packets onto the same network interface on which
   * they arrived. */
  if (netif == inp) {
    LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: not bouncing packets back on incoming interface.\n"));
    IP6_STATS_INC(ip6.rterr);
    IP6_STATS_INC(ip6.drop);
    return FWD_DROP;
  }

  /* decrement HL */
  IP6H_HOPLIM_SET(iphdr, IP6H_HOPLIM(iphdr) - 1);
  /* send ICMP6 if HL == 0 */
  if (IP6H_HOPLIM(iphdr) == 0) {
#if LWIP_ICMP6
    /* Don't send ICMP messages in response to ICMP messages */
    if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
      icmp6_time_exceeded(p, ICMP6_TE_HL);
    }
#endif /* LWIP_ICMP6 */
    IP6_STATS_INC(ip6.drop);
    return FWD_DROP;
  }

  if (netif->mtu && (p->tot_len > netif->mtu)) {
#if LWIP_ICMP6
    /* Don't send ICMP messages in response to ICMP messages */
    if (IP6H_NEXTH(iphdr) != IP6_NEXTH_ICMP6) {
      icmp6_packet_too_big(p, netif->mtu);
    }
#endif /* LWIP_ICMP6 */
    IP6_STATS_INC(ip6.drop);
    return FWD_DROP;
  }

  LWIP_DEBUGF(IP6_DEBUG, ("ip6_forward: forwarding packet to %"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F"\n",
      IP6_ADDR_BLOCK1(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK2(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK3(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK4(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK5(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK6(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK7(ip6_current_dest_addr()),
      IP6_ADDR_BLOCK8(ip6_current_dest_addr())));

  /* transmit pbuf on chosen interface */
  netif->output_ip6(netif, p, ip6_current_dest_addr());
  IP6_STATS_INC(ip6.fw);
  IP6_STATS_INC(ip6.xmit);
  return FWD_FORWARDED;
}
Exemplo n.º 3
0
static void
pxping_recv6(void *arg, struct pbuf *p)
{
    struct pxping *pxping = (struct pxping *)arg;
    struct icmp6_echo_hdr *icmph;
    size_t bufsize;
    struct pong6 *pong;
    int mapped;
    void *reqdata;
    size_t reqsize;
    struct sockaddr_in6 src, dst;
    int hopl;
    IP_OPTION_INFORMATION opts;
    int status;

    pong = NULL;

    icmph = (struct icmp6_echo_hdr *)p->payload;

    memset(&dst, 0, sizeof(dst));
    dst.sin6_family = AF_INET6;
    mapped = pxremap_outbound_ip6((ip6_addr_t *)&dst.sin6_addr,
                                  ip6_current_dest_addr());
    if (RT_UNLIKELY(mapped == PXREMAP_FAILED)) {
        goto out;
    }

    hopl = IP6H_HOPLIM(ip6_current_header());
    if (mapped == PXREMAP_ASIS) {
        if (RT_UNLIKELY(hopl == 1)) {
            status = pbuf_header(p, ip_current_header_tot_len());
            if (RT_LIKELY(status == 0)) {
                icmp6_time_exceeded(p, ICMP6_TE_HL);
            }
            goto out;
        }
        --hopl;
    }

    status = pbuf_header(p, -(u16_t)sizeof(*icmph)); /* to ping payload */
    if (RT_UNLIKELY(status != 0)) {
        goto out;
    }

    bufsize = sizeof(ICMPV6_ECHO_REPLY) + p->tot_len;
    pong = (struct pong6 *)malloc(sizeof(*pong) - sizeof(pong->buf) + bufsize);
    if (RT_UNLIKELY(pong == NULL)) {
        goto out;
    }
    pong->bufsize = bufsize;
    pong->netif = pxping->netif;

    ip6_addr_copy(pong->reqsrc, *ip6_current_src_addr());
    memcpy(&pong->reqicmph, icmph, sizeof(*icmph));

    memset(pong->buf, 0xa5, pong->bufsize);

    pong->reqsize = reqsize = p->tot_len;
    if (p->next == NULL) {
        /* single pbuf can be directly used as request data source */
        reqdata = p->payload;
    }
    else {
        /* data from pbuf chain must be concatenated */
        pbuf_copy_partial(p, pong->buf, p->tot_len, 0);
        reqdata = pong->buf;
    }

    memset(&src, 0, sizeof(src));
    src.sin6_family = AF_INET6;
    src.sin6_addr = in6addr_any; /* let the OS select host source address */

    memset(&opts, 0, sizeof(opts));
    opts.Ttl = hopl;

    status = Icmp6SendEcho2(pxping->hdl6, NULL,
                            pxping->callback6, pong,
                            &src, &dst, reqdata, (WORD)reqsize, &opts,
                            pong->buf, (DWORD)pong->bufsize,
                            5 * 1000 /* ms */);

    if (RT_UNLIKELY(status != 0)) {
        DPRINTF(("Icmp6SendEcho2: unexpected status %d\n", status));
        goto out;
    }
    else if ((status = GetLastError()) != ERROR_IO_PENDING) {
        int code;

        DPRINTF(("Icmp6SendEcho2: error %d\n", status));
        switch (status) {
        case ERROR_NETWORK_UNREACHABLE:
        case ERROR_HOST_UNREACHABLE:
            code = ICMP6_DUR_NO_ROUTE;
            break;
        default:
            code = -1;
            break;
        }

        if (code != -1) {
            /* move payload back to IP header */
            status = pbuf_header(p, (u16_t)(sizeof(*icmph)
                                            + ip_current_header_tot_len()));
            if (RT_LIKELY(status == 0)) {
                icmp6_dest_unreach(p, code);
            }
        }
        goto out;
    }
    
    pong = NULL;                /* callback owns it now */
  out:
    if (pong != NULL) {
        free(pong);
    }
    pbuf_free(p);
}
Exemplo n.º 4
0
Arquivo: ip6.c Projeto: ORCOS/ORCOS
void ip6_input(struct pbuf *p, struct netif *inp) {
    struct ip6_hdr *iphdr;
    struct netif *netif;

    PERF_START;

#if IP_DEBUG
    ip6_debug_print(p);
#endif /* IP_DEBUG */

    IP_STATS_INC(ip.recv);

    /* identify the IP header */
    iphdr = p->payload;

    if (iphdr->v != 6) {
        LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n"));
#if IP_DEBUG
        ip6_debug_print(p);
#endif /* IP_DEBUG */
        pbuf_free(p);
        IP_STATS_INC(ip.err);IP_STATS_INC(ip.drop);
        return;
    }

    char forus = 0;

    /* is this packet for us? */
    for (netif = netif_list; netif != NULL; netif = netif->next) {
#if IP_DEBUG
        LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest "));
        ip6_addr_debug_print(IP_DEBUG, ((struct ip6_addr *)&(iphdr->dest)));
        LWIP_DEBUGF(IP_DEBUG, ("netif->ip6_addr "));
        ip6_addr_debug_print(IP_DEBUG, ((struct ip6_addr *)&(netif->ip6_addr)));
        LWIP_DEBUGF(IP_DEBUG, ("\n\r"));
#endif /* IP_DEBUG */
        if (ip6_addr_cmp(&(iphdr->dest), &(netif->ip6_addr))) {
            forus = 1;
            LWIP_DEBUGF(IP_DEBUG, ("ip6_input: packet for us: perfect match"));
            break;
        }
        if (ip6_addr_issolicitedmulticast(&(iphdr->dest), &(netif->ip6_addr))) {
            forus = 1;
            LWIP_DEBUGF(IP_DEBUG, ("ip6_input: packet for us on solicited multicast address\n"));
            break;
        }

    }

    // check if it is a multicast address and we are listening on that address
    if (ip6_addr_isallnodes(&(iphdr->dest)))
        forus = 1;

    if (forus == 0) {
        /* packet not for us, route or discard */
        LWIP_DEBUGF(IP_DEBUG, ("ip6_input: packet not for us.\n"));
#if IP_FORWARD
        ip6_forward(p, iphdr);
#endif
        pbuf_free(p);
        return;
    }

    pbuf_realloc(p, IP6_HLEN + ntohs(iphdr->len));

    /* send to upper layers */
#if IP_DEBUG
    /*  LWIP_DEBUGF("ip_input: \n");
     ip_debug_print(p);
     LWIP_DEBUGF("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
#endif /* IP_DEBUG */

    /*if(pbuf_header(p, -IP6_HLEN)) {
     LWIP_ASSERT("Can't move over header in packet", 0);
     return;
     }*/

    switch (iphdr->nexthdr) {
#if LWIP_UDP
    case IP6_PROTO_UDP:
        udp_input(p, inp);
        break;
#endif
#if LWIP_TCP
    case IP6_PROTO_TCP:
        tcp_input(p, inp);
        break;
#endif
#if LWIP_ICMP
    case IP6_PROTO_ICMP:
        icmp6_input(p, inp);
        break;
#endif /* LWIP_ICMP */
    default:
#if LWIP_ICMP
        /* send ICMP destination protocol unreachable */
        icmp6_dest_unreach(p, ICMP_DUR_PROTO);
#endif /* LWIP_ICMP */
        pbuf_free(p);
        LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %"U16_F"\n", iphdr->nexthdr));

        IP_STATS_INC(ip.proterr);
        IP_STATS_INC(ip.drop);
    }PERF_STOP("ip_input");
}