net: 6lo: Fix source address uncompression

When src and dst addresses are compressed based on context
information, uncompression method should verify CID bit,
SAC and DAC bits and context ID's. But it has missed some
cases which resulted in invalid uncompressed IPv6 header.

e.g. CID is set, SAC is 0 and DAC is 1 and context id's provided.
Uncompression method assumed that src address is compressed based
on context information but it is not.

Signed-off-by: Ravi kumar Veeramally <ravikumar.veeramally@linux.intel.com>
This commit is contained in:
Ravi kumar Veeramally 2017-06-05 15:58:16 +03:00 committed by Anas Nashif
commit 7a01988c64
3 changed files with 57 additions and 60 deletions

View file

@ -862,11 +862,6 @@ static inline u8_t uncompress_sa(struct net_pkt *pkt,
struct net_ipv6_hdr *ipv6,
u8_t offset)
{
if (CIPHC[1] & NET_6LO_IPHC_SAC_1) {
NET_DBG("SAC_1");
NET_DBG("SAM_00 unspecified address");
return offset;
}
NET_DBG("SAC_0");
@ -913,16 +908,11 @@ static inline u8_t uncompress_sa_ctx(struct net_pkt *pkt,
u8_t offset,
struct net_6lo_context *ctx)
{
if (!ctx) {
return uncompress_sa(pkt, ipv6, offset);
}
NET_DBG("SAC_1");
switch (CIPHC[1] & NET_6LO_IPHC_SAM_11) {
case NET_6LO_IPHC_SAM_00:
NET_DBG("SAM_00 full src addr inlined");
memcpy(ipv6->src.s6_addr, &CIPHC[offset], 16);
offset += 16;
NET_DBG("SAM_00 unspecified address");
break;
case NET_6LO_IPHC_SAM_01:
NET_DBG("SAM_01 last 64 bits are inlined");
@ -978,8 +968,6 @@ static inline u8_t uncompress_da_mcast(struct net_pkt *pkt,
NET_DBG("Dst is multicast");
if (CIPHC[1] & NET_6LO_IPHC_DAC_1) {
/* TODO: DAM00 Unicast-Prefix-based IPv6 Multicast Addresses */
/* Reserved DAM_01, DAM_10, DAM_11 */
NET_WARN("Unsupported DAM options");
return 0;
}
@ -1033,17 +1021,12 @@ static inline u8_t uncompress_da(struct net_pkt *pkt,
struct net_ipv6_hdr *ipv6,
u8_t offset)
{
NET_DBG("DAC_0");
if (CIPHC[1] & NET_6LO_IPHC_M_1) {
return uncompress_da_mcast(pkt, ipv6, offset);
}
if (CIPHC[1] & NET_6LO_IPHC_DAC_1) {
/* Invalid case: ctx doesn't exists , but DAC is 1*/
return 0;
}
NET_DBG("DAC_0");
switch (CIPHC[1] & NET_6LO_IPHC_DAM_11) {
case NET_6LO_IPHC_DAM_00:
NET_DBG("DAM_00 full dst addr inlined");
@ -1087,21 +1070,12 @@ static inline u8_t uncompress_da_ctx(struct net_pkt *pkt,
u8_t offset,
struct net_6lo_context *ctx)
{
if (!ctx) {
return uncompress_da(pkt, ipv6, offset);
}
NET_DBG("DAC_1");
if (CIPHC[1] & NET_6LO_IPHC_M_1) {
return uncompress_da_mcast(pkt, ipv6, offset);
}
if (!(CIPHC[1] & NET_6LO_IPHC_DAC_1)) {
/* Invalid case: ctx exists but DAC is 0. */
return 0;
}
NET_DBG("DAC_1");
switch (CIPHC[1] & NET_6LO_IPHC_DAM_11) {
case NET_6LO_IPHC_DAM_01:
NET_DBG("DAM_01 last 64 bits are inlined");
@ -1210,7 +1184,7 @@ static inline u8_t uncompress_nh_udp(struct net_pkt *pkt,
#if defined(CONFIG_NET_6LO_CONTEXT)
/* Helper function to uncompress src and dst contexts */
static inline bool uncompress_cid(struct net_pkt *pkt,
static inline void uncompress_cid(struct net_pkt *pkt,
struct net_6lo_context **src,
struct net_6lo_context **dst)
{
@ -1230,17 +1204,6 @@ static inline bool uncompress_cid(struct net_pkt *pkt,
if (!(*dst)) {
NET_DBG("Unknown dst cid %d", cid);
}
/* If CID flag set and src or dst context not available means,
* either we don't have context information or we received
* corrupted packet.
*/
if (!*src && !*dst) {
NET_ERR("Context information does not exist in cache");
return false;
}
return true;
}
#endif
@ -1259,10 +1222,7 @@ static inline bool uncompress_IPHC_header(struct net_pkt *pkt)
if (CIPHC[1] & NET_6LO_IPHC_CID_1) {
#if defined(CONFIG_NET_6LO_CONTEXT)
if (!uncompress_cid(pkt, &src, &dst)) {
return false;
}
uncompress_cid(pkt, &src, &dst);
offset++;
#else
NET_WARN("Context based uncompression not enabled");
@ -1298,9 +1258,15 @@ static inline bool uncompress_IPHC_header(struct net_pkt *pkt)
/* Uncompress Source Address */
#if defined(CONFIG_NET_6LO_CONTEXT)
offset = uncompress_sa_ctx(pkt, ipv6, offset, src);
if (!offset) {
goto fail;
if (CIPHC[1] & NET_6LO_IPHC_SAC_1) {
if (!src) {
NET_ERR("SAC is set but src context doesn't exists");
goto fail;
}
offset = uncompress_sa_ctx(pkt, ipv6, offset, src);
} else {
offset = uncompress_sa(pkt, ipv6, offset);
}
#else
offset = uncompress_sa(pkt, ipv6, offset);
@ -1308,15 +1274,26 @@ static inline bool uncompress_IPHC_header(struct net_pkt *pkt)
/* Uncompress Destination Address */
#if defined(CONFIG_NET_6LO_CONTEXT)
offset = uncompress_da_ctx(pkt, ipv6, offset, dst);
if (!offset) {
goto fail;
if (CIPHC[1] & NET_6LO_IPHC_DAC_1) {
if (CIPHC[1] & NET_6LO_IPHC_M_1) {
/* TODO: DAM00 Unicast-Prefix-based IPv6 Multicast
* Addresses. DAM_01, DAM_10 and DAM_11 are reserved.
*/
NET_ERR("DAC_1 and M_1 is not supported");
goto fail;
}
if (!dst) {
NET_ERR("DAC is set but dst context doesn't exists");
goto fail;
}
offset = uncompress_da_ctx(pkt, ipv6, offset, dst);
} else {
offset = uncompress_da(pkt, ipv6, offset);
}
#else
offset = uncompress_da(pkt, ipv6, offset);
if (!offset) {
goto fail;
}
#endif
net_buf_add(frag, NET_IPV6H_LEN);

View file

@ -456,7 +456,7 @@ static struct net_6lo_data test_data_4 = {
.ipv6.len = { 0x00, 0x00 },
.ipv6.nexthdr = IPPROTO_UDP,
.ipv6.hop_limit = 0xff,
.ipv6.src = src_sac1_sam00,
.ipv6.src = src_sam00,
.ipv6.dst = dst_m1_dam00,
.nh.udp.src_port = htons(udp_src_port_16bit),
.nh.udp.dst_port = htons(udp_dst_port_16bit),
@ -795,6 +795,25 @@ static struct net_6lo_data test_data_22 = {
.small = true,
.iphc = true
};
static struct net_6lo_data test_data_23 = {
.ipv6.vtc = 0x60,
.ipv6.tcflow = 0x20,
.ipv6.flow = 0x3412,
.ipv6.len = { 0x00, 0x00 },
.ipv6.nexthdr = IPPROTO_UDP,
.ipv6.hop_limit = 0xff,
.ipv6.src = src_sam00,
.ipv6.dst = dst_dac1_dam01,
.nh.udp.src_port = htons(udp_src_port_8bit_y),
.nh.udp.dst_port = htons(udp_dst_port_8bit),
.nh.udp.len = 0x00,
.nh.udp.chksum = 0x00,
.nh_udp = true,
.nh_icmp = false,
.small = false,
.iphc = true
};
#endif
static int test_6lo(struct net_6lo_data *data)
@ -856,7 +875,7 @@ static const struct {
{ "test_6lo_sam00_dam00", &test_data_1},
{ "test_6lo_sam01_dam01", &test_data_2},
{ "test_6lo_sam10_dam10", &test_data_3},
{ "test_6lo_sac1_sam00_m1_dam00", &test_data_4},
{ "test_6lo_sam00_m1_dam00", &test_data_4},
{ "test_6lo_sam01_m1_dam01", &test_data_5},
{ "test_6lo_sam10_m1_dam10", &test_data_6},
{ "test_6lo_sam10_m1_dam10_no_udp", &test_data_7},
@ -876,6 +895,7 @@ static const struct {
{ "test_6lo_sac1_sam01_m1_dam01", &test_data_20},
{ "test_6lo_sac1_sam10_m1_dam10", &test_data_21},
{ "test_6lo_sac1_sam11_m1_dam10", &test_data_22},
{ "test_6lo_sac0_sam00_dac1_dam01", &test_data_23},
#endif
};

View file

@ -337,7 +337,7 @@ static struct net_fragment_data test_data_4 = {
.ipv6.len = { 0x00, 0x00 },
.ipv6.nexthdr = IPPROTO_UDP,
.ipv6.hop_limit = 0xff,
.ipv6.src = src_sac1_sam00,
.ipv6.src = src_sam00,
.ipv6.dst = dst_m1_dam00,
.udp.src_port = htons(udp_src_port_16bit),
.udp.dst_port = htons(udp_dst_port_16bit),
@ -506,7 +506,7 @@ static const struct {
{ "test_fragment_sam00_dam00", &test_data_1},
{ "test_fragment_sam01_dam01", &test_data_2},
{ "test_fragment_sam10_dam10", &test_data_3},
{ "test_fragment_sac1_sam00_m1_dam00", &test_data_4},
{ "test_fragment_sam00_m1_dam00", &test_data_4},
{ "test_fragment_sam01_m1_dam01", &test_data_5},
{ "test_fragment_sam10_m1_dam10", &test_data_6},
{ "test_fragment_ipv6_dispatch_small", &test_data_7},