linux/include/net/6lowpan.h
<<
>>
Prefs
   1/*
   2 * Copyright 2011, Siemens AG
   3 * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
   4 */
   5
   6/*
   7 * Based on patches from Jon Smirl <jonsmirl@gmail.com>
   8 * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2
  12 * as published by the Free Software Foundation.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 *
  19 * You should have received a copy of the GNU General Public License along
  20 * with this program; if not, write to the Free Software Foundation, Inc.,
  21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  22 */
  23
  24/* Jon's code is based on 6lowpan implementation for Contiki which is:
  25 * Copyright (c) 2008, Swedish Institute of Computer Science.
  26 * All rights reserved.
  27 *
  28 * Redistribution and use in source and binary forms, with or without
  29 * modification, are permitted provided that the following conditions
  30 * are met:
  31 * 1. Redistributions of source code must retain the above copyright
  32 *    notice, this list of conditions and the following disclaimer.
  33 * 2. Redistributions in binary form must reproduce the above copyright
  34 *    notice, this list of conditions and the following disclaimer in the
  35 *    documentation and/or other materials provided with the distribution.
  36 * 3. Neither the name of the Institute nor the names of its contributors
  37 *    may be used to endorse or promote products derived from this software
  38 *    without specific prior written permission.
  39 *
  40 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  43 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  50 * SUCH DAMAGE.
  51 */
  52
  53#ifndef __6LOWPAN_H__
  54#define __6LOWPAN_H__
  55
  56#include <linux/debugfs.h>
  57
  58#include <net/ipv6.h>
  59#include <net/net_namespace.h>
  60
  61/* special link-layer handling */
  62#include <net/mac802154.h>
  63
  64#define EUI64_ADDR_LEN          8
  65
  66#define LOWPAN_NHC_MAX_ID_LEN   1
  67/* Maximum next header compression length which we currently support inclusive
  68 * possible inline data.
  69 */
  70#define LOWPAN_NHC_MAX_HDR_LEN  (sizeof(struct udphdr))
  71/* Max IPHC Header len without IPv6 hdr specific inline data.
  72 * Useful for getting the "extra" bytes we need at worst case compression.
  73 *
  74 * LOWPAN_IPHC + CID + LOWPAN_NHC_MAX_ID_LEN
  75 */
  76#define LOWPAN_IPHC_MAX_HEADER_LEN      (2 + 1 + LOWPAN_NHC_MAX_ID_LEN)
  77/* Maximum worst case IPHC header buffer size */
  78#define LOWPAN_IPHC_MAX_HC_BUF_LEN      (sizeof(struct ipv6hdr) +       \
  79                                         LOWPAN_IPHC_MAX_HEADER_LEN +   \
  80                                         LOWPAN_NHC_MAX_HDR_LEN)
  81/* SCI/DCI is 4 bit width, so we have maximum 16 entries */
  82#define LOWPAN_IPHC_CTX_TABLE_SIZE      (1 << 4)
  83
  84#define LOWPAN_DISPATCH_IPV6            0x41 /* 01000001 = 65 */
  85#define LOWPAN_DISPATCH_IPHC            0x60 /* 011xxxxx = ... */
  86#define LOWPAN_DISPATCH_IPHC_MASK       0xe0
  87
  88static inline bool lowpan_is_ipv6(u8 dispatch)
  89{
  90        return dispatch == LOWPAN_DISPATCH_IPV6;
  91}
  92
  93static inline bool lowpan_is_iphc(u8 dispatch)
  94{
  95        return (dispatch & LOWPAN_DISPATCH_IPHC_MASK) == LOWPAN_DISPATCH_IPHC;
  96}
  97
  98#define LOWPAN_PRIV_SIZE(llpriv_size)   \
  99        (sizeof(struct lowpan_dev) + llpriv_size)
 100
 101enum lowpan_lltypes {
 102        LOWPAN_LLTYPE_BTLE,
 103        LOWPAN_LLTYPE_IEEE802154,
 104};
 105
 106enum lowpan_iphc_ctx_flags {
 107        LOWPAN_IPHC_CTX_FLAG_ACTIVE,
 108        LOWPAN_IPHC_CTX_FLAG_COMPRESSION,
 109};
 110
 111struct lowpan_iphc_ctx {
 112        u8 id;
 113        struct in6_addr pfx;
 114        u8 plen;
 115        unsigned long flags;
 116};
 117
 118struct lowpan_iphc_ctx_table {
 119        spinlock_t lock;
 120        const struct lowpan_iphc_ctx_ops *ops;
 121        struct lowpan_iphc_ctx table[LOWPAN_IPHC_CTX_TABLE_SIZE];
 122};
 123
 124static inline bool lowpan_iphc_ctx_is_active(const struct lowpan_iphc_ctx *ctx)
 125{
 126        return test_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags);
 127}
 128
 129static inline bool
 130lowpan_iphc_ctx_is_compression(const struct lowpan_iphc_ctx *ctx)
 131{
 132        return test_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
 133}
 134
 135struct lowpan_dev {
 136        enum lowpan_lltypes lltype;
 137        struct dentry *iface_debugfs;
 138        struct lowpan_iphc_ctx_table ctx;
 139
 140        /* must be last */
 141        u8 priv[0] __aligned(sizeof(void *));
 142};
 143
 144struct lowpan_802154_neigh {
 145        __le16 short_addr;
 146};
 147
 148static inline
 149struct lowpan_802154_neigh *lowpan_802154_neigh(void *neigh_priv)
 150{
 151        return neigh_priv;
 152}
 153
 154static inline
 155struct lowpan_dev *lowpan_dev(const struct net_device *dev)
 156{
 157        return netdev_priv(dev);
 158}
 159
 160/* private device info */
 161struct lowpan_802154_dev {
 162        struct net_device       *wdev; /* wpan device ptr */
 163        u16                     fragment_tag;
 164};
 165
 166static inline struct
 167lowpan_802154_dev *lowpan_802154_dev(const struct net_device *dev)
 168{
 169        return (struct lowpan_802154_dev *)lowpan_dev(dev)->priv;
 170}
 171
 172struct lowpan_802154_cb {
 173        u16 d_tag;
 174        unsigned int d_size;
 175        u8 d_offset;
 176};
 177
 178static inline
 179struct lowpan_802154_cb *lowpan_802154_cb(const struct sk_buff *skb)
 180{
 181        BUILD_BUG_ON(sizeof(struct lowpan_802154_cb) > sizeof(skb->cb));
 182        return (struct lowpan_802154_cb *)skb->cb;
 183}
 184
 185static inline void lowpan_iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr,
 186                                                       const void *lladdr)
 187{
 188        /* fe:80::XXXX:XXXX:XXXX:XXXX
 189         *        \_________________/
 190         *              hwaddr
 191         */
 192        ipaddr->s6_addr[0] = 0xFE;
 193        ipaddr->s6_addr[1] = 0x80;
 194        memcpy(&ipaddr->s6_addr[8], lladdr, EUI64_ADDR_LEN);
 195        /* second bit-flip (Universe/Local)
 196         * is done according RFC2464
 197         */
 198        ipaddr->s6_addr[8] ^= 0x02;
 199}
 200
 201static inline void lowpan_iphc_uncompress_eui48_lladdr(struct in6_addr *ipaddr,
 202                                                       const void *lladdr)
 203{
 204        /* fe:80::XXXX:XXff:feXX:XXXX
 205         *        \_________________/
 206         *              hwaddr
 207         */
 208        ipaddr->s6_addr[0] = 0xFE;
 209        ipaddr->s6_addr[1] = 0x80;
 210        memcpy(&ipaddr->s6_addr[8], lladdr, 3);
 211        ipaddr->s6_addr[11] = 0xFF;
 212        ipaddr->s6_addr[12] = 0xFE;
 213        memcpy(&ipaddr->s6_addr[13], lladdr + 3, 3);
 214}
 215
 216#ifdef DEBUG
 217/* print data in line */
 218static inline void raw_dump_inline(const char *caller, char *msg,
 219                                   const unsigned char *buf, int len)
 220{
 221        if (msg)
 222                pr_debug("%s():%s: ", caller, msg);
 223
 224        print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, false);
 225}
 226
 227/* print data in a table format:
 228 *
 229 * addr: xx xx xx xx xx xx
 230 * addr: xx xx xx xx xx xx
 231 * ...
 232 */
 233static inline void raw_dump_table(const char *caller, char *msg,
 234                                  const unsigned char *buf, int len)
 235{
 236        if (msg)
 237                pr_debug("%s():%s:\n", caller, msg);
 238
 239        print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false);
 240}
 241#else
 242static inline void raw_dump_table(const char *caller, char *msg,
 243                                  const unsigned char *buf, int len) { }
 244static inline void raw_dump_inline(const char *caller, char *msg,
 245                                   const unsigned char *buf, int len) { }
 246#endif
 247
 248/**
 249 * lowpan_fetch_skb - getting inline data from 6LoWPAN header
 250 *
 251 * This function will pull data from sk buffer and put it into data to
 252 * remove the 6LoWPAN inline data. This function returns true if the
 253 * sk buffer is too small to pull the amount of data which is specified
 254 * by len.
 255 *
 256 * @skb: the buffer where the inline data should be pulled from.
 257 * @data: destination buffer for the inline data.
 258 * @len: amount of data which should be pulled in bytes.
 259 */
 260static inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data,
 261                                    unsigned int len)
 262{
 263        if (unlikely(!pskb_may_pull(skb, len)))
 264                return true;
 265
 266        skb_copy_from_linear_data(skb, data, len);
 267        skb_pull(skb, len);
 268
 269        return false;
 270}
 271
 272static inline bool lowpan_802154_is_valid_src_short_addr(__le16 addr)
 273{
 274        /* First bit of addr is multicast, reserved or 802.15.4 specific */
 275        return !(addr & cpu_to_le16(0x8000));
 276}
 277
 278static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
 279                                       const size_t len)
 280{
 281        memcpy(*hc_ptr, data, len);
 282        *hc_ptr += len;
 283}
 284
 285int lowpan_register_netdevice(struct net_device *dev,
 286                              enum lowpan_lltypes lltype);
 287int lowpan_register_netdev(struct net_device *dev,
 288                           enum lowpan_lltypes lltype);
 289void lowpan_unregister_netdevice(struct net_device *dev);
 290void lowpan_unregister_netdev(struct net_device *dev);
 291
 292/**
 293 * lowpan_header_decompress - replace 6LoWPAN header with IPv6 header
 294 *
 295 * This function replaces the IPHC 6LoWPAN header which should be pointed at
 296 * skb->data and skb_network_header, with the IPv6 header.
 297 * It would be nice that the caller have the necessary headroom of IPv6 header
 298 * and greatest Transport layer header, this would reduce the overhead for
 299 * reallocate headroom.
 300 *
 301 * @skb: the buffer which should be manipulate.
 302 * @dev: the lowpan net device pointer.
 303 * @daddr: destination lladdr of mac header which is used for compression
 304 *      methods.
 305 * @saddr: source lladdr of mac header which is used for compression
 306 *      methods.
 307 */
 308int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
 309                             const void *daddr, const void *saddr);
 310
 311/**
 312 * lowpan_header_compress - replace IPv6 header with 6LoWPAN header
 313 *
 314 * This function replaces the IPv6 header which should be pointed at
 315 * skb->data and skb_network_header, with the IPHC 6LoWPAN header.
 316 * The caller need to be sure that the sk buffer is not shared and at have
 317 * at least a headroom which is smaller or equal LOWPAN_IPHC_MAX_HEADER_LEN,
 318 * which is the IPHC "more bytes than IPv6 header" at worst case.
 319 *
 320 * @skb: the buffer which should be manipulate.
 321 * @dev: the lowpan net device pointer.
 322 * @daddr: destination lladdr of mac header which is used for compression
 323 *      methods.
 324 * @saddr: source lladdr of mac header which is used for compression
 325 *      methods.
 326 */
 327int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
 328                           const void *daddr, const void *saddr);
 329
 330#endif /* __6LOWPAN_H__ */
 331