Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 45 additions & 55 deletions net/ipv6/exthdrs.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,19 +52,6 @@

#include <linux/uaccess.h>

/*
* Parsing tlv encoded headers.
*
* Parsing function "func" returns true, if parsing succeed
* and false, if it failed.
* It MUST NOT touch skb->h.
*/

struct tlvtype_proc {
int type;
bool (*func)(struct sk_buff *skb, int offset);
};

/*********************
Generic functions
*********************/
Expand Down Expand Up @@ -110,16 +97,22 @@ static bool ip6_tlvopt_unknown(struct sk_buff *skb, int optoff,
return false;
}

static bool ipv6_hop_ra(struct sk_buff *skb, int optoff);
static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff);
static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff);
#if IS_ENABLED(CONFIG_IPV6_MIP6)
static bool ipv6_dest_hao(struct sk_buff *skb, int optoff);
#endif

/* Parse tlv encoded option header (hop-by-hop or destination) */

static bool ip6_parse_tlv(const struct tlvtype_proc *procs,
static bool ip6_parse_tlv(bool hopbyhop,
struct sk_buff *skb,
int max_count)
{
int len = (skb_transport_header(skb)[1] + 1) << 3;
const unsigned char *nh = skb_network_header(skb);
int off = skb_network_header_len(skb);
const struct tlvtype_proc *curr;
bool disallow_unknowns = false;
int tlv_count = 0;
int padlen = 0;
Expand Down Expand Up @@ -174,20 +167,45 @@ static bool ip6_parse_tlv(const struct tlvtype_proc *procs,
if (tlv_count > max_count)
goto bad;

for (curr = procs; curr->type >= 0; curr++) {
if (curr->type == nh[off]) {
/* type specific length/alignment
checks will be performed in the
func(). */
if (curr->func(skb, off) == false)
if (hopbyhop) {
switch (nh[off]) {
case IPV6_TLV_ROUTERALERT:
if (!ipv6_hop_ra(skb, off))
return false;
break;
case IPV6_TLV_JUMBO:
if (!ipv6_hop_jumbo(skb, off))
return false;

nh = skb_network_header(skb);
break;
case IPV6_TLV_CALIPSO:
if (!ipv6_hop_calipso(skb, off))
return false;
break;
default:
if (!ip6_tlvopt_unknown(skb, off,
disallow_unknowns))
return false;
break;
}
}
if (curr->type < 0 &&
!ip6_tlvopt_unknown(skb, off, disallow_unknowns))
return false;
} else {
switch (nh[off]) {
#if IS_ENABLED(CONFIG_IPV6_MIP6)
case IPV6_TLV_HAO:
if (!ipv6_dest_hao(skb, off))
return false;

nh = skb_network_header(skb);
break;
#endif
default:
if (!ip6_tlvopt_unknown(skb, off,
disallow_unknowns))
return false;
break;
}
}
padlen = 0;
}
off += optlen;
Expand Down Expand Up @@ -270,16 +288,6 @@ static bool ipv6_dest_hao(struct sk_buff *skb, int optoff)
}
#endif

static const struct tlvtype_proc tlvprocdestopt_lst[] = {
#if IS_ENABLED(CONFIG_IPV6_MIP6)
{
.type = IPV6_TLV_HAO,
.func = ipv6_dest_hao,
},
#endif
{-1, NULL}
};

static int ipv6_destopt_rcv(struct sk_buff *skb)
{
struct inet6_dev *idev = __in6_dev_get(skb->dev);
Expand Down Expand Up @@ -310,8 +318,7 @@ static int ipv6_destopt_rcv(struct sk_buff *skb)
dstbuf = opt->dst1;
#endif

if (ip6_parse_tlv(tlvprocdestopt_lst, skb,
net->ipv6.sysctl.max_dst_opts_cnt)) {
if (ip6_parse_tlv(false, skb, net->ipv6.sysctl.max_dst_opts_cnt)) {
skb->transport_header += extlen;
opt = IP6CB(skb);
#if IS_ENABLED(CONFIG_IPV6_MIP6)
Expand Down Expand Up @@ -994,22 +1001,6 @@ static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff)
return false;
}

static const struct tlvtype_proc tlvprochopopt_lst[] = {
{
.type = IPV6_TLV_ROUTERALERT,
.func = ipv6_hop_ra,
},
{
.type = IPV6_TLV_JUMBO,
.func = ipv6_hop_jumbo,
},
{
.type = IPV6_TLV_CALIPSO,
.func = ipv6_hop_calipso,
},
{ -1, }
};

int ipv6_parse_hopopts(struct sk_buff *skb)
{
struct inet6_skb_parm *opt = IP6CB(skb);
Expand All @@ -1035,8 +1026,7 @@ int ipv6_parse_hopopts(struct sk_buff *skb)
goto fail_and_free;

opt->flags |= IP6SKB_HOPBYHOP;
if (ip6_parse_tlv(tlvprochopopt_lst, skb,
net->ipv6.sysctl.max_hbh_opts_cnt)) {
if (ip6_parse_tlv(true, skb, net->ipv6.sysctl.max_hbh_opts_cnt)) {
skb->transport_header += extlen;
opt = IP6CB(skb);
opt->nhoff = sizeof(struct ipv6hdr);
Expand Down
Loading