Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers iphc_compress.c Source File

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 }