Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
iphc_compress.c
00001 /* 00002 * Copyright (c) 2014-2017, Arm Limited and affiliates. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * 00005 * Licensed under the Apache License, Version 2.0 (the "License"); 00006 * you may not use this file except in compliance with the License. 00007 * You may obtain a copy of the License at 00008 * 00009 * http://www.apache.org/licenses/LICENSE-2.0 00010 * 00011 * Unless required by applicable law or agreed to in writing, software 00012 * distributed under the License is distributed on an "AS IS" BASIS, 00013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 * See the License for the specific language governing permissions and 00015 * limitations under the License. 00016 */ 00017 #include "nsconfig.h" 00018 #include "ns_list.h" 00019 #include "common_functions.h" 00020 #include "ns_trace.h" 00021 #include "nsdynmemLIB.h" 00022 #include <string.h> 00023 #include "NWK_INTERFACE/Include/protocol.h" 00024 #include "Common_Protocols/ipv6_constants.h" 00025 #include "6LoWPAN/IPHC_Decode/cipv6.h" 00026 00027 #define TRACE_GROUP "iphc" 00028 00029 typedef struct iphc_compress_state { 00030 const lowpan_context_list_t * const context_list; 00031 const uint8_t *in; 00032 uint8_t *out; 00033 uint16_t len; 00034 uint16_t out_space; 00035 uint16_t consumed; 00036 uint16_t produced; 00037 const uint8_t *outer_src_iid; 00038 const uint8_t *outer_dst_iid; 00039 const bool stable_only; 00040 } iphc_compress_state_t; 00041 00042 static bool compress_nh(uint8_t nh, iphc_compress_state_t *restrict cs); 00043 00044 static inline bool context_ok_for_compression(const lowpan_context_t *ctx, bool stable_only) 00045 { 00046 return ctx->lifetime && ctx->compression && (!stable_only || ctx->stable); 00047 } 00048 00049 /* Using a specified context, what's the best possible compression of addr? */ 00050 static uint_fast8_t addr_bytes_needed(const uint8_t *addr, const uint8_t *outer_iid, const uint8_t *ctx_prefix, uint_fast8_t ctx_len) 00051 { 00052 /* Quick test: context always gets priority, so all of context must match */ 00053 /* This handles intrusions into IID space, so don't have to recheck this below */ 00054 if (!bitsequal(addr, ctx_prefix, ctx_len)) { 00055 return 16; 00056 } 00057 00058 /* Okay, potential match, but getting next bit optimal is more complex. */ 00059 /* Try each of 3 possible cases in turn */ 00060 uint8_t template[16]; 00061 00062 /* 0-bit case: 64 bits of IID from outer header */ 00063 /* Template contains 0s, then outer IID, then context on top */ 00064 if (ctx_len < 64) { 00065 memset(template, 0, 8); 00066 } 00067 if (ctx_len < 128) { 00068 memcpy(template + 8, outer_iid, 8); 00069 } 00070 bitcopy(template, ctx_prefix, ctx_len); 00071 00072 if (addr_ipv6_equal(template, addr)) { 00073 return 0; 00074 } 00075 00076 /* 16-bit case: need to match top 14 bytes. Respell top 6 bytes of IID */ 00077 /* from last test to contain 0000:00ff:fe00, unless they're fully */ 00078 /* covered by context, in which case template already hold the correct */ 00079 /* context bytes */ 00080 if (ctx_len < 112) { 00081 memcpy(template + 8, ADDR_SHORT_ADR_SUFFIC, 6); 00082 if (ctx_len > 64) { 00083 bitcopy(template + 8, ctx_prefix + 8, ctx_len - 64); 00084 } 00085 } 00086 if (memcmp(template, addr, 14) == 0) { 00087 return 2; 00088 } 00089 00090 /* 64-bit case: only need to match top 8 bytes */ 00091 if (memcmp(template, addr, 8) == 0) { 00092 return 8; 00093 } 00094 00095 /* Had a matching context, but didn't match enough. Example: 00096 * Context = 2002:db4::/32, Addr = 2002:db4:1::1 00097 * Matches all 32 bits of context length, but not enough to compress 64-bit 00098 */ 00099 return 16; 00100 } 00101 00102 static uint8_t compress_mc_addr(const lowpan_context_list_t *context_list, const uint8_t *addr, uint8_t *cmp_addr_out, uint8_t *context, uint8_t *mode, bool stable_only) 00103 { 00104 *mode |= HC_MULTICAST_COMP; 00105 if (memcmp(addr, ADDR_LINK_LOCAL_ALL_NODES, 15) == 0) { 00106 // ff02:0000:0000:0000:0000:0000:0000:00XX 00107 cmp_addr_out[0] = addr[15]; 00108 *mode |= HC_8BIT_MULTICAST; 00109 return 1; 00110 } 00111 if (memcmp(addr + 2, ADDR_LINK_LOCAL_ALL_NODES + 2, 11) == 0) { 00112 // ffXX:0000:0000:0000:0000:0000:00XX:XXXX 00113 cmp_addr_out[0] = addr[1]; 00114 cmp_addr_out[1] = addr[13]; 00115 cmp_addr_out[2] = addr[14]; 00116 cmp_addr_out[3] = addr[15]; 00117 *mode |= HC_32BIT_MULTICAST; 00118 return 4; 00119 } 00120 if (memcmp(addr + 2, ADDR_LINK_LOCAL_ALL_NODES + 2, 9) == 0) { 00121 // ffXX:0000:0000:0000:0000:00XX:XXXX:XXXX 00122 cmp_addr_out[0] = addr[1]; 00123 memcpy(cmp_addr_out + 1, addr + 11, 5); 00124 *mode |= HC_48BIT_MULTICAST; 00125 return 6; 00126 } 00127 /* Looking for addresses of the form ffxx:xxLL:PPPP:PPPP:PPPP:PPPP:xxxx:xxxx */ 00128 /* Context info is padded with zeros, so the 8-byte memcmp is okay for short contexts. */ 00129 /* RFCs are ambiguous about how this should work if prefix length is > 64 bits, */ 00130 /* so don't attempt compression against long contexts. */ 00131 ns_list_foreach(lowpan_context_t, ctx, context_list) { 00132 if (context_ok_for_compression(ctx, stable_only) && 00133 ctx->length <= 64 && 00134 addr[3] == ctx->length && memcmp(addr + 4, ctx->prefix, 8) == 0) { 00135 cmp_addr_out[0] = addr[1]; 00136 cmp_addr_out[1] = addr[2]; 00137 memcpy(cmp_addr_out + 2, addr + 12, 4); 00138 *context |= ctx->cid; 00139 *mode |= HC_48BIT_CONTEXT_MULTICAST; 00140 return 6; 00141 } 00142 } 00143 00144 memcpy(cmp_addr_out, addr, 16); 00145 *mode |= HC_128BIT_MULTICAST; 00146 return 16; 00147 } 00148 00149 static uint8_t compress_addr(const lowpan_context_list_t *context_list, const uint8_t *addr, bool is_dst, const uint8_t *outer_iid, uint8_t *cmp_addr_out, uint8_t *context, uint8_t *mode, bool stable_only) 00150 { 00151 if (is_dst && addr[0] == 0xff) { 00152 return compress_mc_addr(context_list, addr, cmp_addr_out, context, mode, stable_only); 00153 } 00154 00155 uint_fast8_t best_bytes = addr_bytes_needed(addr, outer_iid, ADDR_LINK_LOCAL_PREFIX, 64); 00156 lowpan_context_t *best_ctx = NULL; 00157 bool checked_ctx0 = false; 00158 00159 if (best_bytes > 0) { 00160 ns_list_foreach(lowpan_context_t, ctx, context_list) { 00161 if (!context_ok_for_compression(ctx, stable_only)) { 00162 continue; 00163 } 00164 00165 uint_fast8_t bytes = addr_bytes_needed(addr, outer_iid, ctx->prefix, ctx->length); 00166 if (ctx->cid == 0) { 00167 checked_ctx0 = true; 00168 } 00169 /* This context is better if: 00170 * a) it means fewer inline bytes, or 00171 * b) it needs the same inline bytes and might avoid a CID extension 00172 */ 00173 if (bytes < best_bytes || (bytes == best_bytes && ctx->cid == 0 && best_ctx && best_ctx->cid != 0)) { 00174 best_ctx = ctx; 00175 best_bytes = bytes; 00176 /* Don't need to check further if we've reached 0 bytes, and we've considered context 0 */ 00177 if (best_bytes == 0 && checked_ctx0) { 00178 break; 00179 } 00180 } 00181 } 00182 } 00183 00184 /* If not found a 0-byte match, one more (unlikely) possibility for source - special case for "unspecified" */ 00185 if (best_bytes > 0 && !is_dst && addr_is_ipv6_unspecified(addr)) { 00186 *mode |= HC_SRCADR_COMP | HC_SRC_ADR_128_BIT; 00187 return 0; 00188 } 00189 00190 uint8_t mode_bits; 00191 uint8_t context_bits; 00192 if (best_ctx) { 00193 context_bits = best_ctx->cid; 00194 mode_bits = HC_DSTADR_COMP; 00195 } else { 00196 context_bits = 0; 00197 mode_bits = 0; 00198 } 00199 00200 switch (best_bytes) { 00201 default: 00202 mode_bits |= HC_DST_ADR_128_BIT; 00203 break; 00204 case 8: 00205 mode_bits |= HC_DST_ADR_64_BIT; 00206 break; 00207 case 2: 00208 mode_bits |= HC_DST_ADR_16_BIT; 00209 break; 00210 case 0: 00211 mode_bits |= HC_DST_ADR_FROM_MAC; 00212 break; 00213 } 00214 00215 /* Convert from IPHC DST bits to SRC bits */ 00216 if (!is_dst) { 00217 mode_bits <<= 4; 00218 context_bits <<= 4; 00219 } 00220 00221 *mode |= mode_bits; 00222 *context |= context_bits; 00223 00224 memcpy(cmp_addr_out, addr + (16 - best_bytes), best_bytes); 00225 00226 return best_bytes; 00227 } 00228 00229 static bool compress_udp(iphc_compress_state_t *restrict cs) 00230 { 00231 if (cs->len < 8) { 00232 return false; 00233 } 00234 00235 /* UDP length should be set to payload length - if it's not, we can't compress it */ 00236 uint16_t udp_len = common_read_16_bit(cs->in + 4); 00237 if (udp_len != cs->len) { 00238 return false; 00239 } 00240 00241 uint16_t src_port = common_read_16_bit(cs->in + 0); 00242 uint16_t dst_port = common_read_16_bit(cs->in + 2); 00243 00244 uint8_t *ptr = cs->out; 00245 if ((src_port & 0xfff0) == 0xf0b0 && 00246 (dst_port & 0xfff0) == 0xf0b0) { 00247 if (cs->out_space < 4) { 00248 return false; 00249 } 00250 *ptr++ = NHC_UDP | NHC_UDP_PORT_COMPRESS_BOTH; 00251 *ptr++ = (src_port & 0xF) << 4 | 00252 (dst_port & 0xF); 00253 } else if ((src_port & 0xff00) == 0xf000) { 00254 if (cs->out_space < 7) { 00255 return false; 00256 } 00257 *ptr++ = NHC_UDP | NHC_UDP_PORT_COMPRESS_SRC; 00258 *ptr++ = src_port & 0xff; 00259 ptr = common_write_16_bit(dst_port, ptr); 00260 } else if ((dst_port & 0xff00) == 0xf000) { 00261 if (cs->out_space < 7) { 00262 return false; 00263 } 00264 *ptr++ = NHC_UDP | NHC_UDP_PORT_COMPRESS_DST; 00265 ptr = common_write_16_bit(src_port, ptr); 00266 *ptr++ = dst_port & 0xff; 00267 } else { 00268 if (cs->out_space < 8) { 00269 return false; 00270 } 00271 *ptr++ = NHC_UDP | NHC_UDP_PORT_COMPRESS_NONE; 00272 ptr = common_write_16_bit(src_port, ptr); 00273 ptr = common_write_16_bit(dst_port, ptr); 00274 } 00275 00276 /* Checksum */ 00277 *ptr++ = cs->in[6]; 00278 *ptr++ = cs->in[7]; 00279 uint_fast8_t outlen = ptr - cs->out; 00280 00281 cs->consumed += 8; 00282 cs->in += 8; 00283 cs->len -= 8; 00284 cs->out_space -= outlen; 00285 cs->out += outlen; 00286 cs->produced += outlen; 00287 00288 return true; 00289 } 00290 00291 00292 static bool compress_exthdr(uint8_t nhc, iphc_compress_state_t *restrict cs) 00293 { 00294 if (cs->len < 8) { 00295 return false; 00296 } 00297 00298 const uint8_t *in = cs->in; 00299 uint8_t nh = in[0]; 00300 uint16_t hdrlen; 00301 00302 if (nhc == NHC_EXT_FRAG) { 00303 /* For fragment header, seems sensible to only handle first fragment; 00304 * "Next header" field doesn't describe following data otherwise. 00305 * Could still "compress" this header in all cases, but no point if we don't 00306 * have following headers to compress - it takes 8 bytes either way. 00307 */ 00308 uint16_t offset = common_read_16_bit(in + 2) & 0xFFF8; 00309 if (offset != 0) { 00310 return false; 00311 } 00312 00313 /* Second byte is reserved; it's not a length byte */ 00314 hdrlen = 8; 00315 } else { 00316 hdrlen = (in[1] + 1) * 8; 00317 } 00318 00319 if (hdrlen > cs->len || hdrlen >= 256) { 00320 return false; 00321 } 00322 00323 /* If Options are well-formed, parse and remove final option if it's padding */ 00324 uint8_t hc_bytes = hdrlen; 00325 if (nhc == NHC_EXT_DEST_OPT || nhc == NHC_EXT_HOP_BY_HOP) { 00326 const uint8_t *opt = in + 2, *lastopt = opt; 00327 uint8_t optrem = hdrlen - 2; 00328 00329 while (optrem) { 00330 lastopt = opt; 00331 if (opt[0] == IPV6_OPTION_PAD1) { 00332 opt++; 00333 optrem--; 00334 continue; 00335 } 00336 if (optrem < 2 || optrem < 2 + opt[1]) { 00337 lastopt = NULL; 00338 break; 00339 } 00340 optrem -= 2 + opt[1]; 00341 opt += 2 + opt[1]; 00342 } 00343 if (lastopt && (lastopt[0] == IPV6_OPTION_PAD1 || lastopt[0] == IPV6_OPTION_PADN)) { 00344 hc_bytes = lastopt - in; 00345 } 00346 } 00347 00348 /* Include one for "next header" - we will either need this ourselves, or 00349 * the next hdr will*/ 00350 if (cs->out_space < hc_bytes + 1) { 00351 return false; 00352 } 00353 00354 uint8_t *out = cs->out; 00355 00356 cs->in += hdrlen; 00357 cs->len -= hdrlen; 00358 cs->consumed += hdrlen; 00359 cs->out += hc_bytes; 00360 cs->out_space -= hc_bytes; 00361 cs->produced += hc_bytes; 00362 00363 out[0] = nhc; 00364 if (compress_nh(nh, cs)) { 00365 out[0] |= NHC_EXT_NH; 00366 } 00367 00368 uint8_t *ptr = out + 1; 00369 if (!(out[0] & NHC_EXT_NH)) { 00370 *ptr++ = nh; 00371 cs->out++; 00372 cs->out_space--; 00373 cs->produced++; 00374 } 00375 if (nhc == NHC_EXT_FRAG) { 00376 *ptr++ = in[1]; 00377 } else { 00378 *ptr++ = hc_bytes - 2; 00379 } 00380 memcpy(ptr, in + 2, hc_bytes - 2); 00381 return true; 00382 } 00383 00384 static bool compress_ipv6(iphc_compress_state_t *restrict cs, bool from_nhc) 00385 { 00386 const uint8_t *const in = cs->in; 00387 uint8_t *const out = cs->out; 00388 00389 /* Need at least 2 plus 1 for next header field or following NHC byte */ 00390 /* plus another 1 if coming from NHC (for NHC_EXT_IPV6 byte) */ 00391 if (cs->out_space < from_nhc + 3) { 00392 return false; 00393 } 00394 00395 if (cs->len < 40 || (in[0] & 0xF0) != 0x60) { 00396 tr_debug("Not IPv6"); 00397 return false; 00398 } 00399 uint8_t iphc[2] = { LOWPAN_DISPATCH_IPHC, 0 }; 00400 uint_fast8_t iphc_bytes = from_nhc + 2; 00401 00402 /* Payload length field must match, or we can't compress */ 00403 if (common_read_16_bit(in + 4) != cs->len - 40) { 00404 return false; 00405 } 00406 00407 /* Compress addresses, get context byte */ 00408 uint8_t cid = 0; 00409 uint8_t cmp_src[16], cmp_dst[16], cmp_src_len, cmp_dst_len; 00410 cmp_src_len = compress_addr(cs->context_list, in + 8, false, cs->outer_src_iid, cmp_src, &cid, &iphc[1], cs->stable_only); 00411 cmp_dst_len = compress_addr(cs->context_list, in + 24, true, cs->outer_dst_iid, cmp_dst, &cid, &iphc[1], cs->stable_only); 00412 iphc_bytes += cmp_src_len + cmp_dst_len; 00413 if (cid != 0) { 00414 iphc_bytes += 1; 00415 iphc[1] |= HC_CIDE_COMP; 00416 } 00417 00418 /* Compress Hop Limit */ 00419 switch (cs->in[7]) { 00420 case 255: 00421 iphc[0] |= HC_HOP_LIMIT_255; 00422 break; 00423 case 64: 00424 iphc[0] |= HC_HOP_LIMIT_64; 00425 break; 00426 case 1: 00427 iphc[0] |= HC_HOP_LIMIT_1; 00428 break; 00429 default: 00430 iphc[0] |= HC_HOP_LIMIT_CARRIED_IN_LINE; 00431 iphc_bytes += 1; 00432 break; 00433 } 00434 00435 uint8_t ecn = (in[1] & 0x30) << 2; 00436 uint8_t dscp = (in[0] & 0x0F) << 2 | (in[1] & 0xC0) >> 6; 00437 uint_fast24_t flow = common_read_24_bit(in + 1) & 0xFFFFF; 00438 00439 if (flow == 0 && ecn == 0 && dscp == 0) { 00440 iphc[0] |= HC_TF_ELIDED; 00441 } else if (flow == 0) { 00442 iphc[0] |= HC_TF_ECN_DSCP; 00443 iphc_bytes += 1; 00444 } else if (dscp == 0) { 00445 iphc[0] |= HC_TF_ECN_FLOW_LABEL; 00446 flow |= (uint_fast24_t) ecn << 16; 00447 iphc_bytes += 3; 00448 } else { 00449 iphc[0] |= HC_TF_ECN_DSCP_FLOW_LABEL; 00450 iphc_bytes += 4; 00451 } 00452 00453 /* Include one for "next header" - we will either need this ourselves, or 00454 * the next H will*/ 00455 if (cs->out_space < iphc_bytes + 1) { 00456 return false; 00457 } 00458 00459 /* Update state for next header */ 00460 cs->in += 40; 00461 cs->len -= 40; 00462 cs->consumed += 40; 00463 00464 cs->out += iphc_bytes; 00465 cs->out_space -= iphc_bytes; 00466 cs->produced += iphc_bytes; 00467 00468 cs->outer_src_iid = in + 16; 00469 cs->outer_dst_iid = in + 32; 00470 00471 /* Check if next header can be compressed - potentially recursing */ 00472 if (compress_nh(in[6], cs)) { 00473 iphc[0] |= HC_NEXT_HEADER_MASK; 00474 } else { 00475 /* We produce one more byte for Next Header */ 00476 iphc_bytes++; 00477 cs->out++; 00478 cs->out_space--; 00479 cs->produced++; 00480 } 00481 00482 uint8_t *ptr = out; 00483 if (from_nhc) { 00484 *ptr++ = NHC_EXT_IPV6; 00485 } 00486 *ptr++ = iphc[0]; 00487 *ptr++ = iphc[1]; 00488 if (cid != 0) { 00489 *ptr++ = cid; 00490 } 00491 00492 if ((iphc[0] & HC_TF_MASK) == HC_TF_ECN_DSCP_FLOW_LABEL || (iphc[0] & HC_TF_MASK) == HC_TF_ECN_DSCP) { 00493 *ptr++ = (ecn | dscp); 00494 } 00495 if ((iphc[0] & HC_TF_MASK) == HC_TF_ECN_DSCP_FLOW_LABEL || (iphc[0] & HC_TF_MASK) == HC_TF_ECN_FLOW_LABEL) { 00496 ptr = common_write_24_bit(flow, ptr); // "flow" includes ecn in 3-byte case 00497 } 00498 00499 if (!(iphc[0] & HC_NEXT_HEADER_MASK)) { 00500 *ptr++ = in[6]; 00501 } 00502 00503 if ((iphc[0] & HC_HOP_LIMIT_MASK) == HC_HOP_LIMIT_CARRIED_IN_LINE) { 00504 *ptr++ = in[7]; 00505 } 00506 00507 ptr = (uint8_t *) memcpy(ptr, cmp_src, cmp_src_len) + cmp_src_len; 00508 ptr = (uint8_t *) memcpy(ptr, cmp_dst, cmp_dst_len) + cmp_dst_len; 00509 00510 if (ptr != out + iphc_bytes) { 00511 tr_debug("iphc error"); 00512 } 00513 00514 return true; 00515 } 00516 00517 static bool compress_nh(uint8_t nh, iphc_compress_state_t *restrict cs) 00518 { 00519 switch (nh) { 00520 uint8_t nhc; 00521 case IPV6_NH_HOP_BY_HOP: 00522 nhc = NHC_EXT_HOP_BY_HOP; 00523 goto ext_hdr; 00524 case IPV6_NH_ROUTING: 00525 nhc = NHC_EXT_ROUTING; 00526 goto ext_hdr; 00527 case IPV6_NH_FRAGMENT: 00528 nhc = NHC_EXT_FRAG; 00529 goto ext_hdr; 00530 case IPV6_NH_DEST_OPT: 00531 nhc = NHC_EXT_DEST_OPT; 00532 goto ext_hdr; 00533 case IPV6_NH_MOBILITY: 00534 nhc = NHC_EXT_MOBILITY; 00535 ext_hdr: 00536 return compress_exthdr(nhc, cs); 00537 /* no break */ 00538 case IPV6_NH_IPV6: 00539 return compress_ipv6(cs, true); 00540 case IPV6_NH_UDP: 00541 return compress_udp(cs); 00542 default: 00543 return false; 00544 } 00545 } 00546 00547 00548 /* Input: An IPv6 frame, with outer layer 802.15.4 MAC (or IP) addresses in src+dst */ 00549 /* Output: 6LoWPAN frame - usually compressed. */ 00550 buffer_t *iphc_compress(const lowpan_context_list_t *context_list, buffer_t *buf, uint16_t hc_space, bool stable_only) 00551 { 00552 uint8_t *ptr = buffer_data_pointer(buf); 00553 uint16_t len = buffer_data_length(buf); 00554 uint8_t src_iid[8], dst_iid[8]; 00555 00556 if (len < 40 || (ptr[0] & 0xF0) != 0x60) { 00557 tr_debug("Not IPv6"); 00558 return buffer_free(buf); 00559 } 00560 00561 /* No point allocating excessively */ 00562 if (hc_space > len) { 00563 hc_space = len; 00564 } 00565 00566 /* TODO: Could actually do it in-place with more care, working backwards 00567 * in each header. 00568 */ 00569 uint8_t *hc_out = ns_dyn_mem_temporary_alloc(hc_space); 00570 if (!hc_out) { 00571 tr_debug("No mem"); 00572 return buffer_free(buf); 00573 } 00574 00575 if (!addr_iid_from_outer(src_iid, &buf->src_sa ) || !addr_iid_from_outer(dst_iid, &buf->dst_sa )) { 00576 tr_debug("Bad outer addr"); 00577 ns_dyn_mem_free(hc_out); 00578 return buffer_free(buf); 00579 } 00580 00581 iphc_compress_state_t cs = { 00582 .context_list = context_list, 00583 .in = ptr, 00584 .len = len, 00585 .out = hc_out, 00586 .out_space = hc_space, 00587 .consumed = 0, 00588 .produced = 0, 00589 .outer_src_iid = src_iid, 00590 .outer_dst_iid = dst_iid, 00591 .stable_only = stable_only 00592 }; 00593 00594 if (!compress_ipv6(&cs, false) || cs.produced > cs.consumed) { 00595 /* Compression failed, or made it bigger somehow (impossible?) */ 00596 /* Fall back to uncompressed, which means adding a dispatch byte */ 00597 buf = buffer_headroom(buf, 1); 00598 if (buf) { 00599 ptr = buffer_data_reserve_header(buf, 1); 00600 *ptr = LOWPAN_DISPATCH_IPV6; 00601 } 00602 ns_dyn_mem_free(hc_out); 00603 return buf; 00604 } 00605 00606 buffer_data_strip_header(buf, cs.consumed); 00607 buffer_data_reserve_header(buf, cs.produced); 00608 /* XXX see note above - should be able to improve this to avoid the temp buffer */ 00609 memcpy(buffer_data_pointer(buf), hc_out, cs.produced); 00610 ns_dyn_mem_free(hc_out); 00611 return buf; 00612 00613 }
Generated on Tue Jul 12 2022 14:23:50 by
