net/ipv6/rpl_iptunnel.c

Source file repositories/reference/linux-study-clean/net/ipv6/rpl_iptunnel.c

File Facts

System
Linux kernel
Corpus path
net/ipv6/rpl_iptunnel.c
Extension
.c
Size
9097 bytes
Lines
404
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct rpl_iptunnel_encap {
	DECLARE_FLEX_ARRAY(struct ipv6_rpl_sr_hdr, srh);
};

struct rpl_lwt {
	struct dst_cache cache;
	struct rpl_iptunnel_encap tuninfo;
};

static inline struct rpl_lwt *rpl_lwt_lwtunnel(struct lwtunnel_state *lwt)
{
	return (struct rpl_lwt *)lwt->data;
}

static inline struct rpl_iptunnel_encap *
rpl_encap_lwtunnel(struct lwtunnel_state *lwt)
{
	return &rpl_lwt_lwtunnel(lwt)->tuninfo;
}

static const struct nla_policy rpl_iptunnel_policy[RPL_IPTUNNEL_MAX + 1] = {
	[RPL_IPTUNNEL_SRH]	= { .type = NLA_BINARY },
};

static bool rpl_validate_srh(struct net *net, struct ipv6_rpl_sr_hdr *srh,
			     size_t seglen)
{
	int err;

	if ((srh->hdrlen << 3) != seglen)
		return false;

	/* check at least one segment and seglen fit with segments_left */
	if (!srh->segments_left ||
	    (srh->segments_left * sizeof(struct in6_addr)) != seglen)
		return false;

	if (srh->cmpri || srh->cmpre)
		return false;

	err = ipv6_chk_rpl_srh_loop(net, srh->rpl_segaddr,
				    srh->segments_left);
	if (err)
		return false;

	if (ipv6_addr_type(&srh->rpl_segaddr[srh->segments_left - 1]) &
	    IPV6_ADDR_MULTICAST)
		return false;

	return true;
}

static int rpl_build_state(struct net *net, struct nlattr *nla,
			   unsigned int family, const void *cfg,
			   struct lwtunnel_state **ts,
			   struct netlink_ext_ack *extack)
{
	struct nlattr *tb[RPL_IPTUNNEL_MAX + 1];
	struct lwtunnel_state *newts;
	struct ipv6_rpl_sr_hdr *srh;
	struct rpl_lwt *rlwt;
	int err, srh_len;

	if (family != AF_INET6)
		return -EINVAL;

	err = nla_parse_nested(tb, RPL_IPTUNNEL_MAX, nla,
			       rpl_iptunnel_policy, extack);
	if (err < 0)
		return err;

	if (!tb[RPL_IPTUNNEL_SRH])
		return -EINVAL;

	srh = nla_data(tb[RPL_IPTUNNEL_SRH]);
	srh_len = nla_len(tb[RPL_IPTUNNEL_SRH]);

	if (srh_len < sizeof(*srh))
		return -EINVAL;

	/* verify that SRH is consistent */
	if (!rpl_validate_srh(net, srh, srh_len - sizeof(*srh)))
		return -EINVAL;

	newts = lwtunnel_state_alloc(srh_len + sizeof(*rlwt));
	if (!newts)
		return -ENOMEM;

	rlwt = rpl_lwt_lwtunnel(newts);

Annotation

Implementation Notes