/** * @brief Parse the SACK TCP option * * See RFC6846 page 68 * (and RFC2018 for Selective Acknowledgement option) * * @param context The decompression context * @param data The ROHC data to parse * @param data_len The length of the ROHC data to parse * @param[out] opt_sack The information of SACK option extracted from the packet * @return The number of ROHC bytes parsed, * -1 if packet is malformed */ int d_tcp_sack_parse(const struct rohc_decomp_ctxt *const context, const uint8_t *const data, const size_t data_len, struct d_tcp_opt_sack *const opt_sack) { const uint8_t *remain_data; size_t remain_data_len; uint8_t discriminator; int i; rohc_decomp_debug(context, "parse SACK option"); remain_data = data; remain_data_len = data_len; /* parse discriminator */ if(remain_data_len < 1) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for the discriminator of the TCP SACK " "option: only %zu bytes available while at least 1 byte " "required", remain_data_len); goto error; } discriminator = remain_data[0]; remain_data++; remain_data_len--; if(discriminator > TCP_SACK_BLOCKS_MAX_NR) { rohc_decomp_warn(context, "invalid discriminator value (%d)", discriminator); goto error; } /* parse up to 4 SACK blocks */ for(i = 0; i < discriminator; i++) { const int ret = d_tcp_sack_block(context, remain_data, remain_data_len, &(opt_sack->blocks[i])); if(ret < 0) { rohc_decomp_warn(context, "failed to parse block #%d of SACK " "option", i + 1); goto error; } remain_data += ret; remain_data_len -= ret; rohc_decomp_debug(context, "block #%d of SACK option: start bits = 0x%08x, " "end bits = 0x%08x", i + 1, opt_sack->blocks[i].block_start, opt_sack->blocks[i].block_end); } opt_sack->blocks_nr = discriminator; return (data_len - remain_data_len); error: return -1; }
/** * @brief Parse the LSBs bits of one of the TS echo request/reply fields * * See RFC4996 page 65 * * @param context The decompression context * @param data The data to decode * @param data_len The length of the data to decode * @param[out] ts_field The information of TS option field extracted from packet * @return The number of data bytes parsed, * -1 if data is malformed */ int d_tcp_ts_lsb_parse(const struct rohc_decomp_ctxt *const context, const uint8_t *const data, const size_t data_len, struct rohc_lsb_field32 *const ts_field) { const uint8_t *remain_data; size_t remain_len; remain_data = data; remain_len = data_len; if(remain_len < 1) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for TS LSB: only %zu bytes available " "while at least 1 byte required", remain_len); goto error; } if((remain_data[0] & 0x80) == 0) { /* discriminator '0' */ rohc_decomp_debug(context, "TCP TS option: TS field is 1-byte long"); ts_field->bits = remain_data[0]; ts_field->bits_nr = 7; ts_field->p = ROHC_LSB_SHIFT_TCP_TS_1B; remain_len--; } else if((remain_data[0] & 0x40) == 0) { /* discriminator '10' */ rohc_decomp_debug(context, "TCP TS option: TS field is 2-byte long"); if(remain_len < 2) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for TS LSB: only %zu bytes available " "while at least 2 bytes required", remain_len); goto error; } ts_field->bits = (remain_data[0] & 0x3f) << 8; ts_field->bits |= remain_data[1]; ts_field->bits_nr = 14; ts_field->p = ROHC_LSB_SHIFT_TCP_TS_2B; remain_len -= 2; } else if((remain_data[0] & 0x20) == 0) { /* discriminator '110' */ rohc_decomp_debug(context, "TCP TS option: TS field is 3-byte long"); if(remain_len < 3) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for TS LSB: only %zu bytes available " "while at least 3 bytes required", remain_len); goto error; } ts_field->bits = (remain_data[0] & 0x1f) << 16; ts_field->bits |= remain_data[1] << 8; ts_field->bits |= remain_data[2]; ts_field->bits_nr = 21; ts_field->p = ROHC_LSB_SHIFT_TCP_TS_3B; remain_len -= 3; } else { /* discriminator '111' */ rohc_decomp_debug(context, "TCP TS option: TS field is 4-byte long"); if(remain_len < 4) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for TS LSB: only %zu bytes available " "while at least 4 bytes required", remain_len); goto error; } ts_field->bits = (remain_data[0] & 0x1f) << 24; ts_field->bits |= remain_data[1] << 16; ts_field->bits |= remain_data[2] << 8; ts_field->bits |= remain_data[3]; ts_field->bits_nr = 29; ts_field->p = ROHC_LSB_SHIFT_TCP_TS_4B; remain_len -= 4; } return (data_len - remain_len); error: return -1; }
/** * @brief Parse a SACK field of a SACK block of the TCP SACK option * * See RFC6846 page 67 * (and RFC2018 for Selective Acknowledgement option) * * @param context The decompression context * @param data The ROHC data to parse * @param data_len The length of the ROHC data to parse * @param[out] sack_field The uncompressed SACK field * @return The number of data bytes parsed, * -1 if data is malformed */ static int d_tcp_sack_pure_lsb(const struct rohc_decomp_ctxt *const context, const uint8_t *const data, const size_t data_len, uint32_t *const sack_field) { const uint8_t *remain_data = data; size_t remain_len = data_len; if(remain_len < 2) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for the discriminator of the TCP pure " "field: only %zu bytes available while at least 2 bytes " "required", remain_len); goto error; } if((remain_data[0] & 0x80) == 0) { /* discriminator '0' */ rohc_decomp_debug(context, "SACK block is 2-byte long"); (*sack_field) = *(remain_data++) & 0x7f; (*sack_field) <<= 8; (*sack_field) |= *(remain_data++); remain_len -= 2; } else if((remain_data[0] & 0x40) == 0) { /* discriminator '10' */ rohc_decomp_debug(context, "SACK block is 3-byte long"); if(remain_len < 3) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for the discriminator of the TCP pure " "field: only %zu bytes available while at least 3 bytes " "required", remain_len); goto error; } (*sack_field) = *(remain_data++) & 0x3f; (*sack_field) <<= 8; (*sack_field) |= *(remain_data++); (*sack_field) <<= 8; (*sack_field) |= *(remain_data++); remain_len -= 3; } else if((remain_data[0] & 0x20) == 0) { /* discriminator '110' */ rohc_decomp_debug(context, "SACK block is 4-byte long"); if(remain_len < 4) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for the discriminator of the TCP pure " "field: only %zu bytes available while at least 4 bytes " "required", remain_len); goto error; } (*sack_field) = *(remain_data++) & 0x1f; (*sack_field) <<= 8; (*sack_field) |= *(remain_data++); (*sack_field) <<= 8; (*sack_field) |= *(remain_data++); (*sack_field) <<= 8; (*sack_field) |= *(remain_data++); remain_len -= 4; } else if(remain_data[0] == 0xff) { /* discriminator '11111111' */ rohc_decomp_debug(context, "SACK block is 5-byte long"); if(remain_len < 5) { rohc_warning(context->decompressor, ROHC_TRACE_DECOMP, ROHC_PROFILE_TCP, "packet too short for the discriminator of the TCP pure " "field: only %zu bytes available while at least 5 bytes " "required", remain_len); goto error; } remain_data++; /* skip discriminator */ (*sack_field) = *(remain_data++); (*sack_field) <<= 8; (*sack_field) |= *(remain_data++); (*sack_field) <<= 8; (*sack_field) |= *(remain_data++); (*sack_field) <<= 8; (*sack_field) |= *(remain_data++); remain_len -= 5; } else { rohc_decomp_warn(context, "malformed SACK block: unexpected " "discriminator 0x%02x", remain_data[0]); goto error; } return (data_len - remain_len); error: return -1; }
/** * @brief Parse a network packet * * @param[out] packet The parsed packet * @param data The data to parse * @param trace_cb The function to call for printing traces * @param trace_cb_priv An optional private context, may be NULL * @param trace_entity The entity that emits the traces * @return true if the packet was successfully parsed, * false if a problem occurred (a malformed packet is * not considered as an error) */ bool net_pkt_parse(struct net_pkt *const packet, const struct rohc_buf data, rohc_trace_callback2_t trace_cb, void *const trace_cb_priv, rohc_trace_entity_t trace_entity) { packet->data = rohc_buf_data(data); packet->len = data.len; packet->ip_hdr_nr = 0; packet->key = 0; /* traces */ packet->trace_callback = trace_cb; packet->trace_callback_priv = trace_cb_priv; /* create the outer IP packet from raw data */ if(!ip_create(&packet->outer_ip, rohc_buf_data(data), data.len)) { rohc_warning(packet, trace_entity, ROHC_PROFILE_GENERAL, "cannot create the outer IP header"); goto error; } packet->ip_hdr_nr++; rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL, "outer IP header: %u bytes", ip_get_totlen(&packet->outer_ip)); rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL, "outer IP header: version %d", ip_get_version(&packet->outer_ip)); if(packet->outer_ip.nh.data != NULL) { rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL, "outer IP header: next header is of type %d", packet->outer_ip.nh.proto); if(packet->outer_ip.nl.data != NULL) { rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL, "outer IP header: next layer is of type %d", packet->outer_ip.nl.proto); } } /* build the hash key for the packet */ if(ip_get_version(&packet->outer_ip) == IPV4) { packet->key ^= ipv4_get_saddr(&packet->outer_ip); packet->key ^= ipv4_get_daddr(&packet->outer_ip); } else if(ip_get_version(&packet->outer_ip) == IPV6) { const struct ipv6_addr *const saddr = ipv6_get_saddr(&packet->outer_ip); const struct ipv6_addr *const daddr = ipv6_get_daddr(&packet->outer_ip); packet->key ^= saddr->addr.u32[0]; packet->key ^= saddr->addr.u32[1]; packet->key ^= saddr->addr.u32[2]; packet->key ^= saddr->addr.u32[3]; packet->key ^= daddr->addr.u32[0]; packet->key ^= daddr->addr.u32[1]; packet->key ^= daddr->addr.u32[2]; packet->key ^= daddr->addr.u32[3]; } /* get the transport protocol */ packet->transport = &packet->outer_ip.nl; /* is there any inner IP header? */ if(rohc_is_tunneling(packet->transport->proto)) { /* create the second IP header */ if(!ip_get_inner_packet(&packet->outer_ip, &packet->inner_ip)) { rohc_warning(packet, trace_entity, ROHC_PROFILE_GENERAL, "cannot create the inner IP header"); goto error; } packet->ip_hdr_nr++; rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL, "inner IP header: %u bytes", ip_get_totlen(&packet->inner_ip)); rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL, "inner IP header: version %d", ip_get_version(&packet->inner_ip)); if(packet->inner_ip.nh.data != NULL) { rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL, "inner IP header: next header is of type %d", packet->inner_ip.nh.proto); if(packet->inner_ip.nl.data != NULL) { rohc_debug(packet, trace_entity, ROHC_PROFILE_GENERAL, "inner IP header: next layer is of type %d", packet->inner_ip.nl.proto); } } /* get the transport protocol */ packet->transport = &packet->inner_ip.nl; } return true; error: return false; }