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
 201#ifdef DEBUG
 202/* print data in line */
 203static inline void raw_dump_inline(const char *caller, char *msg,
 204                                   const unsigned char *buf, int len)
 205{
 206        if (msg)
 207                pr_debug("%s():%s: ", caller, msg);
 208
 209        print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, false);
 210}
 211
 212/* print data in a table format:
 213 *
 214 * addr: xx xx xx xx xx xx
 215 * addr: xx xx xx xx xx xx
 216 * ...
 217 */
 218static inline void raw_dump_table(const char *caller, char *msg,
 219                                  const unsigned char *buf, int len)
 220{
 221        if (msg)
 222                pr_debug("%s():%s:\n", caller, msg);
 223
 224        print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false);
 225}
 226#else
 227static inline void raw_dump_table(const char *caller, char *msg,
 228                                  const unsigned char *buf, int len) { }
 229static inline void raw_dump_inline(const char *caller, char *msg,
 230                                   const unsigned char *buf, int len) { }
 231#endif
 232
 233/**
 234 * lowpan_fetch_skb - getting inline data from 6LoWPAN header
 235 *
 236 * This function will pull data from sk buffer and put it into data to
 237 * remove the 6LoWPAN inline data. This function returns true if the
 238 * sk buffer is too small to pull the amount of data which is specified
 239 * by len.
 240 *
 241 * @skb: the buffer where the inline data should be pulled from.
 242 * @data: destination buffer for the inline data.
 243 * @len: amount of data which should be pulled in bytes.
 244 */
 245static inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data,
 246                                    unsigned int len)
 247{
 248        if (unlikely(!pskb_may_pull(skb, len)))
 249                return true;
 250
 251        skb_copy_from_linear_data(skb, data, len);
 252        skb_pull(skb, len);
 253
 254        return false;
 255}
 256
 257static inline bool lowpan_802154_is_valid_src_short_addr(__le16 addr)
 258{
 259        /* First bit of addr is multicast, reserved or 802.15.4 specific */
 260        return !(addr & cpu_to_le16(0x8000));
 261}
 262
 263static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
 264                                       const size_t len)
 265{
 266        memcpy(*hc_ptr, data, len);
 267        *hc_ptr += len;
 268}
 269
 270int lowpan_register_netdevice(struct net_device *dev,
 271                              enum lowpan_lltypes lltype);
 272int lowpan_register_netdev(struct net_device *dev,
 273                           enum lowpan_lltypes lltype);
 274void lowpan_unregister_netdevice(struct net_device *dev);
 275void lowpan_unregister_netdev(struct net_device *dev);
 276
 277/**
 278 * lowpan_header_decompress - replace 6LoWPAN header with IPv6 header
 279 *
 280 * This function replaces the IPHC 6LoWPAN header which should be pointed at
 281 * skb->data and skb_network_header, with the IPv6 header.
 282 * It would be nice that the caller have the necessary headroom of IPv6 header
 283 * and greatest Transport layer header, this would reduce the overhead for
 284 * reallocate headroom.
 285 *
 286 * @skb: the buffer which should be manipulate.
 287 * @dev: the lowpan net device pointer.
 288 * @daddr: destination lladdr of mac header which is used for compression
 289 *      methods.
 290 * @saddr: source lladdr of mac header which is used for compression
 291 *      methods.
 292 */
 293int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
 294                             const void *daddr, const void *saddr);
 295
 296/**
 297 * lowpan_header_compress - replace IPv6 header with 6LoWPAN header
 298 *
 299 * This function replaces the IPv6 header which should be pointed at
 300 * skb->data and skb_network_header, with the IPHC 6LoWPAN header.
 301 * The caller need to be sure that the sk buffer is not shared and at have
 302 * at least a headroom which is smaller or equal LOWPAN_IPHC_MAX_HEADER_LEN,
 303 * which is the IPHC "more bytes than IPv6 header" at worst case.
 304 *
 305 * @skb: the buffer which should be manipulate.
 306 * @dev: the lowpan net device pointer.
 307 * @daddr: destination lladdr of mac header which is used for compression
 308 *      methods.
 309 * @saddr: source lladdr of mac header which is used for compression
 310 *      methods.
 311 */
 312int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
 313                           const void *daddr, const void *saddr);
 314
 315#endif /* __6LOWPAN_H__ */
 316