static uint16_t ping_interrupt(struct uip_driver_s *dev, void *conn, void *pvpriv, uint16_t flags) { struct icmp_ping_s *pstate = (struct icmp_ping_s *)pvpriv; uint8_t *ptr; int failcode = -ETIMEDOUT; int i; nllvdbg("flags: %04x\n", flags); if (pstate) { /* Check if this device is on the same network as the destination device. */ if (!uip_ipaddr_maskcmp(pstate->png_addr, dev->d_ipaddr, dev->d_netmask)) { /* Destination address was not on the local network served by this * device. If a timeout occurs, then the most likely reason is * that the destination address is not reachable. */ nllvdbg("Not reachable\n"); failcode = -ENETUNREACH; } else { /* Check if this is a ICMP ECHO reply. If so, return the sequence * number to the caller. NOTE: We may not even have sent the * requested ECHO request; this could have been the delayed ECHO * response from a previous ping. */ if ((flags & UIP_ECHOREPLY) != 0 && conn != NULL) { struct uip_icmpip_hdr *icmp = (struct uip_icmpip_hdr *)conn; nlldbg("ECHO reply: id=%d seqno=%d\n", ntohs(icmp->id), ntohs(icmp->seqno)); if (ntohs(icmp->id) == pstate->png_id) { /* Consume the ECHOREPLY */ flags &= ~UIP_ECHOREPLY; dev->d_len = 0; /* Return the result to the caller */ pstate->png_result = OK; pstate->png_seqno = ntohs(icmp->seqno); goto end_wait; } } /* Check: * If the outgoing packet is available (it may have been claimed * by a sendto interrupt serving a different thread * -OR- * If the output buffer currently contains unprocessed incoming * data. * -OR- * If we have alread sent the ECHO request * * In the first two cases, we will just have to wait for the next * polling cycle. */ if (dev->d_sndlen <= 0 && /* Packet available */ (flags & UIP_NEWDATA) == 0 && /* No incoming data */ !pstate->png_sent) /* Request not sent */ { struct uip_icmpip_hdr *picmp = ICMPBUF; /* We can send the ECHO request now. * * Format the ICMP ECHO request packet */ picmp->type = ICMP_ECHO_REQUEST; picmp->icode = 0; #ifndef CONFIG_NET_IPv6 picmp->id = htons(pstate->png_id); picmp->seqno = htons(pstate->png_seqno); #else # error "IPv6 ECHO Request not implemented" #endif /* Add some easily verifiable data */ for (i = 0, ptr = ICMPDAT; i < pstate->png_datlen; i++) { *ptr++ = i; } /* Send the ICMP echo request. Note that d_sndlen is set to * the size of the ICMP payload and does not include the size * of the ICMP header. */ nlldbg("Send ECHO request: seqno=%d\n", pstate->png_seqno); dev->d_sndlen= pstate->png_datlen + 4; uip_icmpsend(dev, &pstate->png_addr); pstate->png_sent = true; return flags; } } /* Check if the selected timeout has elapsed */ if (ping_timeout(pstate)) { /* Yes.. report the timeout */ nlldbg("Ping timeout\n"); pstate->png_result = failcode; goto end_wait; } /* Continue waiting */ } return flags; end_wait: nllvdbg("Resuming\n"); /* Do not allow any further callbacks */ pstate->png_cb->flags = 0; pstate->png_cb->priv = NULL; pstate->png_cb->event = NULL; /* Wake up the waiting thread */ sem_post(&pstate->png_sem); return flags; }
static uint16_t ping_interrupt(FAR struct net_driver_s *dev, FAR void *conn, FAR void *pvpriv, uint16_t flags) { FAR struct icmpv6_ping_s *pstate = (struct icmpv6_ping_s *)pvpriv; nllvdbg("flags: %04x\n", flags); if (pstate) { /* Check if this is a ICMPv6 ECHO reply. If so, return the sequence * number to the caller. NOTE: We may not even have sent the * requested ECHO request; this could have been the delayed ECHO * response from a previous ping. */ if ((flags & ICMPv6_ECHOREPLY) != 0 && conn != NULL) { FAR struct icmpv6_echo_reply_s *reply = ICMPv6ECHOREPLY; nllvdbg("ECHO reply: id=%d seqno=%d\n", ntohs(reply->id), ntohs(reply->seqno)); if (ntohs(reply->id) == pstate->png_id) { /* Consume the ECHOREPLY */ flags &= ~ICMPv6_ECHOREPLY; dev->d_len = 0; /* Return the result to the caller */ pstate->png_result = OK; pstate->png_seqno = ntohs(reply->seqno); goto end_wait; } } /* Check: * If the outgoing packet is available (it may have been claimed * by a sendto interrupt serving a different thread) * -OR- * If the output buffer currently contains unprocessed incoming * data. * -OR- * If we have already sent the ECHO request * * In the first two cases, we will just have to wait for the next * polling cycle. */ if (dev->d_sndlen <= 0 && /* Packet available */ (flags & ICMPv6_NEWDATA) == 0 && /* No incoming data */ !pstate->png_sent) /* Request not sent */ { /* Send the ECHO request now. */ icmpv6_echo_request(dev, pstate); pstate->png_sent = true; return flags; } /* Check if the selected timeout has elapsed */ if (ping_timeout(pstate)) { int failcode; /* Check if this device is on the same network as the destination * device. */ if (!net_ipv6addr_maskcmp(pstate->png_addr, dev->d_ipv6addr, dev->d_ipv6netmask)) { /* Destination address was not on the local network served by * this device. If a timeout occurs, then the most likely * reason is that the destination address is not reachable. */ nlldbg("Not reachable\n"); failcode = -ENETUNREACH; } else { nlldbg("Ping timeout\n"); failcode = -ETIMEDOUT; } /* Report the failure */ pstate->png_result = failcode; goto end_wait; } /* Continue waiting */ } return flags; end_wait: nllvdbg("Resuming\n"); /* Do not allow any further callbacks */ pstate->png_cb->flags = 0; pstate->png_cb->priv = NULL; pstate->png_cb->event = NULL; /* Wake up the waiting thread */ sem_post(&pstate->png_sem); return flags; }