Skip to content

Commit

Permalink
net: icmpv6: Add support for Route Information option
Browse files Browse the repository at this point in the history
This commits adds handling of the Route Information option from
the Router Advertisement message. This option allows to add/delete
routes in the host based on the information sent by the router.

Signed-off-by: Robert Lubos <robert.lubos@nordicsemi.no>
  • Loading branch information
rlubos authored and carlescufi committed Dec 20, 2021
1 parent 43c6df5 commit c1dc82c
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 2 deletions.
20 changes: 20 additions & 0 deletions subsys/net/ip/icmpv6.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,26 @@ struct net_icmpv6_nd_opt_6co {
uint8_t prefix[NET_IPV6_ADDR_SIZE];
} __packed;

/* RFC 4191, ch. 2.3 */
struct net_icmpv6_nd_opt_route_info {
uint8_t prefix_len;
struct {
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
uint8_t reserved_2 :3;
uint8_t prf :2;
uint8_t reserved_1 :3;
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
uint8_t reserved_1 :3;
uint8_t prf :2;
uint8_t reserved_2 :3;
#endif
} flags;
uint32_t route_lifetime;
/* Variable-legnth prefix field follows, can be 0, 8 or 16 bytes
* depending on the option length.
*/
} __packed;

struct net_icmpv6_echo_req {
uint16_t identifier;
uint16_t sequence;
Expand Down
73 changes: 71 additions & 2 deletions subsys/net/ip/ipv6_nbr.c
Original file line number Diff line number Diff line change
Expand Up @@ -2281,6 +2281,61 @@ static inline bool handle_ra_6co(struct net_pkt *pkt, uint8_t len)
}
#endif

static inline bool handle_ra_route_info(struct net_pkt *pkt, uint8_t len)
{
NET_PKT_DATA_ACCESS_DEFINE(routeinfo_access,
struct net_icmpv6_nd_opt_route_info);
struct net_icmpv6_nd_opt_route_info *route_info;
struct net_route_entry *route;
struct in6_addr prefix_buf = { 0 };
uint8_t prefix_field_len = (len - 1) * 8;
uint32_t route_lifetime;
uint8_t prefix_len;
uint8_t preference;
int ret;

route_info = (struct net_icmpv6_nd_opt_route_info *)
net_pkt_get_data(pkt, &routeinfo_access);
if (!route_info) {
return false;
}

ret = net_pkt_acknowledge_data(pkt, &routeinfo_access);
if (ret < 0) {
return false;
}

prefix_len = route_info->prefix_len;
route_lifetime = ntohl(route_info->route_lifetime);
preference = route_info->flags.prf;

ret = net_pkt_read(pkt, &prefix_buf, prefix_field_len);
if (ret < 0) {
NET_ERR("Error reading prefix, %d", ret);
return false;
}

if (route_lifetime == 0) {
route = net_route_lookup(net_pkt_orig_iface(pkt), &prefix_buf);
if (route != NULL) {
ret = net_route_del(route);
if (ret < 0) {
NET_DBG("Failed to delete route");
}
}
} else {
route = net_route_add(net_pkt_orig_iface(pkt),
&prefix_buf,
prefix_len,
(struct in6_addr *)NET_IPV6_HDR(pkt)->src);
if (route == NULL) {
NET_DBG("Failed to add route");
}
}

return true;
}

static enum net_verdict handle_ra_input(struct net_pkt *pkt,
struct net_ipv6_hdr *ip_hdr,
struct net_icmp_hdr *icmp_hdr)
Expand Down Expand Up @@ -2404,9 +2459,23 @@ static enum net_verdict handle_ra_input(struct net_pkt *pkt,
break;
#endif
case NET_ICMPV6_ND_OPT_ROUTE:
NET_DBG("Route option skipped");
goto skip;
if (!IS_ENABLED(CONFIG_NET_ROUTE)) {
NET_DBG("Route option skipped");
goto skip;
}

/* RFC 4191, ch. 2.3 */
if (nd_opt_hdr->len == 0U || nd_opt_hdr->len > 3U) {
NET_ERR("DROP: Invalid %s length (%d)",
"route info opt", nd_opt_hdr->len);
goto drop;
}

if (!handle_ra_route_info(pkt, nd_opt_hdr->len)) {
goto drop;
}

break;
#if defined(CONFIG_NET_IPV6_RA_RDNSS)
case NET_ICMPV6_ND_OPT_RDNSS:
NET_DBG("RDNSS option skipped");
Expand Down

0 comments on commit c1dc82c

Please sign in to comment.