diff --git a/core/net/uip-icmp6.c b/core/net/uip-icmp6.c index c5ff855e4..d87067c6d 100644 --- a/core/net/uip-icmp6.c +++ b/core/net/uip-icmp6.c @@ -71,6 +71,8 @@ static uip_ipaddr_t tmp_ipaddr; #include "rpl/rpl.h" #endif /* UIP_CONF_IPV6_RPL */ +LIST(echo_reply_callback_list); + #if UIP_CONF_IPV6 /*---------------------------------------------------------------------------*/ void @@ -238,7 +240,7 @@ uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param) { UIP_STAT(++uip_stat.icmp.sent); - PRINTF("Sending ICMPv6 ERROR message to"); + PRINTF("Sending ICMPv6 ERROR message type %d code %d to", type, code); PRINT6ADDR(&UIP_IP_BUF->destipaddr); PRINTF("from"); PRINT6ADDR(&UIP_IP_BUF->srcipaddr); @@ -248,7 +250,7 @@ uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param) { /*---------------------------------------------------------------------------*/ void -uip_icmp6_send(uip_ipaddr_t *dest, int type, int code, int payload_len) +uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len) { UIP_IP_BUF->vtc = 0x60; @@ -272,6 +274,92 @@ uip_icmp6_send(uip_ipaddr_t *dest, int type, int code, int payload_len) tcpip_ipv6_output(); } /*---------------------------------------------------------------------------*/ +void +uip_icmp6_echo_reply_input(void) +{ + int ttl; + uip_ipaddr_t sender; +#if UIP_CONF_IPV6_RPL + uint8_t temp_ext_len; +#endif /* UIP_CONF_IPV6_RPL */ + uip_ipaddr_copy(&sender, &UIP_IP_BUF->srcipaddr); + ttl = UIP_IP_BUF->ttl; + + if(uip_ext_len > 0) { +#if UIP_CONF_IPV6_RPL + if((temp_ext_len = rpl_invert_header())) { + /* If there were other extension headers*/ + UIP_FIRST_EXT_BUF->next = UIP_PROTO_ICMP6; + if (uip_ext_len != temp_ext_len) { + uip_len -= (uip_ext_len - temp_ext_len); + UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); + /* move the echo reply payload (starting after the icmp + * header) to the new location in the reply. The shift is + * equal to the length of the remaining extension headers + * present Note: UIP_ICMP_BUF still points to the echo reply + * at this stage + */ + memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - (uip_ext_len - temp_ext_len), + (uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN, + (uip_len - UIP_IPH_LEN - temp_ext_len - UIP_ICMPH_LEN)); + } + uip_ext_len = temp_ext_len; + uip_len -= uip_ext_len; + } else { +#endif /* UIP_CONF_IPV6_RPL */ + /* If there were extension headers*/ + UIP_IP_BUF->proto = UIP_PROTO_ICMP6; + uip_len -= uip_ext_len; + UIP_IP_BUF->len[0] = ((uip_len - UIP_IPH_LEN) >> 8); + UIP_IP_BUF->len[1] = ((uip_len - UIP_IPH_LEN) & 0xff); + /* move the echo reply payload (starting after the icmp header) + * to the new location in the reply. The shift is equal to the + * length of the extension headers present Note: UIP_ICMP_BUF + * still points to the echo request at this stage + */ + memmove((uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN - uip_ext_len, + (uint8_t *)UIP_ICMP_BUF + UIP_ICMPH_LEN, + (uip_len - UIP_IPH_LEN - UIP_ICMPH_LEN)); + uip_ext_len = 0; +#if UIP_CONF_IPV6_RPL + } +#endif /* UIP_CONF_IPV6_RPL */ + } + + /* Call all registered applications to let them know an echo reply + has been received. */ + { + struct uip_icmp6_echo_reply_notification *n; + for(n = list_head(echo_reply_callback_list); + n != NULL; + n = list_item_next(n)) { + if(n->callback != NULL) { + n->callback(&sender, ttl, + (uint8_t *)&UIP_ICMP_BUF[sizeof(struct uip_icmp_hdr)], + uip_len - sizeof(struct uip_icmp_hdr) - UIP_IPH_LEN); + } + } + } + return; +} +/*---------------------------------------------------------------------------*/ +void +uip_icmp6_echo_reply_callback_add(struct uip_icmp6_echo_reply_notification *n, + uip_icmp6_echo_reply_callback_t c) +{ + if(n != NULL && c != NULL) { + n->callback = c; + list_add(echo_reply_callback_list, n); + } +} +/*---------------------------------------------------------------------------*/ +void +uip_icmp6_echo_reply_callback_rm(struct uip_icmp6_echo_reply_notification *n) +{ + list_remove(echo_reply_callback_list, n); +} +/*---------------------------------------------------------------------------*/ /** @} */ #endif /* UIP_CONF_IPV6 */ diff --git a/core/net/uip-icmp6.h b/core/net/uip-icmp6.h index add6d7053..a33cdfd0e 100644 --- a/core/net/uip-icmp6.h +++ b/core/net/uip-icmp6.h @@ -113,6 +113,15 @@ typedef struct uip_icmp6_error{ void uip_icmp6_echo_request_input(void); +/** \ + * brief Process an echo reply + * + * Perform a few checks, then call applications to inform that an echo + * reply has been received. + */ +void +uip_icmp6_echo_reply_input(void); + /** * \brief Send an icmpv6 error message * \param type type of the error message @@ -130,7 +139,55 @@ uip_icmp6_error_output(uint8_t type, uint8_t code, uint32_t param); * \param payload_len length of the payload */ void -uip_icmp6_send(uip_ipaddr_t *dest, int type, int code, int payload_len); +uip_icmp6_send(const uip_ipaddr_t *dest, int type, int code, int payload_len); + + + +typedef void (* uip_icmp6_echo_reply_callback_t)(uip_ipaddr_t *source, + uint8_t ttl, + uint8_t *data, + uint16_t datalen); +struct uip_icmp6_echo_reply_notification { + struct uip_icmp6_echo_reply_notification *next; + uip_icmp6_echo_reply_callback_t callback; +}; + +/** + * \brief Add a callback function for ping replies + * \param n A struct uip_icmp6_echo_reply_notification that must have been allocated by the caller + * \param c A pointer to the callback function to be called + * + * This function adds a callback function to the list of + * callback functions that are called when an ICMP echo + * reply (ping reply) is received. This is used when + * implementing a ping protocol: attach a callback + * function to the ping reply, then send out a ping packet + * with uip_icmp6_send(). + * + * The caller must have statically allocated a struct + * uip_icmp6_echo_reply_notification to hold the internal + * state of the callback function. + * + * When a ping reply packet is received, all registered + * callback functions are called. The callback functions + * must not modify the contents of the uIP buffer. + */ +void +uip_icmp6_echo_reply_callback_add(struct uip_icmp6_echo_reply_notification *n, + uip_icmp6_echo_reply_callback_t c); + +/** + * \brief Remove a callback function for ping replies + * \param n A struct uip_icmp6_echo_reply_notification that must have been previously added with uip_icmp6_echo_reply_callback_add() + * + * This function removes a callback function from the list of + * callback functions that are called when an ICMP echo + * reply (ping reply) is received. + */ +void +uip_icmp6_echo_reply_callback_rm(struct uip_icmp6_echo_reply_notification *n); + + /** @} */ diff --git a/core/net/uip6.c b/core/net/uip6.c index f3f29ebf1..d0b2095ee 100644 --- a/core/net/uip6.c +++ b/core/net/uip6.c @@ -1431,7 +1431,8 @@ uip_process(uint8_t flag) uip_icmp6_echo_request_input(); break; case ICMP6_ECHO_REPLY: - /** \note We don't implement any application callback for now */ + /** Call echo reply input function. */ + uip_icmp6_echo_reply_input(); PRINTF("Received an icmp6 echo reply\n"); UIP_STAT(++uip_stat.icmp.recv); uip_len = 0;