VirtualBox

Changeset 49593 in vbox for trunk/src/VBox/NetworkServices


Ignore:
Timestamp:
Nov 21, 2013 1:56:20 AM (11 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
90798
Message:

Snapshot work in progress on IPv6 ping now that it seems to work for
the basic case. Raw sockets API for IPv6 is somewhat unwieldy, so
I'll do more refactoring when dust settles a bit.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/NetworkServices/NAT/pxping.c

    r49555 r49593  
    6262
    6363    SOCKET sock6;
     64    int hopl;
    6465
    6566    struct pollmgr_handler pmhdl4;
     
    128129
    129130/**
    130  * lwIP thread callback message.
     131 * lwIP thread callback message for IPv4 ping.
     132 *
     133 * We pass raw IP datagram for ip_output_if() so we only need pbuf and
     134 * netif (from pxping).
    131135 */
    132136struct ping_msg {
     
    137141
    138142
     143/**
     144 * lwIP thread callback message for IPv6 ping.
     145 *
     146 * We cannot obtain raw IPv6 datagram from host without extra trouble,
     147 * so we pass ICMPv6 payload in pbuf and also other parameters to
     148 * ip6_output_if().
     149 */
     150struct ping6_msg {
     151    struct tcpip_msg msg;
     152    struct pxping *pxping;
     153    struct pbuf *p;
     154    ip6_addr_t src, dst;
     155    int hopl, tclass;
     156};
     157
     158
    139159static void pxping_recv4(void *arg, struct pbuf *p);
     160static void pxping_recv6(void *arg, struct pbuf *p);
    140161
    141162static void pxping_timer(void *arg);
     
    157178static void pxping_pcb_debug_print(struct ping_pcb *pcb);
    158179
    159 static struct ping_msg *pxping_msg_allocate(struct pxping *pxping, struct pbuf *p);
    160 
    161180static int pxping_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents);
    162 static void pxping_pmgr_icmp4(struct pxping *pxping,
    163                               size_t nread, struct sockaddr_in *peer);
     181
     182static void pxping_pmgr_icmp4(struct pxping *pxping);
    164183static void pxping_pmgr_icmp4_echo(struct pxping *pxping,
    165184                                   u16_t iplen, struct sockaddr_in *peer);
    166185static void pxping_pmgr_icmp4_error(struct pxping *pxping,
    167186                                    u16_t iplen, struct sockaddr_in *peer);
     187static void pxping_pmgr_icmp6(struct pxping *pxping);
     188static void pxping_pmgr_icmp6_echo(struct pxping *pxping,
     189                                   u16_t iplen, struct sockaddr_in6 *peer);
     190static void pxping_pmgr_icmp6_error(struct pxping *pxping,
     191                                    u16_t iplen, struct sockaddr_in6 *peer);
     192
    168193static void pxping_pmgr_forward_inbound(struct pxping *pxping, u16_t iplen);
    169194static void pxping_pcb_forward_inbound(void *arg);
     195
     196static void pxping_pmgr_forward_inbound6(struct pxping *pxping,
     197                                         ip6_addr_t *src, ip6_addr_t *dst,
     198                                         u8_t hopl, u8_t tclass,
     199                                         u16_t icmplen);
     200static void pxping_pcb_forward_inbound6(void *arg);
    170201
    171202/*
     
    187218
    188219err_t
    189 pxping_init(struct netif *netif, SOCKET sock)
    190 {
    191     if (sock == INVALID_SOCKET) {
     220pxping_init(struct netif *netif, SOCKET sock4, SOCKET sock6)
     221{
     222    const int on = 1;
     223    int status;
     224
     225    if (sock4 == INVALID_SOCKET && sock6 == INVALID_SOCKET) {
    192226        return ERR_VAL;
    193227    }
    194228
    195229    g_pxping.netif = netif;
    196 
    197     g_pxping.sock4 = sock;
    198     g_pxping.ttl = -1;
    199     g_pxping.tos = 0;
    200 
    201230    sys_mutex_new(&g_pxping.lock);
    202231
    203     g_pxping.pmhdl4.callback = pxping_pmgr_pump;
    204     g_pxping.pmhdl4.data = (void *)&g_pxping;
    205     g_pxping.pmhdl4.slot = -1;
    206 
    207     pollmgr_add(&g_pxping.pmhdl4, g_pxping.sock4, POLLIN);
    208 
    209     ping_proxy_accept(pxping_recv4, &g_pxping);
     232    g_pxping.sock4 = sock4;
     233    if (g_pxping.sock4 != INVALID_SOCKET) {
     234        g_pxping.ttl = -1;
     235        g_pxping.tos = 0;
     236
     237        g_pxping.pmhdl4.callback = pxping_pmgr_pump;
     238        g_pxping.pmhdl4.data = (void *)&g_pxping;
     239        g_pxping.pmhdl4.slot = -1;
     240        pollmgr_add(&g_pxping.pmhdl4, g_pxping.sock4, POLLIN);
     241
     242        ping_proxy_accept(pxping_recv4, &g_pxping);
     243    }
     244
     245    g_pxping.sock6 = sock6;
     246    if (g_pxping.sock6 != INVALID_SOCKET) {
     247        g_pxping.hopl = -1;
     248
     249#if !defined(IPV6_RECVPKTINFO)
     250#define IPV6_RECVPKTINFO (IPV6_PKTINFO)
     251#endif
     252        status = setsockopt(sock6, IPPROTO_IPV6, IPV6_RECVPKTINFO,
     253                            (const char *)&on, sizeof(on));
     254        if (status < 0) {
     255            perror("IPV6_RECVPKTINFO");
     256            /* XXX: this is fatal */
     257        }
     258
     259#if !defined(IPV6_RECVHOPLIMIT)
     260#define IPV6_RECVHOPLIMIT (IPV6_HOPLIMIT)
     261#endif
     262        status = setsockopt(sock6, IPPROTO_IPV6, IPV6_RECVHOPLIMIT,
     263                            (const char *)&on, sizeof(on));
     264        if (status < 0) {
     265            perror("IPV6_RECVHOPLIMIT");
     266        }
     267
     268#ifdef IPV6_RECVTCLASS
     269        /* TODO: IPV6_RECVTCLASS */
     270#endif
     271
     272        g_pxping.pmhdl6.callback = pxping_pmgr_pump;
     273        g_pxping.pmhdl6.data = (void *)&g_pxping;
     274        g_pxping.pmhdl6.slot = -1;
     275        pollmgr_add(&g_pxping.pmhdl6, g_pxping.sock6, POLLIN);
     276
     277        ping6_proxy_accept(pxping_recv6, &g_pxping);
     278    }
     279
    210280    return ERR_OK;
    211281}
     
    231301
    232302    *oldp = u;
     303    return sum;
     304}
     305
     306
     307static u32_t
     308updateip6_with_chksum(ip6_addr_t *oldp, const ip6_addr_t *ip6)
     309{
     310    u32_t sum;
     311
     312    sum  = update32_with_chksum(&oldp->addr[0], ip6->addr[0]);
     313    sum += update32_with_chksum(&oldp->addr[1], ip6->addr[1]);
     314    sum += update32_with_chksum(&oldp->addr[2], ip6->addr[2]);
     315    sum += update32_with_chksum(&oldp->addr[3], ip6->addr[3]);
     316
    233317    return sum;
    234318}
     
    260344
    261345    pcb = pxping_pcb_for_request(pxping, 0,
    262                                  ip_2_ipX(ip_current_src_addr()),
    263                                  ip_2_ipX(ip_current_dest_addr()),
     346                                 ipX_current_src_addr(),
     347                                 ipX_current_dest_addr(),
    264348                                 id);
    265349    if (pcb == NULL) {
     
    319403
    320404
     405/**
     406 * ICMPv6 Echo Request in pbuf "p" is to be proxied.
     407 */
     408static void
     409pxping_recv6(void *arg, struct pbuf *p)
     410{
     411    struct pxping *pxping = (struct pxping *)arg;
     412    struct ping_pcb *pcb;
     413    struct ip6_hdr *iph;
     414    struct icmp6_echo_hdr *icmph;
     415    int hopl;
     416    u32_t sum;
     417    u16_t iphlen;
     418    u16_t id, seq;
     419    int status;
     420
     421    iph = (/* UNCONST */ struct ip6_hdr *)ip6_current_header();
     422    iphlen = ip_current_header_tot_len();
     423
     424    icmph = (struct icmp6_echo_hdr *)p->payload;
     425
     426    id  = icmph->id;
     427    seq = icmph->seqno;
     428
     429    pcb = pxping_pcb_for_request(pxping, 1,
     430                                 ipX_current_src_addr(),
     431                                 ipX_current_dest_addr(),
     432                                 id);
     433    if (pcb == NULL) {
     434        pbuf_free(p);
     435        return;
     436    }
     437
     438    pxping_pcb_debug_print(pcb); /* XXX */
     439    printf(" seq %d len %u hopl %d\n",
     440           ntohs(seq), (unsigned int)p->tot_len,
     441           IP6H_HOPLIM(iph));
     442
     443    hopl = IP6H_HOPLIM(iph);
     444    if (!pcb->is_mapped) {
     445        if (hopl == 1) {
     446            pbuf_header(p, iphlen); /* back to IP header */
     447            icmp6_time_exceeded(p, ICMP6_TE_HL);
     448            return;
     449        }
     450        --hopl;
     451    }
     452
     453    /*
     454     * Rewrite ICMPv6 echo header.  We don't need to recompute the
     455     * checksum since, unlike IPv4, checksum includes pseudo-header.
     456     * OS computes checksum for us on send() since it needs to select
     457     * source address.
     458     */
     459    icmph->id = pcb->host_id;
     460
     461    /* TODO: use control messages to save a syscall? */
     462    if (hopl != pxping->hopl) {
     463        status = setsockopt(pxping->sock6, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
     464                            (char *)&hopl, sizeof(hopl));
     465        if (status == 0) {
     466            pxping->hopl = hopl;
     467        }
     468        else {
     469            perror("IPV6_HOPLIMIT");
     470        }
     471    }
     472
     473    proxy_sendto(pxping->sock6, p,
     474                 &pcb->peer.sin6, sizeof(pcb->peer.sin6));
     475
     476    pbuf_free(p);
     477}
     478
     479
    321480static void
    322481pxping_pcb_debug_print(struct ping_pcb *pcb)
    323482{
    324     printf("ping %p: %d.%d.%d.%d -> %d.%d.%d.%d id %04x->%04x",
    325            (void *)pcb,
    326            ip4_addr1(&pcb->src), ip4_addr2(&pcb->src),
    327            ip4_addr3(&pcb->src), ip4_addr4(&pcb->src),
    328            ip4_addr1(&pcb->dst), ip4_addr2(&pcb->dst),
    329            ip4_addr3(&pcb->dst), ip4_addr4(&pcb->dst),
    330            ntohs(pcb->guest_id),
    331            ntohs(pcb->host_id));
     483    char addrbuf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
     484    const char *addrstr;
     485    int sdom = pcb->is_ipv6 ? AF_INET6 : AF_INET;
     486
     487    DPRINTF(("ping %p:", (void *)pcb));
     488
     489    addrstr = inet_ntop(sdom, (void *)&pcb->src, addrbuf, sizeof(addrbuf));
     490    DPRINTF((" %s", addrstr));
     491
     492    DPRINTF((" ->"));
     493
     494    addrstr = inet_ntop(sdom, (void *)&pcb->dst, addrbuf, sizeof(addrbuf));
     495    DPRINTF((" %s", addrstr));
     496
     497    DPRINTF((" id %04x->%04x", ntohs(pcb->guest_id), ntohs(pcb->host_id)));
    332498}
    333499
     
    442608
    443609    if (pcb == NULL) {
     610        int mapped;
     611
    444612        pcb = pxping_pcb_allocate(pxping);
    445613        if (pcb == NULL) {
     
    461629
    462630        if (is_ipv6) {
     631            pcb->peer.sin6.sin6_family = AF_INET6;
     632#if HAVE_SA_LEN
     633            pcb->peer.sin6.sin6_len = sizeof(pcb->peer.sin6);
     634#endif
     635            pcb->peer.sin.sin_port = htons(IPPROTO_ICMPV6);
     636            mapped = pxremap_outbound_ip6((ip6_addr_t *)&pcb->peer.sin6.sin6_addr,
     637                                          ipX_2_ip6(&pcb->dst));
    463638        }
    464639        else {
    465             int mapped;
    466 
    467640            pcb->peer.sin.sin_family = AF_INET;
    468641#if HAVE_SA_LEN
    469642            pcb->peer.sin.sin_len = sizeof(pcb->peer.sin);
    470643#endif
     644            pcb->peer.sin.sin_port = htons(IPPROTO_ICMP);
    471645            mapped = pxremap_outbound_ip4((ip_addr_t *)&pcb->peer.sin.sin_addr,
    472646                                          ipX_2_ip(&pcb->dst));
    473             if (mapped == PXREMAP_FAILED) {
    474                 free(pcb);
    475                 return NULL;
    476             }
    477             else {
    478                 pcb->is_mapped = (mapped == PXREMAP_MAPPED);
    479             }
    480             pcb->peer.sin.sin_port = htons(IP_PROTO_ICMP);
     647        }
     648
     649        if (mapped == PXREMAP_FAILED) {
     650            free(pcb);
     651            return NULL;
     652        }
     653        else {
     654            pcb->is_mapped = (mapped == PXREMAP_MAPPED);
    481655        }
    482656
     
    596770
    597771
    598 static struct ping_msg *
    599 pxping_msg_allocate(struct pxping *pxping, struct pbuf *p)
    600 {
    601     struct ping_msg *msg;
    602 
    603     msg = (struct ping_msg *)malloc(sizeof(*msg));
    604     if (msg == NULL) {
    605         return NULL;
    606     }
    607 
    608     msg->msg.type = TCPIP_MSG_CALLBACK_STATIC;
    609     msg->msg.sem = NULL;
    610     msg->msg.msg.cb.function = pxping_pcb_forward_inbound;
    611     msg->msg.msg.cb.ctx = (void *)msg;
    612 
    613     msg->pxping = pxping;
    614     msg->p = p;
    615 
    616     return msg;
    617 }
    618 
    619 
    620772static int
    621773pxping_pmgr_pump(struct pollmgr_handler *handler, SOCKET fd, int revents)
    622774{
    623775    struct pxping *pxping;
    624     struct sockaddr_storage ss;
    625     socklen_t sslen = sizeof(ss);
    626     ssize_t nread;
    627776
    628777    pxping = (struct pxping *)handler->data;
     778    LWIP_ASSERT1(fd == pxping->sock4 || fd == pxping->sock6);
    629779
    630780    if (revents & ~(POLLIN|POLLERR)) {
     
    654804    }
    655805
    656     memset(&ss, 0, sizeof(ss));
    657     nread = recvfrom(fd, pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0,
    658                      (struct sockaddr *)&ss, &sslen);
    659     if (nread < 0) {
    660         perror(__func__);
    661         return POLLIN;
    662     }
    663 
    664     pxping_pmgr_icmp4(pxping, nread, (struct sockaddr_in *)&ss);
     806    if (fd == pxping->sock4) {
     807        pxping_pmgr_icmp4(pxping);
     808    }
     809    else /* fd == pxping->sock6 */ {
     810        pxping_pmgr_icmp6(pxping);
     811    }
    665812
    666813    return POLLIN;
     
    673820 */
    674821static void
    675 pxping_pmgr_icmp4(struct pxping *pxping,
    676                   size_t nread, struct sockaddr_in *peer)
    677 {
     822pxping_pmgr_icmp4(struct pxping *pxping)
     823{
     824    struct sockaddr_in sin;
     825    socklen_t salen = sizeof(sin);
     826    ssize_t nread;
    678827    struct ip_hdr *iph;
    679828    struct icmp_echo_hdr *icmph;
    680829    u16_t iplen;
     830
     831    memset(&sin, 0, sizeof(sin));
     832
     833    /*
     834     * Reads from raw IPv4 sockets deliver complete IP datagrams with
     835     * IP header included.
     836     */
     837    nread = recvfrom(pxping->sock4, pollmgr_udpbuf, sizeof(pollmgr_udpbuf), 0,
     838                     (struct sockaddr *)&sin, &salen);
     839    if (nread < 0) {
     840        perror(__func__);
     841        return;
     842    }
    681843
    682844    if (nread < IP_HLEN) {
     
    712874    }
    713875
     876    /* XXX: TODO: not for loopback */
    714877    if (IPH_TTL(iph) == 1) {
    715878        DPRINTF2(("%s: dropping packet with ttl 1\n", __func__));
     
    741904    icmph = (struct icmp_echo_hdr *)(pollmgr_udpbuf + IP_HLEN);
    742905    if (ICMPH_TYPE(icmph) == ICMP_ER) {
    743         pxping_pmgr_icmp4_echo(pxping, iplen, peer);
     906        pxping_pmgr_icmp4_echo(pxping, iplen, &sin);
    744907    }
    745908    else if (ICMPH_TYPE(icmph) == ICMP_DUR || ICMPH_TYPE(icmph) == ICMP_TE) {
    746         pxping_pmgr_icmp4_error(pxping, iplen, peer);
     909        pxping_pmgr_icmp4_error(pxping, iplen, &sin);
    747910    }
    748911#if 1
     
    808971    sys_mutex_unlock(&pxping->lock);
    809972
    810     /* rewrite inner ICMP echo header */
     973    /* rewrite ICMP echo header */
    811974    sum = (u16_t)~icmph->chksum;
    812975    sum += update16_with_chksum(&icmph->id, guest_id);
     
    814977    icmph->chksum = ~sum;
    815978
    816     /* rewrite outer IP header */
     979    /* rewrite IP header */
    817980    sum = (u16_t)~IPH_CHKSUM(iph);
    818981    sum += update32_with_chksum((u32_t *)&iph->dest,
     
    8481011    ip_addr_t pcb_src, pcb_dst;
    8491012    u16_t guest_id;
     1013    int mapped;
    8501014    u32_t sum;
    8511015
     
    9281092
    9291093    /* save info before unlocking since pcb may expire */
     1094    mapped = pcb->is_mapped;
    9301095    ip_addr_copy(pcb_src, *ipX_2_ip(&pcb->src));
    9311096    ip_addr_copy(pcb_dst, *ipX_2_ip(&pcb->dst));
     
    9481113    sum = (u16_t)~IPH_CHKSUM(oiph);
    9491114    sum += update32_with_chksum((u32_t *)&oiph->src, ip4_addr_get_u32(&pcb_src));
     1115    /* XXX: FIXME: rewrite dst if mapped */
    9501116    sum = FOLD_U32T(sum);
    9511117    IPH_CHKSUM_SET(oiph, ~sum);
     
    9541120    sum = (u16_t)~IPH_CHKSUM(iph);
    9551121    sum += update32_with_chksum((u32_t *)&iph->dest, ip4_addr_get_u32(&pcb_src));
    956     IPH_TTL_SET(iph, IPH_TTL(iph) - 1);
    957     sum += PP_NTOHS(~0x0100);
     1122    if (!mapped) { /* XXX: FIXME: error may be from elsewhere */
     1123        IPH_TTL_SET(iph, IPH_TTL(iph) - 1);
     1124        sum += PP_NTOHS(~0x0100);
     1125    }
    9581126    sum = FOLD_U32T(sum);
    9591127    IPH_CHKSUM_SET(iph, ~sum);
    9601128
    9611129    pxping_pmgr_forward_inbound(pxping, iplen);
     1130}
     1131
     1132
     1133static void
     1134pxping_pmgr_icmp6(struct pxping *pxping)
     1135{
     1136    struct msghdr mh;
     1137    struct iovec iov[1];
     1138    static u8_t cmsgbuf[128];
     1139    struct cmsghdr *cmh;
     1140    struct sockaddr_in6 sin6;
     1141    socklen_t salen = sizeof(sin6);
     1142    ssize_t nread;
     1143    struct icmp6_echo_hdr *icmph;
     1144#if defined(RT_OS_LINUX) && !defined(__USE_GNU)
     1145    /* XXX: https://sourceware.org/bugzilla/show_bug.cgi?id=6775 */
     1146    struct in6_pktinfo {
     1147        struct in6_addr ipi6_addr;
     1148        unsigned int ipi6_ifindex;
     1149    };
     1150#endif
     1151    struct in6_pktinfo *pktinfo;
     1152    int hopl, tclass;
     1153
     1154    int mapped;
     1155    struct ping_pcb *pcb;
     1156    ip6_addr_t guest_ip, target_ip, unmapped_target_ip;
     1157    u16_t id, guest_id;
     1158    u32_t sum;
     1159
     1160    char addrbuf[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
     1161    const char *addrstr;
     1162
     1163    /*
     1164     * Reads from raw IPv6 sockets deliver only the payload.  Full
     1165     * headers are available via recvmsg(2)/cmsg(3).
     1166     */
     1167    memset(&mh, 0, sizeof(mh));
     1168    mh.msg_name = &sin6;
     1169    mh.msg_namelen = sizeof(sin6);
     1170    iov[0].iov_base = pollmgr_udpbuf;
     1171    iov[0].iov_len = sizeof(pollmgr_udpbuf);
     1172    mh.msg_iov = iov;
     1173    mh.msg_iovlen = 1;
     1174    mh.msg_control = cmsgbuf;
     1175    mh.msg_controllen = sizeof(cmsgbuf);
     1176    mh.msg_flags = 0;
     1177
     1178    nread = recvmsg(pxping->sock6, &mh, 0);
     1179    if (nread < 0) {
     1180        perror(__func__);
     1181        return;
     1182    }
     1183    addrstr = inet_ntop(AF_INET6, (void *)&sin6.sin6_addr, addrbuf, sizeof(addrbuf));
     1184
     1185    icmph = (struct icmp6_echo_hdr *)pollmgr_udpbuf;
     1186    DPRINTF2(("%s: %s ICMPv6: ", __func__, addrstr));
     1187
     1188    id = 0;
     1189    if (icmph->type == ICMP6_TYPE_EREP) {
     1190        id = icmph->id;
     1191        DPRINTF2(("echo reply %04x %u\n",
     1192                  (unsigned int)icmph->id, (unsigned int)icmph->seqno));
     1193    }
     1194    else { /* XXX */
     1195        if (icmph->type == ICMP6_TYPE_EREQ) {
     1196            DPRINTF2(("echo request %04x %u\n",
     1197                      (unsigned int)icmph->id, (unsigned int)icmph->seqno));
     1198        }
     1199        else if (icmph->type == ICMP6_TYPE_DUR) {
     1200            DPRINTF2(("destination unreachable\n"));
     1201        }
     1202        else if (icmph->type == ICMP6_TYPE_PTB) {
     1203            DPRINTF2(("packet too big\n"));
     1204        }
     1205        else if (icmph->type == ICMP6_TYPE_TE) {
     1206            DPRINTF2(("time exceeded\n"));
     1207        }
     1208        else if (icmph->type == ICMP6_TYPE_PP) {
     1209            DPRINTF2(("parameter problem\n"));
     1210        }
     1211        else {
     1212            DPRINTF2(("type %d len %u\n", icmph->type, (unsigned int)nread));
     1213        }
     1214        return;
     1215    }
     1216
     1217    /* XXX: refactor into pxping_pmgr_icmp6_echo(), pxping_pmgr_icmp6_error() */
     1218
     1219    pktinfo = NULL;
     1220    hopl = -1;
     1221    tclass = -1;
     1222    for (cmh = CMSG_FIRSTHDR(&mh); cmh != NULL; cmh = CMSG_NXTHDR(&mh, cmh)) {
     1223        if (cmh->cmsg_len == 0)
     1224            break;
     1225
     1226        if (cmh->cmsg_level == IPPROTO_IPV6
     1227            && cmh->cmsg_type == IPV6_HOPLIMIT
     1228            && cmh->cmsg_len == CMSG_LEN(sizeof(int)))
     1229        {
     1230            hopl = *(int *)CMSG_DATA(cmh);
     1231            DPRINTF2(("hoplimit = %d\n", hopl));
     1232        }
     1233
     1234        if (cmh->cmsg_level == IPPROTO_IPV6
     1235            && cmh->cmsg_type == IPV6_PKTINFO
     1236            && cmh->cmsg_len == CMSG_LEN(sizeof(struct in6_pktinfo)))
     1237        {
     1238            pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmh);
     1239            DPRINTF2(("pktinfo found\n"));
     1240        }
     1241    }
     1242
     1243    if (pktinfo == NULL) {
     1244        /*
     1245         * ip6_output_if() doesn't do checksum for us so we need to
     1246         * manually recompute it - for this we must know the
     1247         * destination address of the pseudo-header that we will
     1248         * rewrite with guest's address.
     1249         */
     1250        DPRINTF2(("%s: unable to get pktinfo\n", __func__));
     1251        return;
     1252    }
     1253
     1254    ip6_addr_copy(target_ip, *(ip6_addr_t *)&sin6.sin6_addr);
     1255    mapped = pxremap_inbound_ip6(&unmapped_target_ip, &target_ip);
     1256    if (mapped == PXREMAP_FAILED) {
     1257        return;
     1258    }
     1259
     1260    sys_mutex_lock(&pxping->lock);
     1261    pcb = pxping_pcb_for_reply(pxping, 1, ip6_2_ipX(&unmapped_target_ip), id);
     1262    if (pcb == NULL) {
     1263        sys_mutex_unlock(&pxping->lock);
     1264        DPRINTF2(("%s: no match\n", __func__));
     1265        return;
     1266    }
     1267
     1268    DPRINTF2(("%s: pcb %p\n", __func__, (void *)pcb));
     1269
     1270    /* save info before unlocking since pcb may expire */
     1271    ip6_addr_copy(guest_ip, *ipX_2_ip6(&pcb->src));
     1272    guest_id = pcb->guest_id;
     1273
     1274    sys_mutex_unlock(&pxping->lock);
     1275
     1276    /* rewrite ICMPv6 echo header */
     1277    sum = (u16_t)~icmph->chksum;
     1278    sum += update16_with_chksum(&icmph->id, guest_id);
     1279
     1280    /* dst address in pseudo header (clobbers pktinfo) */
     1281    sum += updateip6_with_chksum((ip6_addr_t *)&pktinfo->ipi6_addr, &guest_ip);
     1282
     1283    /* src address in pseudo header (clobbers target_ip) */
     1284    if (mapped) {
     1285        sum += updateip6_with_chksum(&target_ip, &unmapped_target_ip);
     1286    }
     1287
     1288    sum = FOLD_U32T(sum);
     1289    icmph->chksum = ~sum;
     1290
     1291    if (hopl < 0) {
     1292        hopl = LWIP_ICMP6_HL;
     1293    }
     1294    else if (!mapped) {
     1295        if (hopl == 1) {
     1296            return;
     1297        }
     1298        --hopl;
     1299    }
     1300
     1301    if (tclass < 0) {
     1302        tclass = 0;
     1303    }
     1304
     1305    pxping_pmgr_forward_inbound6(pxping,
     1306                                 &unmapped_target_ip, /* echo reply src */
     1307                                 &guest_ip, /* echo reply dst */
     1308                                 hopl, tclass, (u16_t)nread);
     1309}
     1310
     1311
     1312static void
     1313pxping_pmgr_icmp6_echo(struct pxping *pxping,
     1314                       u16_t iplen, struct sockaddr_in6 *peer)
     1315{
     1316}
     1317
     1318static void
     1319pxping_pmgr_icmp6_error(struct pxping *pxping,
     1320                        u16_t iplen, struct sockaddr_in6 *peer)
     1321{
    9621322}
    9631323
     
    9851345    }
    9861346
    987     error = pbuf_take(p, pollmgr_udpbuf, (u16_t)iplen);
     1347    error = pbuf_take(p, pollmgr_udpbuf, iplen);
    9881348    if (error != ERR_OK) {
    9891349        DPRINTF(("%s: pbuf_take(%d) failed\n",
     
    9931353    }
    9941354
    995     msg = pxping_msg_allocate(pxping, p);
     1355    msg = (struct ping_msg *)malloc(sizeof(*msg));
    9961356    if (msg == NULL) {
    9971357        pbuf_free(p);
     
    9991359    }
    10001360
    1001     /* call pxping_pcb_forward_inbound() on lwip thread */
     1361    msg->msg.type = TCPIP_MSG_CALLBACK_STATIC;
     1362    msg->msg.sem = NULL;
     1363    msg->msg.msg.cb.function = pxping_pcb_forward_inbound;
     1364    msg->msg.msg.cb.ctx = (void *)msg;
     1365
     1366    msg->pxping = pxping;
     1367    msg->p = p;
     1368
    10021369    proxy_lwip_post(&msg->msg);
    10031370}
     
    10181385        DPRINTF(("%s: ip_output_if: %s\n",
    10191386                 __func__, proxy_lwip_strerr(error)));
     1387        pbuf_free(msg->p);
    10201388    }
    10211389
    10221390    free(msg);
    10231391}
     1392
     1393
     1394static void
     1395pxping_pmgr_forward_inbound6(struct pxping *pxping,
     1396                             ip6_addr_t *src, ip6_addr_t *dst,
     1397                             u8_t hopl, u8_t tclass,
     1398                             u16_t icmplen)
     1399{
     1400    struct pbuf *p;
     1401    struct ping6_msg *msg;
     1402
     1403    err_t error;
     1404
     1405    p = pbuf_alloc(PBUF_IP, icmplen, PBUF_RAM);
     1406    if (p == NULL) {
     1407        DPRINTF(("%s: pbuf_alloc(%d) failed\n",
     1408                 __func__, (unsigned int)icmplen));
     1409        return;
     1410    }
     1411
     1412    error = pbuf_take(p, pollmgr_udpbuf, icmplen);
     1413    if (error != ERR_OK) {
     1414        DPRINTF(("%s: pbuf_take(%d) failed\n",
     1415                 __func__, (unsigned int)icmplen));
     1416        pbuf_free(p);
     1417        return;
     1418    }
     1419
     1420    msg = (struct ping6_msg *)malloc(sizeof(*msg));
     1421    if (msg == NULL) {
     1422        pbuf_free(p);
     1423        return;
     1424    }
     1425
     1426    msg->msg.type = TCPIP_MSG_CALLBACK_STATIC;
     1427    msg->msg.sem = NULL;
     1428    msg->msg.msg.cb.function = pxping_pcb_forward_inbound6;
     1429    msg->msg.msg.cb.ctx = (void *)msg;
     1430
     1431    msg->pxping = pxping;
     1432    msg->p = p;
     1433    ip6_addr_copy(msg->src, *src);
     1434    ip6_addr_copy(msg->dst, *dst);
     1435    msg->hopl = hopl;
     1436    msg->tclass = tclass;
     1437
     1438    proxy_lwip_post(&msg->msg);
     1439}
     1440
     1441
     1442static void
     1443pxping_pcb_forward_inbound6(void *arg)
     1444{
     1445    struct ping6_msg *msg = (struct ping6_msg *)arg;
     1446    err_t error;
     1447
     1448    LWIP_ASSERT1(msg != NULL);
     1449    LWIP_ASSERT1(msg->pxping != NULL);
     1450    LWIP_ASSERT1(msg->p != NULL);
     1451
     1452    error = ip6_output_if(msg->p,
     1453                          &msg->src, &msg->dst, msg->hopl, msg->tclass,
     1454                          IP6_NEXTH_ICMP6, msg->pxping->netif);
     1455    if (error != ERR_OK) {
     1456        DPRINTF(("%s: ip6_output_if: %s\n",
     1457                 __func__, proxy_lwip_strerr(error)));
     1458        pbuf_free(msg->p);
     1459    }
     1460
     1461    free(msg);
     1462}
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette